#include #include #include #include #include #include #include extern uint8_t pbitmap[]; /* linker.ld */ static size_t pbitmap_len; /* in bytes */ static void *memtop; static void *firstfreepage; /* not necessarily actually free */ static size_t toindex(void *p) { assert((void*)pbitmap <= p); return ((uintptr_t)p - (uintptr_t)pbitmap) / PAGE_SIZE; } static bool pbitmap_get(void *p) { size_t i = toindex(p); size_t b = i / 8; uint8_t m = 1 << (i&7); assert(b < pbitmap_len); // TODO the bitmap should be a tad longer return (pbitmap[b]&m) != 0; } static bool pbitmap_set(void *p, bool v) { size_t i = toindex(p); size_t b = i / 8; uint8_t m = 1 << (i&7); assert(b < pbitmap_len); bool prev = (pbitmap[b]&m) != 0; if (v) { pbitmap[b] |= m; } else { pbitmap[b] &= ~m; } return prev; } void mem_init(void *p) { memtop = p; kprintf("memory %8x -> %8x\n", &_bss_end, memtop); pbitmap_len = toindex(memtop) / 8; memset(pbitmap, 0, pbitmap_len); mem_reserve(pbitmap, pbitmap_len); firstfreepage = pbitmap; } void mem_reserve(void *addr, size_t len) { kprintf("reserved %8x -> %8x\n", addr, addr + len); void *top = min(addr + len, memtop); addr = (void*)((uintptr_t)addr & ~PAGE_MASK); /* round down to page */ for (void *p = max(addr, (void*)pbitmap); p < top; p += PAGE_SIZE) { /* this doesn't allow overlapping reserved regions, but, more * importantly, it prevents reserving an already allocated page */ if (pbitmap_get(p)) { panic_invalid_state(); } pbitmap_set(p, true); } } void * page_zalloc(size_t pages) { void *p = page_alloc(pages); memset(p, 0, pages * PAGE_SIZE); return p; } void * page_alloc(size_t pages) { assert(pages == 1); for (void *p = firstfreepage; p < memtop; p += PAGE_SIZE) { if (!pbitmap_get(p)) { pbitmap_set(p, true); firstfreepage = p + PAGE_SIZE; return p; } } kprintf("we ran out of memory :(\ngoodbye.\n"); panic_unimplemented(); } void page_free(void *addr, size_t pages) { assert((void*)pbitmap <= addr); for (size_t i = 0; i < pages; i++) { if (pbitmap_set(addr + i*PAGE_SIZE, false) == false) { panic_invalid_state(); } } firstfreepage = min(firstfreepage, addr); }