:: commit 0c7e08d3c7c2c09a571d6d01632b55587ec03f89

mintsuki <mintsuki@protonmail.com> — 2020-09-11 08:53

parents: 9802c8d36e

Add a more proper 64-bit vmm

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 <stdint.h>
+#include <stddef.h>
+#include <mm/vmm64.h>
+#include <lib/blib.h>
+
+#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 <stdint.h>
+
+#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 <drivers/pic.h>
 #include <fs/file.h>
 #include <lib/asm.h>
+#include <mm/vmm64.h>
 
 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_ptr = (void *)pagemap;
+            pagemap_t pagemap = new_pagemap();
 
-            // zero out the pagemap
-            for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
-                *p = 0;
+            // Map 0 to 2GiB at 0xffffffff80000000
+            for (uint64_t i = 0; i < 0x80000000; i += PAGE_SIZE) {
+                map_page(pagemap, i + 0xffffffff80000000, i, 0x03);
+            }
 
-            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;
+            // 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);
+            }
 
-            // populate the page directories
-            for (size_t i = 0; i < 512 * 4; i++)
-                (&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7);
+            pagemap_ptr = (void *)pagemap;
         }
 
         ASM(
tab: 248 wrap: offon