diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-04-21 23:07:23 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-04-21 23:07:23 +0800 |
| commit | e9a3dac62746f175f92ace4cc461de2924ea92f8 (patch) | |
| tree | 9348a2fbbe6d61e7373f74c927f1b55faed3c2c9 /docs/specs/vmm.md | |
| parent | b0ccdda4bc3af04e54677cd910ed04c5ba1b1a63 (diff) | |
| download | lume-e9a3dac62746f175f92ace4cc461de2924ea92f8.tar.gz lume-e9a3dac62746f175f92ace4cc461de2924ea92f8.tar.xz | |
docs: add specifications for C++ Kernel Runtime, Flattened Device Tree, Physical Memory Manager, SLUB Allocator, and Virtual Memory Manager
- Introduced `cpp_runtime.md` detailing the C++ ABI stubs required for LumeOS kernel, including panic mechanisms and error paths.
- Added `fdt.md` to outline the device tree management for hardware discovery and configuration, including data structures and public APIs.
- Created `pmm.md` to specify the physical memory management system based on the buddy system, including frame allocation and concurrency handling.
- Developed `slab.md` to describe the SLUB allocator for efficient memory allocation, detailing its structure and public APIs.
- Established `vmm.md` to define the virtual memory manager's objectives, dependencies, and core data structures for managing virtual address space.
Diffstat (limited to 'docs/specs/vmm.md')
| -rw-r--r-- | docs/specs/vmm.md | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/docs/specs/vmm.md b/docs/specs/vmm.md new file mode 100644 index 0000000..7492a02 --- /dev/null +++ b/docs/specs/vmm.md @@ -0,0 +1,158 @@ +# 虚拟内存管理器 (Virtual Memory Manager) + +## 1. 目标 (Objective) + +为 LumeOS 管理虚拟地址空间。本模块分两个阶段实现: + +- **Phase 1(本文档重点):** + 1. 在 `vmm_init()` 中建立精细化的内核页表(4KB 粒度、精确权限)。 + 2. 实现基于 Rbtree 和 Slab 的 VMA (Virtual Memory Area) 区间树以管理用户态内存。 + 3. 实现架构无关的按需分页 (Demand Paging) 模拟接口。 +- **Phase 2(未来):** 将 VMM 的按需分页逻辑绑定到真实的 Trap 异常中断系统,并引入进程 (Process/Task) 关联和基于硬件触发的缺页异常处理。 + +采用 pmap(Physical Map)分层模型:MI 层管理地址空间布局逻辑,MD 层(`arch/riscv/mm/pmap.cc`)封装 SV39 页表硬件操作。 + +## 2. 前置依赖 (Dependencies) + +- **全局初始化契约 (`global_init.md`):** `vmm_init()` 在 `slab_init()` 和 `fdt_unflatten()` 之后、`trap_init()` 之前被 BSP 调用。 +- **物理内存契约 (`pmm.md`):** 依赖 `pmm_alloc_frame()` 分配页表页。 +- **Slab 分配器契约 (`slab.md`):** Phase 2 依赖 `kmalloc` 创建 VMA 对象。 +- **架构抽象契约 (`arch_abstraction.md`):** 依赖 `arch::mmu::set_page_table()`, `arch::mmu::flush_tlb_all()` 切换和刷新页表。 +- **链接脚本契约 (`linker_and_entry.md`):** 依赖 `_stext/_etext`, `_srodata/_erodata`, `_sdata/_edata`, `_sbss/_ebss`, `_kernel_end` 确定各段边界。 + +## 3. 核心数据结构 (Data Structures) + +### 3.1 SV39 页表项 (PTE) 格式 + +``` +63 54 53 28 27 19 18 10 9 8 7 6 5 4 3 2 1 0 ++---------+----------+----------+----------+----+-+-+-+-+-+-+-+-+ +| Reserved| PPN[2] | PPN[1] | PPN[0] |RSW |D|A|G|U|X|W|R|V| +| (10) | (26) | (9) | (9) |(2) |1|1|1|1|1|1|1|1| ++---------+----------+----------+----------+----+-+-+-+-+-+-+-+-+ +``` + +权限位常量: + +```cpp +namespace pmap { + inline constexpr uint64 PTE_V = 1 << 0; // Valid + inline constexpr uint64 PTE_R = 1 << 1; // Read + inline constexpr uint64 PTE_W = 1 << 2; // Write + inline constexpr uint64 PTE_X = 1 << 3; // Execute + inline constexpr uint64 PTE_U = 1 << 4; // User-accessible + inline constexpr uint64 PTE_G = 1 << 5; // Global + inline constexpr uint64 PTE_A = 1 << 6; // Accessed + inline constexpr uint64 PTE_D = 1 << 7; // Dirty +} +``` + +### 3.2 pmap 接口 (MD 层, namespace 函数) + +遵循 `00_conventions.md` 的多态策略——pmap 为极热路径,使用 namespace 函数 + 编译期链接。 + +```cpp +// 定义于 arch/riscv/mm/pmap.h (arch 私有头) 和 mm/pmap.h (MI 接口) +namespace pmap { + // 分配并初始化一个新的根页表,返回其物理地址。 + // 失败返回 0。 + uint64 create(); + + // 销毁一个页表及其所有子页表页。 + void destroy(uint64 root_pa); + + // 建立映射:va -> pa,权限为 perm。 + // 自动分配中间页表页。 + // 返回 0 成功,负错误码失败。 + int map(uint64 root_pa, uint64 va, uint64 pa, uint64 perm); + + // 解除 va 处的映射。 + void unmap(uint64 root_pa, uint64 va); + + // 查询 va 对应的 pa。成功返回 true 并写入 *pa_out。 + bool lookup(uint64 root_pa, uint64 va, uint64* pa_out); + + // 将 root_pa 写入 satp 并刷新 TLB。 + void activate(uint64 root_pa); +} +``` + +### 3.3 内核地址空间布局 + +`vmm_init()` 建立的精细内核映射: + +``` +Virtual Address Physical Address Perm Description +───────────────────────────────────────────────────────────────────── +arch::kVAOffset + 0x80200000 0x80200000 R-X .text (代码段) +arch::kVAOffset + _srodata _srodata_pa R-- .rodata (只读数据) +arch::kVAOffset + _sdata _sdata_pa RW- .data + .bss +arch::kVAOffset + frame_map_pa frame_map_pa RW- PMM frame_map 数组 +arch::kVAOffset + 0x10000000 0x10000000 RW- UART MMIO +arch::kVAOffset + 0x0C000000 0x0C000000 RW- PLIC MMIO +arch::kVAOffset + mem_end ... RW- 剩余物理内存 (到 mem_end) +``` + +## 4. 公共 API (Public APIs) + +### 4.1 Phase 1 API + +```cpp +// 初始化内核页表,替代 early_pgdir。 +// 1. 分配新根页表 +// 2. 按段权限映射内核各段 +// 3. 映射 MMIO 区域 +// 4. 激活新页表 +// 5. 旧的 early_pgdir 恒等映射自动失效 +void vmm_init(); + +// AP 切换到 BSP 建好的内核页表 +void vmm_init_ap(); +``` + +### 4.2 Phase 2 API (未来) + +```cpp +// 暂为 stub,Phase 2 实现 +int vmm_map_user(uint64 root_pa, uint64 va, uint64 len, uint64 perm); +int vmm_unmap_user(uint64 root_pa, uint64 va, uint64 len); +int vmm_handle_page_fault(uint64 root_pa, uint64 fault_addr, uint64 cause); +uint64 vmm_clone(uint64 parent_root_pa); +``` + +## 5. 并发与锁契约 (Concurrency & Locks) + +- **Phase 1:** `vmm_init()` 在 BSP 单核期执行,无需锁。 +- **pmap 锁:** 每个根页表关联一把 Spinlock(Phase 2 在 AddressSpace 结构中)。多核操作同一页表必须持有此锁。 +- **TLB Shootdown:** Phase 1 仅有内核页表且在单核期建立,无需 shootdown。Phase 2 需实现。 + +## 6. 错误路径 (Error Paths) + +- `pmap::create()` 或 `pmap::map()` 中 `pmm_alloc_frame()` 失败 → `kernel_panic()`(内核页表映射失败不可恢复)。 +- `vmm_init()` 中任何映射步骤失败 → `kernel_panic()`。 + +## 7. 状态机 / 时序图 (State Machine / Sequence) + +### 7.1 vmm_init 时序 + +``` +[kernel_main on BSP, after slab_init + fdt_unflatten] + │ + ├─> 1. root_pa = pmap::create() // 分配新根页表 + │ + ├─> 2. 映射内核 .text 段 (RX) + │ for (pa = _stext_pa; pa < _etext_pa; pa += PAGE_SIZE) + │ pmap::map(root_pa, pa + arch::kVAOffset, pa, PTE_R|PTE_X|PTE_G) + │ + ├─> 3. 映射 .rodata 段 (R-) + ├─> 4. 映射 .data + .bss 段 (RW) + ├─> 5. 映射 frame_map 区域 (RW) + ├─> 6. 映射剩余物理内存 (RW) + ├─> 7. 映射 MMIO: UART 0x10000000, PLIC 0x0C000000 (RW) + │ + ├─> 8. pmap::activate(root_pa) // 写 satp, sfence.vma + │ └─ 此刻 early_pgdir 的恒等映射失效 + │ └─ 代码继续执行(因为高半区映射已建立) + │ + └─> 9. 保存 root_pa 到全局变量 g_kernel_pgtbl +``` |
