summaryrefslogtreecommitdiff
path: root/na/mm
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-05-03 01:47:15 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-05-03 01:47:15 +0800
commit2b237b24c4db5513f8046e15d24501257e7feeaa (patch)
tree7b5fcbe3e00d30056064801594b899eb3db5c88b /na/mm
parent4b1b9912caf41fa52818e5d84130016ce00888cc (diff)
downloadlume-2b237b24c4db5513f8046e15d24501257e7feeaa.tar.gz
lume-2b237b24c4db5513f8046e15d24501257e7feeaa.tar.xz
feat: implement KASLR support and runtime address mapping for RISC-V architecture
Co-authored-by: Copilot <copilot@github.com>
Diffstat (limited to 'na/mm')
-rw-r--r--na/mm/pmm.cc32
-rw-r--r--na/mm/vmm.cc40
2 files changed, 54 insertions, 18 deletions
diff --git a/na/mm/pmm.cc b/na/mm/pmm.cc
index 1400448..633bd2f 100644
--- a/na/mm/pmm.cc
+++ b/na/mm/pmm.cc
@@ -7,11 +7,9 @@
* Buddy allocator with Per-CPU single-page caches (PCP).
*
* Initialization sequence (called by BSP in single-core period):
- * 1. Query FDT for physical memory base and size.
- * 2. Carve out space for the frame_map array at the start of free memory
- * (immediately after _kernel_end, page-aligned).
- * 3. Initialize all Frame descriptors as Free.
- * 4. Feed free frames into the buddy system at the highest possible order.
+ * 1. memblock + vmm_init allocate and map the frame_map at VMEMMAP.
+ * 2. Zero and mark all Frame descriptors reserved by default.
+ * 3. Carve free regions from memblock into the buddy system.
*
* The frame_map is a flat array indexed by physical page frame number (PFN).
* PFN = (pa - mem_base) / PAGE_SIZE. This keeps address conversion O(1).
@@ -68,17 +66,26 @@ uint32 g_pcp_batch_size = 0;
* PFN = (pa - g_mem_base) / kPageSize
*/
static inline uint64 pa_to_frame_index(uint64 pa) {
+ if (pa < g_mem_base || pa >= g_mem_base + g_num_frames * kPageSize)
+ kernel_panic("pa_to_frame: physical address outside managed range");
return (pa - g_mem_base) / kPageSize;
}
static inline uint64 frame_index_to_pa(uint64 idx) {
+ if (idx >= g_num_frames)
+ kernel_panic("frame_to_pa: frame index outside managed range");
return g_mem_base + idx * kPageSize;
}
PhysAddr frame_to_pa(const Frame *frame) {
- uint64 idx = static_cast<uint64>(frame - g_frame_map);
- if (frame < g_frame_map || idx >= g_num_frames)
+ uintptr base = reinterpret_cast<uintptr>(g_frame_map);
+ uintptr addr = reinterpret_cast<uintptr>(frame);
+ uintptr end = base + g_num_frames * sizeof(Frame);
+
+ if (addr < base || addr >= end)
kernel_panic("frame_to_pa: frame outside frame_map bounds");
+
+ uint64 idx = (addr - base) / sizeof(Frame);
return phys_addr(frame_index_to_pa(idx));
}
@@ -391,11 +398,20 @@ void pmm_init() {
* No relocation needed — frame_map starts life at the right VA. */
g_frame_map_pa = vmm_get_frame_map_pa();
g_frame_map_bytes = vmm_get_frame_map_size();
- g_frame_map = reinterpret_cast<Frame *>(arch::kVmemmapBase);
+ g_frame_map = reinterpret_cast<Frame *>(arch::g_vmemmap_base);
/* 4. Zero out the entire frame_map */
zero_range(g_frame_map, g_frame_map_bytes);
+ /* 4b. Default every frame descriptor to reserved/non-free. */
+ for (uint64 i = 0; i < g_num_frames; i++) {
+ Frame *f = &g_frame_map[i];
+ f->refcount.store(0, __ATOMIC_RELAXED);
+ f->state = FrameState::Allocated;
+ f->order = 0;
+ f->free.free_link.init();
+ }
+
/* 5. Initialize buddy free list heads */
g_pmm_lock.init("pmm");
for (int i = 0; i < kMaxOrder; i++) {
diff --git a/na/mm/vmm.cc b/na/mm/vmm.cc
index 041413d..c1436d1 100644
--- a/na/mm/vmm.cc
+++ b/na/mm/vmm.cc
@@ -50,7 +50,7 @@ uint64 vmm_get_num_frames() { return g_vmemmap_num_frames; }
/* Convert a linker symbol to PA (kernel is executing in higher-half VA). */
static inline uint64 sym_to_pa(const void *sym) {
- return va_to_pa(virt_addr(reinterpret_cast<uint64>(sym))).raw;
+ 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. */
@@ -65,6 +65,18 @@ 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,
+ 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. */
static void map_range_at_huge(uint64 root, uint64 va_base, uint64 pa_start,
uint64 pa_end, uint64 perm) {
@@ -117,14 +129,19 @@ void vmm_init() {
uint64 mem_size = memblock_get_mem_size();
uint64 mem_end = mem_base + mem_size;
- /* 3. Map kernel .text (RX) */
- map_range(root, text_start, text_end, pmap::PTE_R | pmap::PTE_X);
+ /* 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) */
- map_range(root, ro_start, ro_end, pmap::PTE_R);
+ /* 4. Map .rodata (R) at fixed linked VA */
+ map_range_linked(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);
+ /* 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));
@@ -150,8 +167,8 @@ void vmm_init() {
kprintf("[vmm] vmemmap: %llu frames, %llu KB at PA 0x%llx\n", num_frames,
frame_map_span / 1024, frame_map_pa);
- /* Map frame_map at kVmemmapBase, using 2MB pages where possible */
- map_range_at_huge(root, arch::kVmemmapBase, frame_map_pa,
+ /* Map frame_map at g_vmemmap_base (randomised by KASLR), using 2MB pages where possible */
+ map_range_at_huge(root, arch::g_vmemmap_base, frame_map_pa,
frame_map_pa + frame_map_span, pmap::PTE_R | pmap::PTE_W);
/* Export for pmm_init() */
@@ -166,7 +183,10 @@ void vmm_init() {
/* 9. Activate the new page table */
pmap::activate(root);
- kprintf("[vmm] vmm_init complete (vmemmap at 0x%llx)\n", arch::kVmemmapBase);
+ /* 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::g_vmemmap_base);
}
void vmm_init_ap() {