M Makefile => Makefile +1 -1
@@ 1,6 1,6 @@
INCLUDE = include
-KERNEL = kernel.o ide.o console.o ext2.o blockdev.o kmem.o paging.o atpic.o proc.o scheduler.o
+KERNEL = kernel.o ide.o console.o ext2.o blockdev.o kmem.o paging.o atpic.o proc.o scheduler.o bitmap.o
HEADERS = $(shell find include/ -type f)
CC = i686-elf-gcc
A bitmap.c => bitmap.c +75 -0
@@ 0,0 1,75 @@
+#include <sys/bitmap.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+struct bitmap *
+bitmap_create(void *mem, uint32_t available, size_t bitmap_size) {
+ /* check, if it fits */
+ if (available < bitmap_required_size(bitmap_size)) {
+ return NULL;
+ }
+
+ struct bitmap *bm = (struct bitmap *)mem;
+ bm->size = bitmap_size;
+ bm->first_clear = 0;
+ bm->area = (uint32_t *)(mem + sizeof(struct bitmap *));
+
+ memset(bm->area, 0, ((bitmap_size + 31) / 32) * 4);
+
+ return NULL;
+}
+
+void
+bitmap_set(struct bitmap *bm, uint32_t index) {
+ uint32_t area_index = index / 32;
+ uint32_t mask = 1 << (index % 32);
+ bm->area[area_index] |= mask;
+}
+
+void
+bitmap_clear(struct bitmap *bm, uint32_t index) {
+ uint32_t area_index = index / 32;
+ uint32_t mask = ~(1 << (index % 32));
+ bm->area[area_index] &= mask;
+ if (area_index < bm->first_clear) {
+ bm->first_clear = area_index;
+ }
+}
+
+int
+bitmap_get(struct bitmap *bm, uint32_t index) {
+ uint32_t area_index = index / 32;
+ uint32_t mask = 1 << (index % 32);
+ return (bm->area[area_index] & mask);
+}
+
+uint32_t
+bitmap_find_clear(struct bitmap *bm) {
+ for(uint32_t area_index = bm->first_clear; area_index < bm->size; ++area_index) {
+ if (bm->area[area_index] != 0xffffffff) {
+ area_index *= 32;
+ uint32_t value = bm->area[area_index];
+ while (value & 1) {
+ area_index++;
+ value >>= 1;
+ }
+ return area_index;
+ }
+ }
+
+ return 0;
+}
+
+void
+bitmap_range_update(struct bitmap *bm, uint32_t start, uint32_t count, int value) {
+ // TODO: this is a very naive implementation, replace with a real one
+ if (value) {
+ for (uint32_t index=start; index<start+count; ++index) {
+ bitmap_set(bm, index);
+ }
+ } else {
+ for (uint32_t index=start; index<start+count; ++index) {
+ bitmap_clear(bm, index);
+ }
+ }
+}
M include/stdlib.h => include/stdlib.h +9 -0
@@ 29,4 29,13 @@ static inline void memcpy(void *dst, const void *src, uint32_t size) {
}
}
+static inline void *memset(void *b, int c, size_t len) {
+ uint8_t x = (uint8_t)c;
+ uint8_t *p = b, *end=p-len;
+ while(p<end) {
+ *p++ = x;
+ }
+ return b;
+}
+
#endif /* _STDLIB_H_ */
A include/sys/bitmap.h => include/sys/bitmap.h +29 -0
@@ 0,0 1,29 @@
+#ifndef _BITMAP_H_
+#define _BITMAP_H_
+
+#include <sys/types.h>
+
+struct bitmap {
+ /* number of bits */
+ size_t size;
+ /* area_index, where the first clear bit might be found */
+ uint32_t first_clear;
+ /* data */
+ uint32_t *area;
+};
+
+struct bitmap *bitmap_create(void *mem, uint32_t available, size_t bitmap_size);
+
+int bitmap_get(struct bitmap *bm, uint32_t index);
+void bitmap_set(struct bitmap *bm, uint32_t index);
+void bitmap_clear(struct bitmap *bm, uint32_t index);
+void bitmap_update(struct bitmap *bm, uint32_t index, int value);
+void bitmap_range_update(struct bitmap *bm, uint32_t start, uint32_t count, int value);
+uint32_t bitmap_find_clear(struct bitmap *bm);
+
+static inline uint32_t
+bitmap_required_size(size_t bitmap_size) {
+ return (sizeof(struct bitmap) + ((bitmap_size + 31) / 32) * 4);
+}
+
+#endif /* _BITMAP_H_ */
M include/sys/kernel.h => include/sys/kernel.h +0 -2
@@ 3,8 3,6 @@
#include <sys/console.h>
-#define NULL ((void *)0)
-
void panic(const char *msg);
#endif /* _KERNEL_H_ */
M include/sys/memory.h => include/sys/memory.h +3 -9
@@ 11,15 11,9 @@ void *kmalloc(size_t size);
void *kmalloc_align(size_t alignment, size_t size);
void kfree(void *p);
-static inline void *memset(void *b, int c, size_t len) {
- uint8_t x = (uint8_t)c;
- uint8_t *p = b, *end=p-len;
- while(p<end) {
- *p++ = x;
- }
- return b;
-}
-
void kmem_init(uint32_t memory_map_entry_count, struct memory_map_entry *entries);
+uint32_t phys_aquire_page(void);
+void phys_release_page(uint32_t page);
+
#endif /* _MEMORY_H_ */
M include/sys/types.h => include/sys/types.h +5 -0
@@ 11,4 11,9 @@ typedef int int32_t;
typedef unsigned int size_t;
+#define NULL ((void *)0)
+
+#define UINT32_MAX 0xffffffff
+#define UINT32_ADD_OVERFLOW(a,b) ((a) > (UINT32_MAX - (b)))
+
#endif /* _TYPES_H_ */
M kmem.c => kmem.c +96 -7
@@ 1,3 1,4 @@
+#include <sys/bitmap.h>
#include <sys/console.h>
#include <sys/kernel.h>
#include <sys/memory.h>
@@ 9,6 10,9 @@
#define KMEM_ARENA_START 0x200000
#define KMEM_ARENA_END 0x400000
+// First non-reserved phys memory address
+#define PHYS_RESERVED 0x200000
+
struct memory_map_entry {
uint32_t base_low;
uint32_t base_high;
@@ 20,6 24,9 @@ struct memory_map_entry {
struct kmem {
void *free; // first free page
+ uint32_t phys_pages_total;
+ uint32_t phys_pages_available;
+ struct bitmap *phys_pages;
};
struct free_info {
@@ 28,6 35,26 @@ struct free_info {
static struct kmem kmem_state;
+static void *lowmem_next = 0x10000;
+static const void *lowmem_max = 0x80000;
+static void *
+lowmem_alloc(size_t size) {
+ if (lowmem_next + size >= lowmem_max) { return NULL; }
+ void *p = lowmem_next;
+ lowmem_next += size;
+ return p;
+}
+
+static int
+memory_usable(struct memory_map_entry *m) {
+ return ((m->type == 1) &&
+ (m->base_high == 0) &&
+ (m->base_low + m->length_low > PHYS_RESERVED) &&
+ (m->length_low > 0) &&
+ (m->length_high == 0) &&
+ !UINT32_ADD_OVERFLOW(m->base_low, m->length_low));
+}
+
void kmem_detect(uint32_t count, struct memory_map_entry *mmap);
void kmem_init(uint32_t memory_map_entry_count, struct memory_map_entry *entries) {
@@ 51,15 78,77 @@ void kmem_init(uint32_t memory_map_entry_count, struct memory_map_entry *entries
void
kmem_detect(uint32_t count, struct memory_map_entry *mmap) {
- khexprint("mmap count", count);
+ uint32_t highest = 0;
+ for (int i=0; i<count; ++i) {
+ if (!memory_usable(mmap + i)) {
+ khexprint("=========== SKIP mmap entry", i);
+ khexprint(" base_low", mmap[i].base_low);
+ khexprint(" base_high", mmap[i].base_high);
+ khexprint(" length_low", mmap[i].length_low);
+ khexprint(" length_high", mmap[i].length_high);
+ khexprint(" type", mmap[i].type);
+ continue;
+ }
+ if ((mmap[i].base_low + mmap[i].length_low) > highest) {
+ highest = mmap[i].base_low + mmap[i].length_low;
+ }
+ }
+ kmem_state.phys_pages_total = highest / PAGE_SIZE;
+ void *bm_mem = lowmem_alloc(bitmap_required_size(kmem_state.phys_pages_total));
+ struct bitmap *bm = kmem_state.phys_pages = bitmap_create(bm_mem,
+ bitmap_required_size(kmem_state.phys_pages_total),
+ kmem_state.phys_pages_total);
+
+ // initally, mark all memory as unusable
+ bitmap_range_update(bm, 0, kmem_state.phys_pages_total, 1);
+
+ uint32_t available_count = 0;
for (int i=0; i<count; ++i) {
- khexprint("=========== mmap entry", i);
- khexprint("base_low", mmap[i].base_low);
- khexprint("base_high", mmap[i].base_high);
- khexprint("length_low", mmap[i].length_low);
- khexprint("length_high", mmap[i].length_high);
- khexprint("type", mmap[i].type);
+ if (!memory_usable(mmap + i)) {
+ continue;
+ }
+ uint32_t start = mmap[i].base_low;
+ uint32_t end = mmap[i].base_low + mmap[i].length_low;
+ if (end < PHYS_RESERVED) {
+ continue;
+ }
+ if (start < PHYS_RESERVED) {
+ start = PHYS_RESERVED;
+ }
+
+ khexprint("=========== USE mmap entry", i);
+ khexprint(" base_low", mmap[i].base_low);
+ khexprint(" base_high", mmap[i].base_high);
+ khexprint(" length_low", mmap[i].length_low);
+ khexprint(" length_high", mmap[i].length_high);
+ khexprint(" type", mmap[i].type);
+ khexprint(" actual_start", start);
+ khexprint(" actual_end", end);
+
+ // first completely usable page
+ uint32_t first_page = (start + PAGE_SIZE - 1) / PAGE_SIZE;
+
+ // first page that is not completely usable
+ uint32_t last_page = end / PAGE_SIZE;
+
+ // mark memory as unused(available)
+ bitmap_range_update(bm, first_page, last_page, 0);
+ available_count += (last_page - first_page);
}
+ khexprint("============ Memory detection complete\n total memory",
+ available_count*PAGE_SIZE);
+}
+
+uint32_t
+phys_aquire_page(void) {
+ uint32_t page = bitmap_find_clear(kmem_state.phys_pages);
+ bitmap_set(kmem_state.phys_pages, page);
+ return page;
+}
+
+void
+phys_release_page(uint32_t page) {
+ bitmap_clear(kmem_state.phys_pages, page);
}
void *kmem_alloc_pages(size_t pages) {