From 7669ea32a422d4665063909fd5ea339c28a66d41 Mon Sep 17 00:00:00 2001 From: Nathan Singer Date: Wed, 11 Jun 2025 20:36:30 -0400 Subject: [PATCH] implements a physical memory manager... sort of, it gives an out of mem error, and variable are setting incorrectly --- kernel/arch/pmm/pmm.c | 140 +++++++++++++++++++++++++++++++++--- kernel/include/kernel/pmm.h | 11 +++ kernel/kmain.c | 14 +++- libc/stdio/printf.c | 4 +- 4 files changed, 155 insertions(+), 14 deletions(-) diff --git a/kernel/arch/pmm/pmm.c b/kernel/arch/pmm/pmm.c index 3b48968..a79037a 100644 --- a/kernel/arch/pmm/pmm.c +++ b/kernel/arch/pmm/pmm.c @@ -1,4 +1,10 @@ #include +#include +#include + +#ifdef __TESTING__ +#include +#endif #include #include @@ -19,25 +25,47 @@ */ #define PMM_PAGE_SIZE 4096 +#define PMM_BLOCKS_PER_BYTE 8 struct pmm_mem_info { - uint64_t startaddr; - uint64_t len; // in kb + uint32_t startaddr; + uint32_t len; // in kb uint32_t* bitmap; + + uint32_t max_blocks; + uint32_t free_blocks; + uint32_t used_blocks; }; #define PMM_GET_MEM_BLOCKS(x) x.len / PMM_PAGE_SIZE struct pmm_mem_info main_mem; -void __pmm_set(int bit, uint32_t* bitmap) +void pmm_set(int bit); +void pmm_unset(int bit); +bool pmm_test(int bit); +int pmm_first_free(void); +void pmm_init(void); +void* pmm_alloc_block(void); +void pmm_free_block(void* p); + +void __pmm_set(int bit, struct pmm_mem_info mem_block) { - bitmap[bit / 32] |= (1 << (bit % 32)); + (mem_block.bitmap)[bit / 32] |= (1 << (bit % 32)); + mem_block.used_blocks++; + mem_block.free_blocks--; } -void __pmm_unset(int bit, uint32_t* bitmap) +void __pmm_unset(int bit, struct pmm_mem_info mem_block) { - bitmap[bit / 32] &= ~(1 << (bit % 32)); + (mem_block.bitmap)[bit / 32] &= ~(1 << (bit % 32)); + mem_block.used_blocks--; + mem_block.free_blocks--; +} + +bool __pmm_test(int bit, struct pmm_mem_info mem_block) +{ + return (mem_block.bitmap)[bit / 32] & (1 << (bit % 32)); } int __pmm_first_free(struct pmm_mem_info mem_block) @@ -51,10 +79,57 @@ int __pmm_first_free(struct pmm_mem_info mem_block) return (i * 32) + j; // i * 32 is the chunk of 32, plus j to get to the page in the chunk } } - kwarn("OUT OF MEMORY"); return -1; } +void __pmm_add_mem_block(uint32_t addr, int32_t len, struct pmm_mem_info* mem_block) +{ + mem_block->startaddr = addr; + mem_block->len = len; + mem_block->bitmap = 0; +} + +void __pmm_init(struct pmm_mem_info mem_block) +{ + // TODO same as above + mem_block.used_blocks = 0; + mem_block.max_blocks = PMM_GET_MEM_BLOCKS(main_mem); + mem_block.free_blocks = mem_block.max_blocks; + + memset(mem_block.bitmap, 0x0, PMM_GET_MEM_BLOCKS(mem_block) / PMM_BLOCKS_PER_BYTE); // declare all memory available + +#ifdef __TESTING__ + printf("Initialized %1 blocks of memory (%1KiB available)\n", mem_block.max_blocks, mem_block.free_blocks * 4096); +#endif + __pmm_set(0, mem_block); // first block must always be set +} + +void* __pmm_alloc_block(struct pmm_mem_info mem_block) +{ + if (mem_block.free_blocks == 0) { + kerror("OUT OF MEMORY"); + return 0; + } + + int block_in_map = pmm_first_free(); + if (block_in_map == -1) { + kerror("OUT OF MEMORY"); + return 0; + } + + __pmm_set(block_in_map, mem_block); + + return (void*) (mem_block.startaddr + (block_in_map * PMM_PAGE_SIZE)); +} + +void __pmm_free_block(void* p, struct pmm_mem_info mem_block) +{ + uint64_t* addr = (uint64_t*) &p; + int idx = ((*addr) - mem_block.startaddr) / PMM_PAGE_SIZE; + + __pmm_unset(idx, mem_block); +} + void pmm_set(int bit) { /** @@ -67,11 +142,58 @@ void pmm_set(int bit) * * below is merely a temporary solution */ - __pmm_set(bit, main_mem.bitmap); + __pmm_set(bit, main_mem); } void pmm_unset(int bit) { // TODO: same as above - __pmm_unset(bit, main_mem.bitmap); + __pmm_unset(bit, main_mem); } + +bool pmm_test(int bit) +{ + // TODO: same as above + return __pmm_test(bit, main_mem); +} + +int pmm_first_free(void) //TODO implement a free_s where it finds a series of free pages +{ + // TODO: same as above + int ret = __pmm_first_free(main_mem); + if (ret == -1) + kerror("OUT OF MEMORY"); + return ret; +} + + +void pmm_init(void) +{ + // TODO same as above + __pmm_init(main_mem); +} + +void* pmm_alloc_block(void) +{ + return __pmm_alloc_block(main_mem); +} + +void pmm_free_block(void* p) +{ + __pmm_free_block(p, main_mem); +} + +void pmm_add_mem_block(uint32_t addr, uint32_t len) +{ + // TODO: make this add to a linked list + __pmm_add_mem_block(addr, len, &main_mem); +} + +#ifdef __TESTING__ +void print_main_mem() +{ + printf("Available blocks: %1\nUsed blocks: %1\nMax blocks: %1\n", + main_mem.free_blocks, main_mem.used_blocks, main_mem.max_blocks); +} +#endif + diff --git a/kernel/include/kernel/pmm.h b/kernel/include/kernel/pmm.h index a703e29..98832f0 100644 --- a/kernel/include/kernel/pmm.h +++ b/kernel/include/kernel/pmm.h @@ -1,4 +1,15 @@ +#include + #ifndef ARCH_PMM_H #define ARCH_PMM_H +void pmm_init(void); +void* pmm_alloc_block(void); +void pmm_free_block(void* p); +void pmm_add_mem_block(uint32_t addr, uint32_t len); + +#ifdef __TESTING__ +void print_main_mem(); +#endif + #endif diff --git a/kernel/kmain.c b/kernel/kmain.c index 2928594..e869fea 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -34,9 +34,10 @@ void verify_memmap(multiboot_info_t* mbd, uint32_t magic) printf("Start Addr: %4 | Length: %4 | Size: %2 | Type: %d\n", mmmt->addr, mmmt->len, mmmt->size, mmmt->type); - - // mmmt-> len is in bytes (according to multiboot specification0 - // mmmt->len / 1024 == kib // block size == blocks + + if (mmmt->addr == 0x100000) { + pmm_add_mem_block((uint32_t) mmmt->addr, (uint32_t) mmmt->len); + } } } @@ -57,6 +58,13 @@ void _main(multiboot_info_t* mbd, uint32_t magic) serial_initialize(); #endif + pmm_init(); + print_main_mem(); + + pmm_alloc_block(); + + print_main_mem(); + //setup_paging(); init_kb(); diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index f1e4a7f..288ad95 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -115,8 +115,8 @@ int printf(const char* restrict format, ...) { written += len; } else if (*format == '1') { format++; - int32_t i = (int32_t) va_arg(parameters, int32_t); - s32toa(i, buffer, 10); + int32_t i = (uint32_t) va_arg(parameters, int32_t); + u32toa(i, buffer, 10); size_t len = strlen(buffer); if (maxrem < len) { // TODO: Set errno to EOVERFLOW.