From 0c7e08d3c7c2c09a571d6d01632b55587ec03f89 Mon Sep 17 00:00:00 2001 From: mintsuki Date: Fri, 11 Sep 2020 10:53:21 +0200 Subject: [PATCH] Add a more proper 64-bit vmm --- src/lib/blib.c | 4 ++++ src/mm/vmm64.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/mm/vmm64.h | 13 +++++++++++++ src/protos/stivale.c | 42 ++++++++++++++---------------------------- 4 files changed, 75 insertions(+), 28 deletions(-) create mode 100644 src/mm/vmm64.c create mode 100644 src/mm/vmm64.h diff --git a/src/lib/blib.c b/src/lib/blib.c index 6cbd9ef9..e5fe0558 100644 --- a/src/lib/blib.c +++ b/src/lib/blib.c @@ -65,6 +65,10 @@ void *balloc_aligned(size_t count, size_t alignment) { if (new_base >= BUMP_ALLOCATOR_LIMIT) panic("Memory allocation failed"); bump_allocator_base = new_base; + + // Zero out allocated space + memset(ret, 0, count); + return ret; } diff --git a/src/mm/vmm64.c b/src/mm/vmm64.c new file mode 100644 index 00000000..78e0ad4b --- /dev/null +++ b/src/mm/vmm64.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +#define PT_SIZE ((uint64_t)0x1000) + +typedef uint64_t pt_entry_t; + +static pt_entry_t *get_next_level(pt_entry_t *current_level, size_t entry) { + pt_entry_t *ret; + + if (current_level[entry] & 0x1) { + // Present flag set + ret = (pt_entry_t *)(current_level[entry] & ~((pt_entry_t)0xfff)); + } else { + // Allocate a table for the next level + ret = balloc_aligned(PT_SIZE, PT_SIZE); + // Present + writable + user (0b111) + current_level[entry] = (pt_entry_t)ret | 0b111; + } + + return ret; +} + +pagemap_t new_pagemap(void) { + return (pagemap_t)(size_t)balloc_aligned(PT_SIZE, PT_SIZE); +} + +void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags) { + // Calculate the indices in the various tables using the virtual address + size_t pml4_entry = (virt_addr & ((uint64_t)0x1ff << 39)) >> 39; + size_t pml3_entry = (virt_addr & ((uint64_t)0x1ff << 30)) >> 30; + size_t pml2_entry = (virt_addr & ((uint64_t)0x1ff << 21)) >> 21; + + pt_entry_t *pml4 = (pt_entry_t *)(size_t)pagemap; + pt_entry_t *pml3 = get_next_level(pml4, pml4_entry); + pt_entry_t *pml2 = get_next_level(pml3, pml3_entry); + + // Set the entry as present and point it to the passed physical address + // Also set the specified flags + // We only use 2MiB pages else we would not have enough space + pml2[pml2_entry] = (pt_entry_t)(phys_addr | flags | (1 << 7)); +} diff --git a/src/mm/vmm64.h b/src/mm/vmm64.h new file mode 100644 index 00000000..7e63f58e --- /dev/null +++ b/src/mm/vmm64.h @@ -0,0 +1,13 @@ +#ifndef __MM__VMM64_H__ +#define __MM__VMM64_H__ + +#include + +#define PAGE_SIZE ((uint64_t)0x200000) + +typedef uint64_t pagemap_t; + +pagemap_t new_pagemap(void); +void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags); + +#endif diff --git a/src/protos/stivale.c b/src/protos/stivale.c index 6bec7370..beb8461e 100644 --- a/src/protos/stivale.c +++ b/src/protos/stivale.c @@ -16,6 +16,7 @@ #include #include #include +#include struct stivale_header { uint64_t stack; @@ -304,35 +305,20 @@ __attribute__((noreturn)) void stivale_spinup(int bits, bool level5pg, for (size_t i = 0; i < 512 * 4; i++) (&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7); } else { - struct pagemap { - uint64_t pml4[512]; - uint64_t pml3_lo[512]; - uint64_t pml3_hi[512]; - uint64_t pml2_0gb[512]; - uint64_t pml2_1gb[512]; - uint64_t pml2_2gb[512]; - uint64_t pml2_3gb[512]; - }; - struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000); + pagemap_t pagemap = new_pagemap(); + + // Map 0 to 2GiB at 0xffffffff80000000 + for (uint64_t i = 0; i < 0x80000000; i += PAGE_SIZE) { + map_page(pagemap, i + 0xffffffff80000000, i, 0x03); + } + + // Map 0 to 4GiB at 0xffff800000000000 and 0 + for (uint64_t i = 0; i < 0x100000000; i += PAGE_SIZE) { + map_page(pagemap, i, i, 0x03); + map_page(pagemap, i + 0xffff800000000000, i, 0x03); + } + pagemap_ptr = (void *)pagemap; - - // zero out the pagemap - for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++) - *p = 0; - - pagemap->pml4[511] = (uint64_t)(size_t)pagemap->pml3_hi | 0x03; - pagemap->pml4[256] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03; - pagemap->pml4[0] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03; - pagemap->pml3_hi[510] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03; - pagemap->pml3_hi[511] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03; - pagemap->pml3_lo[0] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03; - pagemap->pml3_lo[1] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03; - pagemap->pml3_lo[2] = (uint64_t)(size_t)pagemap->pml2_2gb | 0x03; - pagemap->pml3_lo[3] = (uint64_t)(size_t)pagemap->pml2_3gb | 0x03; - - // populate the page directories - for (size_t i = 0; i < 512 * 4; i++) - (&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7); } ASM(