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
