From 616b0208c22572bea0f154ec9f00ccf5e0238d98 Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 12 Apr 2023 21:40:16 -0300 Subject: [PATCH] kernel: pmm --- kernel-src/arch/x86-64/main.c | 2 + kernel-src/include/kernel/pmm.h | 21 ++++ kernel-src/mm/pmm.c | 174 ++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 kernel-src/include/kernel/pmm.h create mode 100644 kernel-src/mm/pmm.c diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index c7086592..ed0eea43 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -4,6 +4,7 @@ #include #include #include +#include static cpu_t bsp_cpu; @@ -13,6 +14,7 @@ void kernel_entry() { arch_gdt_reload(); arch_idt_setup(); arch_idt_reload(); + pmm_init(); term_init(); __assert(!"kernel entry end"); } diff --git a/kernel-src/include/kernel/pmm.h b/kernel-src/include/kernel/pmm.h new file mode 100644 index 00000000..c5cb1561 --- /dev/null +++ b/kernel-src/include/kernel/pmm.h @@ -0,0 +1,21 @@ +#ifndef _PMM_H +#define _PMM_H + +#include +#include + +#define PMM_SECTION_COUNT 3 +#define PMM_SECTION_1MB 0 +#define PMM_SECTION_4GB 1 +#define PMM_SECTION_DEFAULT 2 + +void *pmm_alloc(size_t count, int flags); +void pmm_free(void *addr, size_t count); +void pmm_init(); + +extern uintptr_t hhdmbase; + +#define MAKE_HHDM(x) (void *)((uintptr_t)x + hhdmbase) +#define FROM_HHDM(x) (void *)((uintptr_t)x - hhdmbase) + +#endif diff --git a/kernel-src/mm/pmm.c b/kernel-src/mm/pmm.c new file mode 100644 index 00000000..ddb21316 --- /dev/null +++ b/kernel-src/mm/pmm.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include + +uintptr_t hhdmbase; +static size_t memorysize; +static size_t physicalpagecount; + +typedef struct { + uintmax_t base; + uintmax_t top; + uintmax_t searchstart; +} bmsection_t; + +static bmsection_t bmsections[PMM_SECTION_COUNT]; + +static uint64_t *bitmap; + +// TODO move to arch specific header +#define PAGE_SIZE 4096 + +static volatile struct limine_hhdm_request hhdmreq = { + .id = LIMINE_HHDM_REQUEST, + .revision = 0 +}; + +volatile struct limine_memmap_request pmm_liminemap = { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0 +}; + +static inline void bmset(void *addr, int v) { + uintmax_t page = (uintptr_t)addr / PAGE_SIZE; + uintmax_t entry = page / 64; + uintmax_t offset = page % 64; + + uint64_t entryval = bitmap[entry]; + entryval &= ~((uint64_t)1 << offset); + entryval |= v << offset; + bitmap[entry] = entryval; +} + +static uintmax_t getfreearea(bmsection_t *section, size_t size) { + uintmax_t result = 0; + uintmax_t found = 0; + + for (uintmax_t search = section->searchstart; search < section->top && found < size; ++search) { + uintmax_t entry = search / 64; + uintmax_t offset = search % 64; + + if (bitmap[entry] == 0) { + search += 63 - offset; // 63 because search gets incremented on continue + result = 0; + found = 0; + continue; + } + + if (((bitmap[entry] >> offset) & 1) == 0) { + found = 0; + result = 0; + continue; + } + + if (found == 0) + result = search; + + ++found; + } + + return result; +} + +static inline void initsection(int section, uintmax_t base, uintmax_t top) { + bmsections[section] = (bmsection_t){ + .base = base, + .top = top, + .searchstart = base + }; +} + +void *pmm_alloc(size_t size, int section) { + for (int i = section; i >= 0; --i) { + // TODO lock section + uintmax_t page = getfreearea(&bmsections[i], size); + + if (page) { + if (page == bmsections[i].searchstart) + bmsections[i].searchstart += size; + + for (size_t j = 0; j < size; ++j) + bmset((void *)((page + j) * PAGE_SIZE), 0); + // TODO unlock + return (void *)(page * PAGE_SIZE); + } + // TODO unlock section + } + return NULL; +} + +void pmm_free(void *addr, size_t size) { + uintmax_t page = (uintptr_t)addr / PAGE_SIZE; + + for (int i = 0; i < PMM_SECTION_COUNT; ++i) { + if (page >= bmsections[i].base && page < bmsections[i].top) { + // TODO lock + + if ((uintptr_t)addr / PAGE_SIZE < bmsections[i].searchstart) + bmsections[i].searchstart = (uintptr_t)addr / PAGE_SIZE; + + for (uintmax_t j = 0; j < size; ++j) + bmset((void *)((page + j) * PAGE_SIZE), 1); + + // TODO unlock + return; + } + } +} + +#define TOP_1MB (0x100000 / PAGE_SIZE) +#define TOP_4GB ((uint64_t)0x100000000 / PAGE_SIZE) + +void pmm_init() { + __assert(hhdmreq.response); + hhdmbase = hhdmreq.response->offset; + __assert(pmm_liminemap.response); + + uintmax_t topofmemory = 0; + + // get size of memory and print memory map + printf("memory map:\n"); + for (size_t i = 0; i < pmm_liminemap.response->entry_count; ++i) { + struct limine_memmap_entry *e = pmm_liminemap.response->entries[i]; + printf("%016p -> %016p: %d\n", e->base, e->base + e->length, e->type); + if (e->type == LIMINE_MEMMAP_USABLE) { + topofmemory = e->base + e->length; + memorysize += e->length; + } + } + + physicalpagecount = topofmemory / PAGE_SIZE; + + size_t bitmapsize = physicalpagecount / 8; + + // find out where to put the bitmap + for (uintmax_t i = 0; i < pmm_liminemap.response->entry_count; ++i) { + struct limine_memmap_entry *e = pmm_liminemap.response->entries[i]; + if (e->type == LIMINE_MEMMAP_USABLE && e->length >= bitmapsize) + bitmap = (uint64_t *)e->base; + } + __assert(bitmap); + + memset(bitmap, 0, bitmapsize); + + // set free pages + for (uintmax_t i = 0; i < pmm_liminemap.response->entry_count; ++i) { + struct limine_memmap_entry *e = pmm_liminemap.response->entries[i]; + if (e->type != LIMINE_MEMMAP_USABLE) + continue; + + for (uintmax_t offset = 0; offset < e->length; offset += PAGE_SIZE) + bmset((void *)(e->base + offset), 1); + } + + // set bitmap as used + for (uintmax_t offset = 0; offset < bitmapsize; offset += PAGE_SIZE) + bmset((void *)((uintptr_t)bitmap + offset), 0); + + // prepare sections + // for all cases this section will always be present so hardcode its values (otherwise the system wouldn't even get here) + initsection(PMM_SECTION_1MB, 1, TOP_1MB); + initsection(PMM_SECTION_4GB, TOP_1MB, physicalpagecount > TOP_4GB ? TOP_4GB : physicalpagecount); + initsection(PMM_SECTION_DEFAULT, TOP_4GB, physicalpagecount > TOP_4GB ? physicalpagecount : TOP_4GB); +}