summaryrefslogtreecommitdiff
path: root/docs/specs/vmm.md
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-04-21 23:07:23 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-04-21 23:07:23 +0800
commite9a3dac62746f175f92ace4cc461de2924ea92f8 (patch)
tree9348a2fbbe6d61e7373f74c927f1b55faed3c2c9 /docs/specs/vmm.md
parentb0ccdda4bc3af04e54677cd910ed04c5ba1b1a63 (diff)
downloadlume-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.md158
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
+```