summaryrefslogtreecommitdiff
path: root/na/mm/vmm.cc
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-04-21 23:22:52 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-04-21 23:22:52 +0800
commitab2c0a8ea472679c846e74ca40823091becc5bf0 (patch)
treeeeb05d4f93dc6ab901a3a5a1562604f02ed9c885 /na/mm/vmm.cc
parent0a657596e19281f57ae74fd00e38cf25fee4d8cd (diff)
downloadlume-ab2c0a8ea472679c846e74ca40823091becc5bf0.tar.gz
lume-ab2c0a8ea472679c846e74ca40823091becc5bf0.tar.xz
feat: add Virtual Memory Manager and Virtual Memory Area management
Diffstat (limited to 'na/mm/vmm.cc')
-rw-r--r--na/mm/vmm.cc124
1 files changed, 124 insertions, 0 deletions
diff --git a/na/mm/vmm.cc b/na/mm/vmm.cc
new file mode 100644
index 0000000..54e9b15
--- /dev/null
+++ b/na/mm/vmm.cc
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+/*
+ * vmm.cc — Virtual Memory Manager (Phase 1: Kernel Page Table)
+ *
+ * Builds a fine-grained kernel page table (4KB pages, precise
+ * permissions per section), activates it, and retires the early_pgdir
+ * identity mapping from entry.S.
+ *
+ * This module is machine-independent (MI). All architecture-specific
+ * page table manipulation goes through the pmap:: namespace.
+ *
+ * Reference: docs/specs/vmm.md
+ */
+
+#include <lume/types.h>
+#include <lume/addr.h>
+#include <lume/pmm.h>
+#include <lume/panic.h>
+#include <lume/fdt.h>
+#include <lume/vmm.h>
+#include <arch/pmap.h>
+#include <arch/mmu.h>
+
+/* Linker-exported section boundaries (virtual addresses) */
+extern "C" char _stext[], _etext[];
+extern "C" char _srodata[], _erodata[];
+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;
+
+/* Convert a linker symbol to PA. Handles both VA and PA cases. */
+static inline uint64 sym_to_pa(const void *sym)
+{
+ return ensure_pa(reinterpret_cast<uint64>(sym));
+}
+
+/* Map a PA range into the kernel page table with given permissions.
+ * All addresses must be page-aligned. Panics on failure. */
+static 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(pa);
+ int ret = pmap::map(root, va, pa, perm | pmap::PTE_G);
+ if (ret != 0)
+ kernel_panic("vmm_init: pmap::map failed");
+ }
+}
+
+
+
+void vmm_init()
+{
+ /* 1. Allocate new root page table */
+ uint64 root = pmap::create();
+ if (!root)
+ kernel_panic("vmm_init: failed to create root page table");
+
+ /* 2. Compute PA boundaries of each kernel section */
+ uint64 text_start = page_align_down(sym_to_pa(_stext));
+ uint64 text_end = page_align_up(sym_to_pa(_etext));
+ uint64 ro_start = page_align_down(sym_to_pa(_srodata));
+ uint64 ro_end = page_align_up(sym_to_pa(_erodata));
+ uint64 data_start = page_align_down(sym_to_pa(_sdata));
+ uint64 bss_end = page_align_up(sym_to_pa(_ebss));
+
+ /* Memory extent from PMM */
+ uint64 mem_base = pmm_get_mem_base();
+ uint64 mem_end = mem_base + pmm_get_mem_size();
+
+ /* 3. Map kernel .text (RX) */
+ map_range(root, text_start, text_end,
+ pmap::PTE_R | pmap::PTE_X);
+
+ /* 4. Map .rodata (R) */
+ map_range(root, ro_start, ro_end,
+ pmap::PTE_R);
+
+ /* 5. Map .data + .bss (RW) */
+ map_range(root, data_start, bss_end,
+ pmap::PTE_R | pmap::PTE_W);
+
+ /* 6. Map remaining physical memory after kernel (RW)
+ * This covers frame_map, slab objects, and all free pages. */
+ 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);
+ }
+ /* 7. MMIO regions will be mapped later via vmm_map_kernel_mmio by architecture/drivers */
+
+ /* 8. Activate the new page table */
+ pmap::activate(root);
+
+ g_kernel_pgtbl = root;
+}
+
+void vmm_init_ap()
+{
+ /* AP just switches to the kernel page table built by BSP */
+ if (!g_kernel_pgtbl)
+ kernel_panic("vmm_init_ap: kernel page table not ready");
+ pmap::activate(g_kernel_pgtbl);
+}
+
+void vmm_map_kernel_mmio(uint64 pa, uint64 size)
+{
+ if (!g_kernel_pgtbl)
+ kernel_panic("vmm_map_kernel_mmio: kernel page table not ready");
+
+ uint64 aligned_pa = page_align_down(pa);
+ uint64 aligned_size = page_align_up(pa + size) - aligned_pa;
+
+ 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();
+}
+
+
+