diff --git a/kernel/include/bitmap.h b/kernel/include/bitmap.h index 1d093c9..8ab3645 100644 --- a/kernel/include/bitmap.h +++ b/kernel/include/bitmap.h @@ -11,9 +11,11 @@ typedef struct bitmap_t { size_t blocks; // Eqiv. to # of bits size_t bytes; // ceil(blocks / 8) size_t used; // # of bits set to 0 + size_t membase; // Used with allocators int ready; } bitmap_t; +void* bmap_ptr(bitmap_t* map, size_t bit); void bmap_set(bitmap_t* map, size_t bit, int val); int bmap_get(bitmap_t* map, size_t bit); void bmap_setarea(bitmap_t* map, size_t base, size_t len, int val); diff --git a/kernel/include/kernel.h b/kernel/include/kernel.h index 7369137..6462d8b 100644 --- a/kernel/include/kernel.h +++ b/kernel/include/kernel.h @@ -7,15 +7,15 @@ /* * Virtual memory addresses */ -#define USER_HEAP 0x10000000 -#define USER_STACK 0xBF000000 -#define USER_SHARED 0xA0000000 -#define KERNEL_BASE 0xC0000000 -#define KERNEL_SIZE 0x10000000 -#define KERNEL_MEM_BASE 0xD0000000 -#define KERNEL_MEM_SIZE 0x10000000 -#define KERNEL_SHARED 0xF0000000 -#define KERNEL_FRAMEBUF 0xC8000000 +#define USER_HEAP 0x10000000 +#define USER_STACK 0xBF000000 +#define USER_SHARED 0xA0000000 +#define KERNEL_BASE 0xC0000000 +#define KERNEL_SIZE 0x10000000 +#define KERNEL_HEAP_BASE 0xD0000000 +#define KERNEL_HEAP_SIZE 0x10000000 +#define KERNEL_SHARED 0xF0000000 +#define KERNEL_FRAMEBUF 0xC8000000 /* * Variable arguments diff --git a/kernel/include/pmm.h b/kernel/include/pmm.h index 047303c..2e074d9 100644 --- a/kernel/include/pmm.h +++ b/kernel/include/pmm.h @@ -7,9 +7,7 @@ extern bitmap_t pmm_bitmap; int pmm_init(void); -void pmm_initRegion(size_t base, size_t len); -void pmm_deinitRegion(size_t base, size_t len); -void* pmm_alloc(size_t len); -void pmm_free(void* ptr, size_t len); +void* pmm_allocPage(void); +void pmm_freePage(void* page); #endif diff --git a/kernel/include/vmm.h b/kernel/include/vmm.h new file mode 100644 index 0000000..53a6785 --- /dev/null +++ b/kernel/include/vmm.h @@ -0,0 +1,13 @@ +#ifndef _VMM_H +#define _VMM_H + +#include +#include + +extern bitmap_t vmm_bitmap; + +int vmm_init(void); +void* vmm_alloc(size_t pages); +void vmm_free(void* ptr, size_t pages); + +#endif diff --git a/kernel/src/bitmap.c b/kernel/src/bitmap.c index 7107514..9da7297 100644 --- a/kernel/src/bitmap.c +++ b/kernel/src/bitmap.c @@ -3,10 +3,15 @@ #include +void* bmap_ptr(bitmap_t* map, size_t bit) { + return (void*)(map->membase + bit * BLOCK_SIZE); +} + void bmap_set(bitmap_t* map, size_t bit, int val) { uint32_t* p = (uint32_t*)map->map; if (val) p[bit / 32] |= (1 << (bit % 32)); else p[bit / 32] &= ~(1 << (bit % 32)); + map->used += (val) ? 1 : -1; } int bmap_get(bitmap_t* map, size_t bit) { @@ -15,13 +20,10 @@ int bmap_get(bitmap_t* map, size_t bit) { } void bmap_setarea(bitmap_t* map, size_t base, size_t len, int val) { - uint32_t align = base / BLOCK_SIZE; - uint32_t count = len / BLOCK_SIZE; + uint32_t align = dceil(base, BLOCK_SIZE); + uint32_t count = dceil(len, BLOCK_SIZE); - while (count-- > 0) { - bmap_set(map, align++, val); - map->used += (val) ? 1 : -1; - } + while (count-- > 0) bmap_set(map, align++, val); } void bmap_setall(bitmap_t* map, int val) { @@ -39,7 +41,7 @@ size_t bmap_findarea(bitmap_t* map, size_t len, int val) { if (bmap_get(map, i) == val) found++; else found = 0; - if (found >= len) return i - found; + if (found >= len) return i - found + 1; } return BMAP_NOT_FOUND; diff --git a/kernel/src/kernel.c b/kernel/src/kernel.c index a6dba2c..a7a92d6 100644 --- a/kernel/src/kernel.c +++ b/kernel/src/kernel.c @@ -6,10 +6,11 @@ #include #include #include +#include __noreturn void kmain(void* ptr, uint32_t magic) { - if (boot_initMB1(ptr, magic) != 0) panic("Unsupporred bootloader."); + if (boot_initMB1(ptr, magic) != 0) panic("Unsupported bootloader."); // Serial console for debugging if (serial_init(COM1) != 0) panic("Failed to initialize Serial driver."); @@ -26,7 +27,7 @@ void kmain(void* ptr, uint32_t magic) { // Memory manager init if (pmm_init() != 0) panic("Failed to initalize Physical Memory Manager."); - //if (vmm_init() != 0) panic("Failed to initalize Virtual Memory Manager."); + if (vmm_init() != 0) panic("Failed to initalize Virtual Memory Manager."); debugf("Basic initialization complete!\n"); diff --git a/kernel/src/paging.c b/kernel/src/paging.c index 629836f..9c5a1fd 100644 --- a/kernel/src/paging.c +++ b/kernel/src/paging.c @@ -65,7 +65,7 @@ void pag_mapPage(uint32_t vaddr, uint32_t paddr, uint32_t flags) { // Allocate a pagetab if it didn't exist if (!(pagedir[pdi] & PAGE_FLAG_PRESENT)) { - uint32_t tabaddr = pmm_bitmap.ready ? (uint32_t)pmm_alloc(1) : pag_tempFrame(); + uint32_t tabaddr = pmm_bitmap.ready ? (uint32_t)pmm_allocPage() : pag_tempFrame(); pagedir[pdi] = tabaddr | PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE | PAGE_FLAG_OWNER | flags; @@ -122,14 +122,14 @@ uint32_t pag_umapPage(uint32_t vaddr) { uint32_t pde = pagedir[pdi]; if (remove && pde & PAGE_FLAG_OWNER) { uint32_t tabaddr = PHYS_ADDR(pde); - pmm_free((void*)tabaddr, 1); + pmm_freePage((void*)tabaddr); pagedir[pdi] = 0; } invalidate(vaddr); // Free the page frame - if (pte & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pte), 1); + if (pte & PAGE_FLAG_OWNER) pmm_freePage((void*)PHYS_ADDR(pte)); if (prevpd != NULL) { pag_syncPagedir(); // Sync it to other pagedirs @@ -221,11 +221,11 @@ void pag_freePagedir(uint32_t* pagedir) { for (size_t j = 0; j < 1024; j++) { uint32_t pte = pagetab[j]; - if (pte & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pte), 1); + if (pte & PAGE_FLAG_OWNER) pmm_freePage((void*)PHYS_ADDR(pte)); } memset(pagetab, 0, PAGE_SIZE); - if (pde & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pde), 1); + if (pde & PAGE_FLAG_OWNER) pmm_freePage((void*)PHYS_ADDR(pde)); pd[i] = 0; } diff --git a/kernel/src/pmm.c b/kernel/src/pmm.c index 69a6e54..d37a499 100644 --- a/kernel/src/pmm.c +++ b/kernel/src/pmm.c @@ -8,10 +8,10 @@ bitmap_t pmm_bitmap; int pmm_init(void) { - size_t totalmem = (bootloader.memLower + bootloader.memUpper) * 1024; - - pmm_bitmap.blocks = dceil(totalmem, BLOCK_SIZE); - pmm_bitmap.bytes = dceil(pmm_bitmap.blocks, 8); + // Full 32-bit address space + pmm_bitmap.membase = 0x00000000; + pmm_bitmap.blocks = 0x100000; // 0xFFFFFFFF / BLOCK_SIZE + pmm_bitmap.bytes = 0x20000; // blocks / 8 pmm_bitmap.map = NULL; // # of pagetabs required to map the bitmap @@ -34,7 +34,7 @@ int pmm_init(void) { pag_registerTempFrame(pageFrameStart); mmap->base += ptcount * PAGE_SIZE; - uint32_t bitmapStart = KERNEL_MEM_BASE - dceil(pmm_bitmap.bytes, PAGE_SIZE) * PAGE_SIZE; + uint32_t bitmapStart = KERNEL_HEAP_BASE - dceil(pmm_bitmap.bytes, PAGE_SIZE) * PAGE_SIZE; uint32_t bitmapStartPhys = mmap->base; pmm_bitmap.map = (void*)bitmapStart; @@ -53,7 +53,9 @@ int pmm_init(void) { mmap = &bootloader.memmap[i]; if (mmap->size == 0) continue; // Ignore dummy entries - if (mmap->type == BOOT_MMAP_AVAILABLE) pmm_initRegion(mmap->base, mmap->size); + if (mmap->type == BOOT_MMAP_AVAILABLE) { + bmap_setarea(&pmm_bitmap, mmap->base, mmap->size, 0); + } // Print entry debugf("\tRegion %2d: 0x%08x - 0x%08x (%d bytes) %s\n", @@ -61,8 +63,9 @@ int pmm_init(void) { (mmap->type == BOOT_MMAP_AVAILABLE) ? "AVAILABLE" : "RESERVED"); } - pmm_deinitRegion(bitmapStartPhys, pmm_bitmap.bytes); - pmm_deinitRegion(pageFrameStart, ptcount * PAGE_SIZE); + bmap_setarea(&pmm_bitmap, bitmapStartPhys, pmm_bitmap.bytes, 1); + bmap_setarea(&pmm_bitmap, pageFrameStart, ptcount * PAGE_SIZE, 1); + bmap_set(&pmm_bitmap, 0, 1); // Reserve block 0 - NULL page // Beatifull print statement :) debugf( @@ -79,31 +82,20 @@ int pmm_init(void) { return 0; } +void* pmm_allocPage(void) { + if (pmm_bitmap.blocks - pmm_bitmap.used == 0) return NULL; -void pmm_initRegion(size_t base, size_t len) { - bmap_setarea(&pmm_bitmap, base, len, 0); - bmap_set(&pmm_bitmap, 0, 1); -} - -void pmm_deinitRegion(size_t base, size_t len) { - bmap_setarea(&pmm_bitmap, base, len, 1); - bmap_set(&pmm_bitmap, 0, 1); -} - -void* pmm_alloc(size_t len) { - if (pmm_bitmap.blocks - pmm_bitmap.used < len) return NULL; - - size_t base = bmap_findarea(&pmm_bitmap, len, 0); + size_t base = bmap_findarea(&pmm_bitmap, 1, 0); if (base == BMAP_NOT_FOUND) return NULL; - bmap_setarea(&pmm_bitmap, base, len, 1); + bmap_set(&pmm_bitmap, base, 1); - return (void*)(base * BLOCK_SIZE); + return bmap_ptr(&pmm_bitmap, base); } -void pmm_free(void* ptr, size_t len) { - size_t base = (size_t)ptr / BLOCK_SIZE; - bmap_setarea(&pmm_bitmap, base, len, 0); +void pmm_freePage(void* page) { + size_t base = (size_t)page / BLOCK_SIZE; + bmap_setarea(&pmm_bitmap, base, 1, 0); bmap_set(&pmm_bitmap, 0, 1); } diff --git a/kernel/src/vmm.c b/kernel/src/vmm.c new file mode 100644 index 0000000..c1b5729 --- /dev/null +++ b/kernel/src/vmm.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +#include + +#include + +bitmap_t vmm_bitmap; + +int vmm_init(void) { + vmm_bitmap.ready = 0; + vmm_bitmap.membase = KERNEL_HEAP_BASE; + vmm_bitmap.blocks = dceil(KERNEL_HEAP_SIZE, BLOCK_SIZE); + vmm_bitmap.bytes = dceil(vmm_bitmap.blocks, 8); + uint32_t bitmaploc = 0xC6000000; + + debugf("%d blocks in %d bytes\n", vmm_bitmap.blocks, vmm_bitmap.bytes); + size_t pagecount = dceil(vmm_bitmap.bytes, PAGE_SIZE); + for (size_t i = 0; i < pagecount; i++) { + void* fr = pmm_allocPage(); + debugf("Allocating page %d/%d...\n", i+1, pagecount); + if (fr == NULL) return 1; + debugf("Mapping page at 0x%08x to 0x%08x\n", fr, bitmaploc + i * PAGE_SIZE); + pag_mapPage(bitmaploc + i * PAGE_SIZE, (uint32_t)fr, 0); + } + + // Set all pages as + vmm_bitmap.map = (void*)bitmaploc; + bmap_setall(&vmm_bitmap, 0); + + bmap_set(&vmm_bitmap, 0, 1); + bmap_set(&vmm_bitmap, 8, 1); + + debugf( + "[vmm] Virtual memory manager initialized.\n" + "\tBitmap manages %d blocks\n" + "\tBitmap is at 0x%08x in virtual memory\n" + "\tBitmap is %d bytes over %d pages\n", + vmm_bitmap.blocks, vmm_bitmap.map, + vmm_bitmap.bytes, pagecount + ); + + vmm_bitmap.ready = 1; + return 0; +} + +void* vmm_alloc(size_t pages) { + size_t idx = bmap_findarea(&vmm_bitmap, pages, 0); + if (idx == BMAP_NOT_FOUND) return NULL; + void* ptr = bmap_ptr(&vmm_bitmap, idx); + + bmap_setarea(&vmm_bitmap, idx * BLOCK_SIZE, pages * PAGE_SIZE, 1); + + for (size_t i = 0; i < pages; i++) { + void* fr = pmm_allocPage(); + if (fr == NULL) return NULL; + pag_mapPage((uint32_t)ptr + i * PAGE_SIZE, (uint32_t)fr, 0); + } + + return ptr; +} + +void vmm_free(void* ptr, size_t pages) { + for (size_t i = 0; i < pages; i++) { + uint32_t vaddr = (uint32_t)ptr + i * PAGE_SIZE; + uint32_t paddr = (uint32_t)pag_virtToPhys((uint32_t)ptr); + + pmm_freePage((void*)paddr); + pag_umapPage(vaddr); + } + + size_t base = ((size_t)ptr - KERNEL_BASE) / BLOCK_SIZE; + bmap_setarea(&vmm_bitmap, base, pages, 0); +} +