diff --git a/.vscode/settings.json b/.vscode/settings.json index af16d73..f25c33f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,9 @@ "limine.h": "c", "stddef.h": "c", "stdint.h": "c", - "typeinfo": "c" + "typeinfo": "c", + "log.h": "c", + "pmm.h": "c", + "paging.h": "c" } } \ No newline at end of file diff --git a/GNUmakefile b/GNUmakefile index 254b739..6af8a94 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -2,7 +2,7 @@ MAKEFLAGS += -rR .SUFFIXES: -QEMUFLAGS := -m 2G -serial stdio -display none +QEMUFLAGS := -m 2G -serial stdio # -display none IMAGE_NAME := release/emk HOST_CC := cc diff --git a/kernel/src/arch/paging.c b/kernel/src/arch/paging.c index d508180..557277c 100644 --- a/kernel/src/arch/paging.c +++ b/kernel/src/arch/paging.c @@ -253,5 +253,10 @@ void paging_init(void) } } + for (uint64_t gb4 = 0; gb4 < 0x100000000; gb4 += PAGE_SIZE) + { + vmap(kernel_pagemap, (uint64_t)HIGHER_HALF(gb4), gb4, VMM_PRESENT | VMM_WRITE); + } + pmset(kernel_pagemap); } \ No newline at end of file diff --git a/kernel/src/emk.c b/kernel/src/emk.c index 093839e..5c18c15 100644 --- a/kernel/src/emk.c +++ b/kernel/src/emk.c @@ -11,6 +11,7 @@ #include #include #include +#include __attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3); __attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request memmap_request = { @@ -67,7 +68,7 @@ void emk_entry(void) hhdm_offset = hhdm_request.response->offset; log_early("HHDM Offset: %llx", hhdm_offset); pmm_init(); - log_early("Initialized PMM"); + log_early("Initialized physical page manager"); /* Test allocate a single physical page */ char *a = palloc(1, true); @@ -89,5 +90,22 @@ void emk_entry(void) paging_init(); log_early("Initialized paging"); + /* Kernel Virtual Memory Context, not to be confused with KVM */ + vpm_ctx_t *kvm_ctx = vmm_init(kernel_pagemap); + if (!kvm_ctx) + { + kpanic(NULL, "Failed to create kernel VMM context"); + } + log_early("Initialized virtual page manager"); + + char *b = valloc(kvm_ctx, 1, VMM_PRESENT | VMM_WRITE); + if (!b) + { + kpanic(NULL, "Failed to allocate single virtual page"); + } + + *b = 32; + log_early("Allocated 1 virtual page: %llx", (uint64_t)b); + hlt(); } \ No newline at end of file diff --git a/kernel/src/mm/vmm.c b/kernel/src/mm/vmm.c new file mode 100644 index 0000000..86b5995 --- /dev/null +++ b/kernel/src/mm/vmm.c @@ -0,0 +1,94 @@ +/* EMK 1.0 Copyright (c) 2025 Piraterna */ +#include +#include +#include +#include +#include +#include + +vpm_ctx_t *vmm_init(uint64_t *pm) +{ + if (!pm || !IS_PAGE_ALIGNED(PHYSICAL(pm))) + return NULL; + + vpm_ctx_t *ctx = (vpm_ctx_t *)palloc(1, true); + if (!ctx) + return NULL; + + ctx->pagemap = pm; + ctx->root = NULL; /* valloc creates the root if not present */ + return ctx; +} + +void *valloc(vpm_ctx_t *ctx, size_t pages, uint64_t flags) +{ + if (!ctx || !pages) + return NULL; + + /* Allocate physical pages */ + void *phys = palloc(pages, true); + if (!phys) + return NULL; + + uint64_t virt = VPM_MIN_ADDR; + vm_region_t *prev = NULL; + vm_region_t *curr = ctx->root; + + while (curr) + { + uint64_t curr_end = curr->start + (curr->pages * PAGE_SIZE); + if (virt + (pages * PAGE_SIZE) <= curr->start) + { + /* Found a gap */ + break; + } + virt = curr_end; + prev = curr; + curr = curr->next; + } + + /* Map the virtual to physical pages */ + for (size_t i = 0; i < pages; i++) + { + uint64_t vaddr = virt + (i * PAGE_SIZE); + uint64_t paddr = (uint64_t)phys + (i * PAGE_SIZE); + if (vmap(ctx->pagemap, vaddr, paddr, flags) != 0) + { + /* Mapping failed, unmap any mapped pages and free physical memory */ + for (size_t j = 0; j < i; j++) + { + vunmap(ctx->pagemap, virt + (j * PAGE_SIZE)); + } + pfree(phys, pages); + return NULL; + } + } + + /* Create new region */ + vm_region_t *region = (vm_region_t *)palloc(1, true); + if (!region) + { + /* Region allocation failed, clean up */ + for (size_t i = 0; i < pages; i++) + { + vunmap(ctx->pagemap, virt + (i * PAGE_SIZE)); + } + pfree(phys, pages); + return NULL; + } + + region->start = virt; + region->pages = pages; + region->next = curr; + + if (prev) + { + prev->next = region; + } + else + { + ctx->root = region; + } + + return (void *)virt; +} \ No newline at end of file diff --git a/kernel/src/mm/vmm.h b/kernel/src/mm/vmm.h index 42e616b..5d1f1f8 100644 --- a/kernel/src/mm/vmm.h +++ b/kernel/src/mm/vmm.h @@ -3,6 +3,11 @@ #define VMM_H #include +#include + +#ifndef VPM_MIN_ADDR +#define VPM_MIN_ADDR 0x1000 +#endif // VPM_MIN_ADDR typedef struct vm_region { @@ -12,12 +17,13 @@ typedef struct vm_region /* TOOD: Maybe store flags */ } vm_region_t; -typedef struct vma_ctx +typedef struct vpm_ctx { vm_region_t *root; uint64_t *pagemap; -} vma_ctx_t; +} vpm_ctx_t; -void vmm_init(); +vpm_ctx_t *vmm_init(uint64_t *pm); +void *valloc(vpm_ctx_t *ctx, size_t pages, uint64_t flags); #endif // VMM_H \ No newline at end of file