diff options
Diffstat (limited to 'mm/vmm.cc')
| -rw-r--r-- | mm/vmm.cc | 235 |
1 files changed, 0 insertions, 235 deletions
diff --git a/mm/vmm.cc b/mm/vmm.cc deleted file mode 100644 index 51617e3..0000000 --- a/mm/vmm.cc +++ /dev/null @@ -1,235 +0,0 @@ -/* 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, activates it, and retires - * the early_pgdir identity mapping from entry.S. - * - * With memblock integration, the initialization order is: - * memblock_init → vmm_init (allocates page_map from memblock, - * maps vmemmap, activates page table) → pmm_init (buddy system - * starts with page_map already at vmemmap VA — no relocation). - * - * Reference: docs/specs/vmm.md - */ - -#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> -#include <lume/page.h> -#include <lume/klog.h> -#include <lume/kprintf.h> -#include <lume/memblock.h> -#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[]; -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 — external linkage for task_exit */ -uint64 g_kernel_pgtbl = 0; - -namespace { - -/* 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). */ -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. */ -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; - int ret = pmap::map(root, va, pa, perm | pmap::PTE_G); - if (ret != 0) { - kernel_panic("vmm_init: pmap::map failed"); - } - } -} - -/* Map a PA range into the kernel page table at the fixed linked VA. */ -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; - int ret = pmap::map(root, va, pa, perm | pmap::PTE_G); - if (ret != 0) { - kernel_panic("vmm_init: pmap::map (linked) failed"); - } - } -} - -/* Map a PA range to an explicit VA base, using 2MB pages where possible. */ -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; - uint64 va = va_base; - - /* Map 2MB-aligned chunks with mega pages */ - while (pa + k2MB <= pa_end) { - if ((va & (k2MB - 1)) == 0 && (pa & (k2MB - 1)) == 0) { - int ret = pmap::map_2mb(root, va, pa, perm | pmap::PTE_G); - if (ret != 0) { - kernel_panic("vmm_init: pmap::map_2mb failed"); - } - pa += k2MB; - va += k2MB; - } else { - break; - } - } - - /* Map remaining 4KB tail */ - while (pa < pa_end) { - int ret = pmap::map(root, va, pa, perm | pmap::PTE_G); - if (ret != 0) { - kernel_panic("vmm_init: vmemmap 4KB pmap::map failed"); - } - pa += kPageSize; - va += kPageSize; - } -} - -} // 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(); - 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 memblock */ - uint64 mem_base = memblock_get_mem_base(); - uint64 mem_size = memblock_get_mem_size(); - uint64 mem_end = mem_base + mem_size; - - /* 3. Map kernel image at FIXED linked VA. - * - * Kernel text/data are linked at the bootstrap higher-half addresses - * (kDirectMapBaseDefault + PA). They must remain executable/readable at - * those addresses until full kernel-image relocation is implemented. - */ - map_range_linked(root, text_start, text_end, pmap::PTE_R | pmap::PTE_X); - - /* 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 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. - * - * Since memblock is active (PMM not yet initialized), pmap::map - * allocates page table pages from memblock too. page_map starts - * life at the vmemmap VA — no relocation ever needed. - */ - uint64 num_pages = mem_size / kPageSize; - uint64 page_map_bytes = num_pages * sizeof(Page); - uint64 page_map_span = page_align_up(page_map_bytes); - uint64 page_map_pa = memblock_alloc_top(page_map_span, kPageSize); - - if (!page_map_pa) { - kernel_panic("vmm_init: memblock failed to allocate page_map"); - } - - kprintf("[vmm] vmemmap: %llu pages, %llu KB at PA 0x%llx\n", num_pages, - page_map_span / 1024, page_map_pa); - - /* Map page_map at vmemmap_base from KaslrLayout (randomised by KASLR), using 2MB pages where possible */ - map_range_at_huge(root, arch::kaslr_layout_get().vmemmap_base, page_map_pa, - page_map_pa + page_map_span, pmap::PTE_R | pmap::PTE_W); - - /* Export for pmm_init() */ - g_vmemmap_page_map_pa = page_map_pa; - g_vmemmap_page_map_size = page_map_bytes; - g_vmemmap_num_pages = num_pages; - - /* 8. Pre-map console MMIO before page table switch */ - g_kernel_pgtbl = root; - console_init(); - - /* 9. Activate the new page table */ - pmap::activate(root); - - /* Console MMIO access must now use runtime (KASLR) direct-map base. */ - console_use_runtime_mapping(); - - kprintf("[vmm] vmm_init complete (vmemmap at 0x%llx)\n", arch::kaslr_layout_get().vmemmap_base); -} - -void vmm_init_ap() { - 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); - tlb_shootdown_all(); -} |
