summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-05-13 15:56:08 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-05-13 15:56:08 +0800
commitd6b81de2a1377858929c79f6be84108b023b5b00 (patch)
treefe6050fdaa5a615e56210c2e750190a24f050494
parent70fa5d207fecf4db0eef58f2b6120bdd0b0f3e96 (diff)
downloadlume-d6b81de2a1377858929c79f6be84108b023b5b00.tar.gz
lume-d6b81de2a1377858929c79f6be84108b023b5b00.tar.xz
feat: update Virtual Memory Manager to use page-based allocation and introduce VmFaultCause enum
-rw-r--r--na/include/lume/vmm.h30
-rw-r--r--na/mm/vmm.cc54
2 files changed, 49 insertions, 35 deletions
diff --git a/na/include/lume/vmm.h b/na/include/lume/vmm.h
index ec26d6a..85988e4 100644
--- a/na/include/lume/vmm.h
+++ b/na/include/lume/vmm.h
@@ -26,6 +26,12 @@ inline constexpr uint64 VM_WRITE = (1ULL << 1);
inline constexpr uint64 VM_EXEC = (1ULL << 2);
inline constexpr uint64 VM_USER = (1ULL << 3);
+enum class VmFaultCause : uint8 {
+ Read = 0,
+ Write = 1,
+ Exec = 2,
+};
+
/* Forward declarations */
struct VmSpace;
struct VmAreaStruct;
@@ -48,13 +54,16 @@ struct VmAreaStruct {
*
* Lock contract:
* Holds: lock (internal spinlock)
- * May acquire: PMM global lock (via pmm_alloc_frame inside page fault)
+ * May acquire: PMM global lock (via pmm_alloc_page inside page fault)
* Callers must NOT hold: PMM lock (lock ordering: VmSpace -> PMM)
*/
struct VmSpace {
uint64 root_pa; // SV39 root page table physical address
struct rb_root vma_tree; // Red-black tree of VmAreaStructs
Spinlock lock; // Protects vma_tree mutations
+
+ uint64 brk_start; // Start of heap (page-aligned)
+ uint64 brk_end; // Current heap end (page-aligned)
// Create a brand new VmSpace (allocates root pagetable)
static VmSpace* create();
@@ -72,18 +81,23 @@ void vmm_init_ap();
/* Map MMIO device region to the active kernel page table */
void vmm_map_kernel_mmio(uint64 pa, uint64 size);
-/* Query frame_map allocation (set by vmm_init, read by pmm_init).
- * Returns the PA, byte size, and frame count of the vmemmap region. */
-uint64 vmm_get_frame_map_pa();
-uint64 vmm_get_frame_map_size();
-uint64 vmm_get_num_frames();
+/* Query page_map allocation (set by vmm_init, read by pmm_init).
+ * Returns the PA, byte size, and page count of the vmemmap region. */
+uint64 vmm_get_page_map_pa();
+uint64 vmm_get_page_map_size();
+uint64 vmm_get_num_pages();
/* User space memory management (VMA & Demand Paging) */
int vmm_map_user(VmSpace* space, uint64 va, uint64 len, uint64 perm);
int vmm_unmap_user(VmSpace* space, uint64 va, uint64 len);
+int vmm_protect_user(VmSpace* space, uint64 va, uint64 len, uint64 perm);
+
+/* VMA helpers for mmap/mprotect implementations */
+uint64 mm_find_free_va(VmSpace* space, uint64 length, uint64 align);
+bool vma_range_covered(VmSpace* space, uint64 start, uint64 end);
-/* Handle user page fault (lookup VMA -> allocate frame -> map) */
-int vmm_handle_page_fault(VmSpace* space, uint64 fault_addr, uint64 cause);
+/* Handle user page fault (lookup VMA -> allocate page -> map) */
+int vmm_handle_page_fault(VmSpace* space, uint64 fault_addr, VmFaultCause cause);
/* Clone an address space for fork() */
VmSpace* vmm_clone(VmSpace* parent_space);
diff --git a/na/mm/vmm.cc b/na/mm/vmm.cc
index c1436d1..0aa2fb0 100644
--- a/na/mm/vmm.cc
+++ b/na/mm/vmm.cc
@@ -8,9 +8,9 @@
* the early_pgdir identity mapping from entry.S.
*
* With memblock integration, the initialization order is:
- * memblock_init → vmm_init (allocates frame_map from memblock,
+ * memblock_init → vmm_init (allocates page_map from memblock,
* maps vmemmap, activates page table) → pmm_init (buddy system
- * starts with frame_map already at vmemmap VA — no relocation).
+ * starts with page_map already at vmemmap VA — no relocation).
*
* Reference: docs/specs/vmm.md
*/
@@ -21,7 +21,7 @@
#include <lume/addr.h>
#include <lume/console.h>
#include <lume/fdt.h>
-#include <lume/frame.h>
+#include <lume/page.h>
#include <lume/klog.h>
#include <lume/kprintf.h>
#include <lume/memblock.h>
@@ -39,14 +39,14 @@ extern "C" char _kernel_end[];
/* Global kernel page table root PA */
static uint64 g_kernel_pgtbl = 0;
-/* VMM exports for PMM: frame_map location after vmemmap mapping. */
-static uint64 g_vmemmap_frame_map_pa = 0;
-static uint64 g_vmemmap_frame_map_size = 0;
-static uint64 g_vmemmap_num_frames = 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;
-uint64 vmm_get_frame_map_pa() { return g_vmemmap_frame_map_pa; }
-uint64 vmm_get_frame_map_size() { return g_vmemmap_frame_map_size; }
-uint64 vmm_get_num_frames() { return g_vmemmap_num_frames; }
+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; }
/* Convert a linker symbol to PA (kernel is executing in higher-half VA). */
static inline uint64 sym_to_pa(const void *sym) {
@@ -149,32 +149,32 @@ void vmm_init() {
map_range(root, after_kernel, mem_end, pmap::PTE_R | pmap::PTE_W);
}
- /* 7. Allocate frame_map from memblock (top of RAM) and map at VMEMMAP.
+ /* 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. frame_map starts
+ * allocates page table pages from memblock too. page_map starts
* life at the vmemmap VA — no relocation ever needed.
*/
- uint64 num_frames = mem_size / kPageSize;
- uint64 frame_map_bytes = num_frames * sizeof(Frame);
- uint64 frame_map_span = page_align_up(frame_map_bytes);
- uint64 frame_map_pa = memblock_alloc_top(frame_map_span, kPageSize);
+ 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 (!frame_map_pa) {
- kernel_panic("vmm_init: memblock failed to allocate frame_map");
+ if (!page_map_pa) {
+ kernel_panic("vmm_init: memblock failed to allocate page_map");
}
- kprintf("[vmm] vmemmap: %llu frames, %llu KB at PA 0x%llx\n", num_frames,
- frame_map_span / 1024, frame_map_pa);
+ kprintf("[vmm] vmemmap: %llu pages, %llu KB at PA 0x%llx\n", num_pages,
+ page_map_span / 1024, page_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);
+ /* 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_frame_map_pa = frame_map_pa;
- g_vmemmap_frame_map_size = frame_map_bytes;
- g_vmemmap_num_frames = num_frames;
+ 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;
@@ -186,7 +186,7 @@ void vmm_init() {
/* 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);
+ kprintf("[vmm] vmm_init complete (vmemmap at 0x%llx)\n", arch::kaslr_layout_get().vmemmap_base);
}
void vmm_init_ap() {