summaryrefslogtreecommitdiff
path: root/na/mm/vmm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'na/mm/vmm.cc')
-rw-r--r--na/mm/vmm.cc65
1 files changed, 45 insertions, 20 deletions
diff --git a/na/mm/vmm.cc b/na/mm/vmm.cc
index 0aa2fb0..51617e3 100644
--- a/na/mm/vmm.cc
+++ b/na/mm/vmm.cc
@@ -18,6 +18,7 @@
#include <arch/config.h>
#include <arch/mmu.h>
#include <arch/pmap.h>
+#include <lume/tlb.h>
#include <lume/addr.h>
#include <lume/console.h>
#include <lume/fdt.h>
@@ -28,6 +29,7 @@
#include <lume/pmm.h>
#include <lume/types.h>
#include <lume/vmm.h>
+#include <lume/config.h>
/* Linker-exported section boundaries (virtual addresses) */
extern "C" char _stext[], _etext[];
@@ -36,25 +38,23 @@ extern "C" char _sdata[], _edata[];
extern "C" char _sbss[], _ebss[];
extern "C" char _kernel_end[];
-/* Global kernel page table root PA */
-static uint64 g_kernel_pgtbl = 0;
+/* Global kernel page table root PA — external linkage for task_exit */
+uint64 g_kernel_pgtbl = 0;
-/* VMM exports for PMM: page_map location after vmemmap mapping. */
-static uint64 g_vmemmap_page_map_pa = 0;
-static uint64 g_vmemmap_page_map_size = 0;
-static uint64 g_vmemmap_num_pages = 0;
+namespace {
-uint64 vmm_get_page_map_pa() { return g_vmemmap_page_map_pa; }
-uint64 vmm_get_page_map_size() { return g_vmemmap_page_map_size; }
-uint64 vmm_get_num_pages() { return g_vmemmap_num_pages; }
+/* VMM exports for PMM: page_map location after vmemmap mapping. */
+uint64 g_vmemmap_page_map_pa = 0;
+uint64 g_vmemmap_page_map_size = 0;
+uint64 g_vmemmap_num_pages = 0;
/* Convert a linker symbol to PA (kernel is executing in higher-half VA). */
-static inline uint64 sym_to_pa(const void *sym) {
+inline uint64 sym_to_pa(const void *sym) {
return boot_va_to_pa(virt_addr(reinterpret_cast<uint64>(sym))).raw;
}
/* Map a PA range into the kernel page table via the direct map. */
-static void map_range(uint64 root, uint64 pa_start, uint64 pa_end,
+void map_range(uint64 root, uint64 pa_start, uint64 pa_end,
uint64 perm) {
for (uint64 pa = pa_start; pa < pa_end; pa += kPageSize) {
uint64 va = pa_to_va(phys_addr(pa)).raw;
@@ -66,7 +66,7 @@ static void map_range(uint64 root, uint64 pa_start, uint64 pa_end,
}
/* Map a PA range into the kernel page table at the fixed linked VA. */
-static void map_range_linked(uint64 root, uint64 pa_start, uint64 pa_end,
+void map_range_linked(uint64 root, uint64 pa_start, uint64 pa_end,
uint64 perm) {
for (uint64 pa = pa_start; pa < pa_end; pa += kPageSize) {
uint64 va = boot_pa_to_va(phys_addr(pa)).raw;
@@ -78,7 +78,7 @@ static void map_range_linked(uint64 root, uint64 pa_start, uint64 pa_end,
}
/* Map a PA range to an explicit VA base, using 2MB pages where possible. */
-static void map_range_at_huge(uint64 root, uint64 va_base, uint64 pa_start,
+void map_range_at_huge(uint64 root, uint64 va_base, uint64 pa_start,
uint64 pa_end, uint64 perm) {
constexpr uint64 k2MB = 2ULL * 1024 * 1024;
uint64 pa = pa_start;
@@ -109,6 +109,12 @@ static void map_range_at_huge(uint64 root, uint64 va_base, uint64 pa_start,
}
}
+} // namespace
+
+uint64 vmm_get_page_map_pa() { return g_vmemmap_page_map_pa; }
+uint64 vmm_get_page_map_size() { return g_vmemmap_page_map_size; }
+uint64 vmm_get_num_pages() { return g_vmemmap_num_pages; }
+
void vmm_init() {
/* 1. Allocate new root page table (from memblock) */
uint64 root = pmap::create();
@@ -137,17 +143,36 @@ void vmm_init() {
*/
map_range_linked(root, text_start, text_end, pmap::PTE_R | pmap::PTE_X);
- /* 4. Map .rodata (R) at fixed linked VA */
- map_range_linked(root, ro_start, ro_end, pmap::PTE_R);
+ /* 4. Map .rodata (R) at fixed linked VA.
+ * We map [_srodata, _sdata) so that the .lume.reloc section (which
+ * sits in its own padded output section between _erodata and _sdata)
+ * is also covered. Relocator only reads it during early boot, but
+ * mapping it keeps post-vmm accesses to __lume_reloc_* symbols sane. */
+ map_range_linked(root, ro_start, page_align_down(sym_to_pa(_sdata)),
+ pmap::PTE_R);
/* 5. Map .data + .bss (RW) at fixed linked VA */
map_range_linked(root, data_start, bss_end, pmap::PTE_R | pmap::PTE_W);
- /* 6. Map remaining physical memory after kernel (RW) */
- uint64 after_kernel = page_align_up(sym_to_pa(_kernel_end));
- if (after_kernel < mem_end) {
- map_range(root, after_kernel, mem_end, pmap::PTE_R | pmap::PTE_W);
+ /* 6. Map usable physical RAM into the KASLR-slid direct map.
+ *
+ * The direct map provides pa_to_va() / va_to_pa() for the physical
+ * address space. We map from kPhysStart (the kernel's linked load
+ * address), skipping [mem_base, kPhysStart) because that region is
+ * PMP-protected firmware (OpenSBI) — S-mode cannot access it.
+ *
+ * Linux does the same on RISC-V: the linear map covers only the
+ * usable RAM range, not firmware-reserved regions.
+ *
+ * Uses 2MB huge pages for efficiency (64 entries for 128MB vs 32K).
+ */
+ uint64 dm_start = kPhysStart;
+ if (dm_start < mem_base) {
+ dm_start = mem_base;
}
+ uint64 dm_va_base = pa_to_va(phys_addr(dm_start)).raw;
+ map_range_at_huge(root, dm_va_base, dm_start, mem_end,
+ pmap::PTE_R | pmap::PTE_W);
/* 7. Allocate page_map from memblock (top of RAM) and map at VMEMMAP.
*
@@ -206,5 +231,5 @@ void vmm_map_kernel_mmio(uint64 pa, uint64 size) {
map_range(g_kernel_pgtbl, aligned_pa, aligned_pa + aligned_size,
pmap::PTE_R | pmap::PTE_W | pmap::PTE_G);
- arch::mmu::flush_tlb_all();
+ tlb_shootdown_all();
}