:: commit 3f32d802ae10334802a9b5e1fe73583345e21511

mintsuki <mintsuki@protonmail.com> — 2024-10-25 03:26

parents: d10269ccbe

vmm: Automatically detect right page size to use

diff --git a/common/mm/vmm.c b/common/mm/vmm.c
index 8adacae2..c2066656 100644
--- a/common/mm/vmm.c
+++ b/common/mm/vmm.c
@@ -24,6 +24,27 @@ static pt_entry_t *get_next_level(pagemap_t pagemap, pt_entry_t *current_level,
                                   uint64_t virt, enum page_size desired_sz,
                                   size_t level_idx, size_t entry);
 
+void map_pages(pagemap_t pagemap, uint64_t virt, uint64_t phys, uint64_t flags, uint64_t count) {
+    if (virt % 0x1000 != 0 || phys % 0x1000 != 0 || count % 0x1000 != 0) {
+        panic(true, "vmm: Misaligned call to map_pages()");
+    }
+
+    for (uint64_t i = 0; i < count; ) {
+        if ((i & (0x40000000 - 1)) == 0 && count - i >= 0x40000000) {
+            map_page(pagemap, virt + i, phys + i, flags, Size1GiB);
+            i += 0x40000000;
+            continue;
+        }
+        if ((i & (0x200000 - 1)) == 0 && count - i >= 0x200000) {
+            map_page(pagemap, virt + i, phys + i, flags, Size2MiB);
+            i += 0x200000;
+            continue;
+        }
+        map_page(pagemap, virt + i, phys + i, flags, Size4KiB);
+        i += 0x1000;
+    }
+}
+
 #if defined (__x86_64__) || defined (__i386__)
 
 #define PT_FLAG_VALID    ((uint64_t)1 << 0)
diff --git a/common/mm/vmm.h b/common/mm/vmm.h
index 00fe07b0..ba8fa10f 100644
--- a/common/mm/vmm.h
+++ b/common/mm/vmm.h
@@ -161,5 +161,6 @@ void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_
 #endif
 
 int vmm_max_paging_mode(void);
+void map_pages(pagemap_t pagemap, uint64_t virt, uint64_t phys, uint64_t flags, uint64_t count);
 
 #endif
diff --git a/common/protos/limine.c b/common/protos/limine.c
index bcc95cf5..55dc3e55 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -75,10 +75,7 @@ static uint64_t get_hhdm_span_top(int base_revision) {
 static pagemap_t build_identity_map(void) {
     pagemap_t pagemap = new_pagemap(paging_mode);
 
-    for (uint64_t i = 0; i < 0x100000000; i += 0x40000000) {
-        map_page(pagemap, i, i, VMM_FLAG_WRITE, Size1GiB);
-    }
-
+    map_pages(pagemap, 0, 0, VMM_FLAG_WRITE, 0x100000000);
 
     size_t _memmap_entries = memmap_entries;
     struct memmap_entry *_memmap =
@@ -105,14 +102,11 @@ static pagemap_t build_identity_map(void) {
             continue;
         }
 
-        uint64_t aligned_base   = ALIGN_DOWN(base, 0x40000000);
-        uint64_t aligned_top    = ALIGN_UP(top, 0x40000000);
+        uint64_t aligned_base   = ALIGN_DOWN(base, 0x1000);
+        uint64_t aligned_top    = ALIGN_UP(top, 0x1000);
         uint64_t aligned_length = aligned_top - aligned_base;
 
-        for (uint64_t j = 0; j < aligned_length; j += 0x40000000) {
-            uint64_t page = aligned_base + j;
-            map_page(pagemap, page, page, VMM_FLAG_WRITE, Size1GiB);
-        }
+        map_pages(pagemap, aligned_base, aligned_base, VMM_FLAG_WRITE, aligned_length);
     }
 
     return pagemap;
@@ -157,33 +151,16 @@ static pagemap_t build_pagemap(int base_revision,
             (ranges[i].permissions & ELF_PF_X ? 0 : (nx ? VMM_FLAG_NOEXEC : 0)) |
             (ranges[i].permissions & ELF_PF_W ? VMM_FLAG_WRITE : 0);
 
-        for (uint64_t j = 0; j < ranges[i].length; j += 0x1000) {
-            map_page(pagemap, virt + j, phys + j, pf, Size4KiB);
-        }
+        map_pages(pagemap, virt, phys, pf, ranges[i].length);
     }
 
     // Map 0x1000->4GiB range to identity if base revision == 0
     if (base_revision == 0) {
-        // Sub 2MiB mappings
-        for (uint64_t i = 0x1000; i < 0x200000; i += 0x1000) {
-            map_page(pagemap, i, i, VMM_FLAG_WRITE, Size4KiB);
-        }
-
-        // Map 2MiB to 4GiB
-        for (uint64_t i = 0x200000; i < 0x40000000; i += 0x200000) {
-            map_page(pagemap, i, i, VMM_FLAG_WRITE, Size2MiB);
-        }
-
-        // Map the rest
-        for (uint64_t i = 0x40000000; i < 0x100000000; i += 0x40000000) {
-            map_page(pagemap, i, i, VMM_FLAG_WRITE, Size1GiB);
-        }
+        map_pages(pagemap, 0x1000, 0x1000, VMM_FLAG_WRITE, 0x100000000 - 0x1000);
     }
 
     // Map 0->4GiB range to HHDM
-    for (uint64_t i = 0; i < 0x100000000; i += 0x40000000) {
-        map_page(pagemap, direct_map_offset + i, i, VMM_FLAG_WRITE, Size1GiB);
-    }
+    map_pages(pagemap, direct_map_offset, 0, VMM_FLAG_WRITE, 0x100000000);
 
     size_t _memmap_entries = memmap_entries;
     struct memmap_entry *_memmap =
@@ -211,17 +188,14 @@ static pagemap_t build_pagemap(int base_revision,
             continue;
         }
 
-        uint64_t aligned_base   = ALIGN_DOWN(base, 0x40000000);
-        uint64_t aligned_top    = ALIGN_UP(top, 0x40000000);
+        uint64_t aligned_base   = ALIGN_DOWN(base, 0x1000);
+        uint64_t aligned_top    = ALIGN_UP(top, 0x1000);
         uint64_t aligned_length = aligned_top - aligned_base;
 
-        for (uint64_t j = 0; j < aligned_length; j += 0x40000000) {
-            uint64_t page = aligned_base + j;
-            if (base_revision == 0) {
-                map_page(pagemap, page, page, VMM_FLAG_WRITE, Size1GiB);
-            }
-            map_page(pagemap, direct_map_offset + page, page, VMM_FLAG_WRITE, Size1GiB);
+        if (base_revision == 0) {
+            map_pages(pagemap, aligned_base, aligned_base, VMM_FLAG_WRITE, aligned_length);
         }
+        map_pages(pagemap, direct_map_offset + aligned_base, aligned_base, VMM_FLAG_WRITE, aligned_length);
     }
 
     // Map the framebuffer with appropriate permissions
@@ -238,21 +212,16 @@ static pagemap_t build_pagemap(int base_revision,
         uint64_t aligned_top    = ALIGN_UP(top, 0x1000);
         uint64_t aligned_length = aligned_top - aligned_base;
 
-        for (uint64_t j = 0; j < aligned_length; j += 0x1000) {
-            uint64_t page = aligned_base + j;
-            if (base_revision == 0) {
-                map_page(pagemap, page, page, VMM_FLAG_WRITE | VMM_FLAG_FB, Size4KiB);
-            }
-            map_page(pagemap, direct_map_offset + page, page, VMM_FLAG_WRITE | VMM_FLAG_FB, Size4KiB);
+        if (base_revision == 0) {
+            map_pages(pagemap, aligned_base, aligned_base, VMM_FLAG_WRITE | VMM_FLAG_FB, aligned_length);
         }
+        map_pages(pagemap, direct_map_offset + aligned_base, aligned_base, VMM_FLAG_WRITE | VMM_FLAG_FB, aligned_length);
     }
 
     // XXX we do this as a quick and dirty way to switch to the higher half
 #if defined (__x86_64__) || defined (__i386__)
     if (base_revision >= 1) {
-        for (uint64_t i = 0; i < 0x100000000; i += 0x40000000) {
-            map_page(pagemap, i, i, VMM_FLAG_WRITE, Size1GiB);
-        }
+        map_pages(pagemap, 0, 0, VMM_FLAG_WRITE, 0x100000000);
     }
 #endif
 
tab: 248 wrap: offon