summaryrefslogtreecommitdiff
path: root/docs/specs/pmm.md
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-10-16 02:39:56 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-10-16 02:39:56 +0800
commit8cace3f05003c6cb4d38c36890055f03151c2ad4 (patch)
treeaa739deaac0266f17c4e91b333957501cb1ea2e9 /docs/specs/pmm.md
parent3ad39e9878310e5317ee73c9b353c1e2c1c5c4ee (diff)
downloadlume-8cace3f05003c6cb4d38c36890055f03151c2ad4.tar.gz
lume-8cace3f05003c6cb4d38c36890055f03151c2ad4.tar.xz
Remove old code
Signed-off-by: Richard Qin <richard.qin.x@gmail.com>
Diffstat (limited to 'docs/specs/pmm.md')
-rw-r--r--docs/specs/pmm.md209
1 files changed, 0 insertions, 209 deletions
diff --git a/docs/specs/pmm.md b/docs/specs/pmm.md
deleted file mode 100644
index 5703e7a..0000000
--- a/docs/specs/pmm.md
+++ /dev/null
@@ -1,209 +0,0 @@
-# 物理内存管理器 (Physical Memory Manager)
-
-## 1. 目标 (Objective)
-
-为 LumeOS 提供对物理内存页帧(Frame)的分配与回收服务。本模块基于伙伴系统(Buddy System)算法管理所有可用物理内存,并引入 Per-CPU 缓存(PCP)机制以降低多核场景下的锁竞争。PMM 是 Slab 分配器和 VMM 的底层基石。
-
-## 2. 前置依赖 (Dependencies)
-
-- **全局初始化契约 (`global_init.md`):** `pmm_init()` 在 `fdt_init()` 之后、`slab_init()` 之前被 BSP 调用。
-- **设备树契约 (`fdt.md`):** 依赖 `fdt_early_get_mem_info()` 获取物理内存的基址和大小。
-- **并发同步契约 (`spinlock.md`):** 依赖 `Spinlock` 实现对全局伙伴系统的互斥访问。
-- **架构抽象契约 (`arch_abstraction.md`):** 依赖 `arch::cpu::id()` 获取当前 CPU 编号以访问 Per-CPU 缓存;依赖 `arch::cpu::intr_off()/intr_on()` 保护 PCP 操作免受中断重入。
-- **项目约定 (`00_conventions.md`):** 遵循所有命名、错误处理和 API 设计规范。
-
-## 3. 核心数据结构 (Data Structures)
-
-### 3.1 物理页帧描述符 (`struct Frame`)
-
-为了极致地压缩元数据内存占用,`struct Frame` 采用 `union` 设计,并严格保证 `refcount` 独立于 `union` 之外,以支持 COW。
-
-```cpp
-// 定义于 include/lume/frame.h
-#include <lume/types.h>
-#include <lume/list.h>
-
-class KmemCache; // 前向声明
-
-enum class FrameState : uint8 {
- Free, // 空闲,位于 Buddy 或 PCP 链表中
- Allocated, // 已分配给上层(Slab, VMM)
- Slab, // 作为 Slab 页使用
-};
-
-struct Frame {
- uint32 refcount; // 原子引用计数(独立于 union)
- FrameState state; // 页帧当前状态
- uint8 order; // 伙伴系统中的阶数 (0-10 for 4KB-4MB)
-
- union {
- // 当 state == FrameState::Free 时
- struct {
- list_node free_link; // 用于挂载到 Buddy 或 PCP 的空闲链表
- } free;
-
- // 当 state == FrameState::Slab 时
- struct {
- KmemCache* cache; // 指向所属的 Slab 缓存
- uint32 obj_count; // 已分配对象数量
- } slab;
- };
-};
-```
-
-### 3.2 Per-CPU 单页缓存 (`struct PerCpuCache`)
-
-每个 CPU 私有的单页帧空闲链表。**访问 PCP 时必须关闭中断**,防止定时器中断处理函数在同一 CPU 上重入 PCP 操作导致链表损坏。
-
-```cpp
-// 定义于 mm/pmm.cc (模块私有)
-inline constexpr int kPcpHighWatermark = 64; // PCP 缓存上限
-inline constexpr int kPcpBatchSize = 32; // 每次 refill/drain 的批量大小
-
-struct PerCpuCache {
- list_node free_list; // 单页帧空闲链表头
- uint32 count; // 当前缓存的页帧数量
-};
-```
-
-### 3.3 伙伴系统常量
-
-```cpp
-// 定义于 include/lume/pmm.h
-inline constexpr int kMaxOrder = 11; // 阶数 0..10 → 4KB..4MB
-```
-
-## 4. 公共 API (Public APIs)
-
-所有分配函数在失败时返回 `nullptr`。
-
-```cpp
-// === 初始化 ===
-void pmm_init(); // BSP 调用,从 FDT 发现内存并初始化伙伴系统
-
-// === 单页帧操作 (Fast Path via PCP) ===
-Frame* pmm_alloc_frame(); // 分配一个 4KB 页帧
-void pmm_free_frame(Frame* f); // 释放一个 4KB 页帧
-
-// === 多页帧操作 (Slow Path, 直接伙伴系统) ===
-Frame* pmm_alloc_frames(uint8 order); // 分配 2^order 个连续页帧
-void pmm_free_frames(Frame* f, uint8 order); // 释放 2^order 个连续页帧
-
-// === 引用计数操作 (原子, 无锁) ===
-void frame_incref(Frame* f); // 原子递增引用计数
-void frame_decref(Frame* f); // 原子递减,降至 0 时自动释放
-
-// === 地址转换 ===
-uint64 frame_to_pa(const Frame* f); // Frame* → 物理地址
-Frame* pa_to_frame(uint64 pa); // 物理地址 → Frame*
-uint64 frame_to_va(const Frame* f); // Frame* → 内核虚拟地址
-```
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-- **持有锁:** 模块内部持有一把 `Spinlock` (`g_pmm_lock`)。
-
-- **锁的作用域:** `g_pmm_lock` **仅保护**全局伙伴系统 (`g_free_areas[]`)。
-
-- **PCP 保护机制:** PCP 操作**必须在中断关闭状态下**执行。这不是"无锁"——而是通过关中断防止同一 CPU 上的重入(定时器中断 → IRQ handler → pmm_alloc_frame → 损坏 PCP 链表)。关中断由 `pmm_alloc_frame()`/`pmm_free_frame()` 内部自动管理。
-
-- **加锁慢速路径:**
- - 当 PCP 为空时,`refill_pcp()` 获取 `g_pmm_lock` 从伙伴系统批量取页。
- - 当 PCP 达到 `kPcpHighWatermark` 时,`drain_pcp()` 获取 `g_pmm_lock` 归还半数页帧。
- - `pmm_alloc_frames()` 和 `pmm_free_frames()` 因直接操作伙伴系统,**始终需要**获取 `g_pmm_lock`。
-
-- **原子操作:** `frame_incref()` / `frame_decref()` 使用 `__atomic_fetch_add/sub` + `__ATOMIC_ACQ_REL`。
-
-## 6. 错误路径 (Error Paths)
-
-- **初始化失败:** `pmm_init()` 若无法从 FDT 找到可用内存,或无法为 `frame_map` 分配空间,则 `kernel_panic()`。
-
-- **分配失败:** `pmm_alloc_*()` 在物理内存耗尽时返回 `nullptr`。上层负责处理。
-
-- **释放错误:** `pmm_free_*()` 若接收到 `nullptr`,立即 `kernel_panic()`。
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-### 7.1 单页分配时序 (Fast & Slow Path)
-
-```
-[pmm_alloc_frame() on CPU X]
- │
- ├─> 1. 关闭中断 (防止同 CPU 重入)
- │
- ├─> 2. 获取 pcp = &g_pcp[cpu_id]
- │
- ├─> 3. if (pcp->count > 0) ?
- │ ├── [是 (Fast Path)]
- │ │ ├─ 3.1 从 pcp->free_list 弹出一个 Frame
- │ │ ├─ 3.2 设置 state=Allocated, refcount=1
- │ │ └─ 3.3 恢复中断, return Frame
- │ │
- │ └── [否 (Slow Path)]
- │ ├─ 4.1 LockGuard guard(g_pmm_lock);
- │ ├─ 4.2 refill_pcp(pcp); // 批量从 Buddy 取 kPcpBatchSize 页
- │ ├─ 4.3 释放锁
- │ └─ 4.4 回到步骤 3 重试
- │
- ▼
-[恢复中断, 返回 Frame* 或 nullptr]
-```
-
-### 7.2 初始化时序
-
-```
-[pmm_init() — BSP 单核期]
- │
- ├─> 1. fdt_early_get_mem_info(&base, &size)
- │ └─ 获取物理内存基址和大小
- │
- ├─> 2. 计算 frame_map 位置 (紧跟 _kernel_end 之后, 页对齐)
- │ └─ frame_map 大小 = num_frames * sizeof(Frame)
- │
- ├─> 3. 清零 frame_map
- │
- ├─> 4. 初始化 Spinlock 和 Buddy 空闲链表头
- │
- ├─> 5. 初始化所有 PCP 链表头
- │
- └─> 6. 将所有空闲页帧 (frame_map 之后) 按最大对齐阶数插入 Buddy
-```
-
-### 7.3 写时复制 (COW) 引用计数流程
-
-```
-[父进程 fork() 创建子进程]
- │
- ├─> 1. 遍历父进程所有可写 VMA
- │
- ├─> 2. for each VMA:
- │ ├─ 2.1 复制父进程的 PTE 到子进程页表
- │ ├─ 2.2 清除父、子 PTE 的 'Write' 权限位
- │ ├─ 2.3 设置父、子 PTE 的 'COW' 软件标志位
- │ └─ 2.4 frame_incref(pa_to_frame(PTE->paddr));
- │
- ▼
-[子进程尝试写入共享页面]
- │
- ├─> 1. 触发 Store Page Fault
- │
- ├─> 2. VMM 陷阱处理:
- │ ├─ 2.1 检查 PTE,确认是合法的 COW Fault
- │ ├─ 2.2 old_frame = pa_to_frame(PTE->paddr)
- │ ├─ 2.3 if (old_frame->refcount == 1) ?
- │ │ ├── [是] 直接恢复 Write 权限,无需拷贝
- │ │ └── [否] 分配新页, 拷贝, 修改 PTE, frame_decref(old)
- │
- ▼
-[返回用户态,写操作成功]
-```
-
-## 8. 已知缺陷与未来挑战 (Known Weaknesses & Future Challenges)
-
-### 8.1 内存回收
-
-当前 API 在物理内存耗尽时仅返回 `nullptr`,缺乏主动回收机制。未来需引入内存回收器。
-
-### 8.2 frame_map 存储
-
-当前设计假设单一连续 `frame_map` 数组,适用于 QEMU 线性内存。对于多内存区域的真实硬件,需演进为稀疏内存模型。