summaryrefslogtreecommitdiff
path: root/docs/specs
diff options
context:
space:
mode:
Diffstat (limited to 'docs/specs')
-rw-r--r--docs/specs/00_conventions.md368
-rw-r--r--docs/specs/arch_abstraction.md223
-rw-r--r--docs/specs/atomics.md80
-rw-r--r--docs/specs/cpp_runtime.md55
-rw-r--r--docs/specs/fdt.md191
-rw-r--r--docs/specs/global_init.md208
-rw-r--r--docs/specs/linker_and_entry.md208
-rw-r--r--docs/specs/pmm.md209
-rw-r--r--docs/specs/slab.md233
-rw-r--r--docs/specs/spinlock.md204
-rw-r--r--docs/specs/testing_and_ci.md83
-rw-r--r--docs/specs/vmm.md158
12 files changed, 0 insertions, 2220 deletions
diff --git a/docs/specs/00_conventions.md b/docs/specs/00_conventions.md
deleted file mode 100644
index 47da6f1..0000000
--- a/docs/specs/00_conventions.md
+++ /dev/null
@@ -1,368 +0,0 @@
-# LumeOS 0 号规范 (Project Conventions)
-
-本文档是 LumeOS 全项目的出厂规范。所有后续 spec 文档和代码必须遵守此规范。
-
----
-
-## 1. 架构总览
-
-### 1.1 分层模型
-
-```
-┌─────────────────────────────────────────────────────────┐
-│ User Programs │
-│ (Busybox, init, shell) │
-├────────────────────── syscall ABI ──────────────────────┤
-│ kernel/syscall │ kernel/proc │ kernel/sched │
-│ (系统调用分发) │ (任务管理) │ (调度器) │
-├───────────────────┼────────────────┼────────────────────┤
-│ fs/ │ mm/ │ kernel/trap │
-│ (VFS + 具体 FS) │ (PMM/Slab/VMM)│ (MI 异常分发) │
-├───────────────────┴────────────────┴────────────────────┤
-│ drivers/ │
-│ (VirtIO, UART, BlockDevice 实现) │
-├─────────────────────────────────────────────────────────┤
-│ arch/$(ARCH)/ │
-│ (CSR, 上下文切换, pmap, TLB, 中断向量, uaccess) │
-├─────────────────────────────────────────────────────────┤
-│ boot/ + linker.ld │
-│ (entry.S, 多核同步, 高半区跳转) │
-└─────────────────────────────────────────────────────────┘
-```
-
-**核心规则:** 依赖方向严格向下。上层模块可以调用下层接口,反之禁止。
-`kernel/`、`fs/`、`mm/` 严禁出现内联汇编或架构特定寄存器操作。
-
-### 1.2 多态策略
-
-| 层级 | 多态方式 | 理由 |
-|------|---------|------|
-| CPU 核心层 (arch primitives) | Namespace 函数 + 编译期链接 | 零运行时开销,极热路径 |
-| 设备抽象层 (BlockDevice 等) | C++ 纯虚类 | 运行时多态,驱动可替换 |
-| 跨平台页表 (pmap) | Namespace 函数 + 编译期链接 | 极热路径,每次 page fault |
-
-### 1.3 目录结构
-
-```
-lumeOS/
-├── include/ # 公共头文件(跨模块可见)
-│ ├── lume/ # 内核公共接口命名空间
-│ │ ├── types.h # 基础类型 (uint64, size_t, ssize_t, ...)
-│ │ ├── errno.h # 全局错误码 (-EINVAL, -ENOMEM, ...)
-│ │ └── config.h # 编译期配置 (PAGE_SIZE, NCPU, ...)
-│ └── uapi/ # 用户态/内核态共享 (syscall 编号, ioctl)
-│
-├── arch/riscv/ # 架构相关(MD 层)
-│ ├── include/arch/ # arch 私有头文件
-│ ├── boot/ # entry.S, trampoline.S
-│ ├── mm/ # pmap 实现 (页表操作)
-│ ├── trap/ # 中断向量, 上下文保存/恢复
-│ └── uaccess.cc # copy_from_user / exception table
-│
-├── mm/ # 内存管理(MI 层)
-│ ├── pmm.cc / pmm.h # 物理页分配 (Buddy)
-│ ├── slab.cc / slab.h # 字节级分配器
-│ └── vmm.cc / vmm.h # VMA 管理, demand paging
-│
-├── kernel/ # 内核核心(MI 层)
-│ ├── main.cc # kernel_main 初始化序列
-│ ├── trap/ # MI 异常分发
-│ ├── proc/ # TCB, 生命周期, clone/exec/exit
-│ ├── sched/ # 调度器
-│ ├── sync/ # Spinlock, Mutex, WaitQueue
-│ └── syscall/ # syscall 跳转表与处理函数
-│
-├── fs/ # 文件系统
-│ ├── vfs.cc / vfs.h # VFS 抽象层, MountTable
-│ ├── file.cc / file.h # File 基类与 FileTable
-│ └── fat32/ # FatFs 胶水层
-│
-├── drivers/ # 设备驱动
-│ ├── uart/ # 串口
-│ ├── virtio/ # VirtIO Block/Net
-│ └── tty/ # TTY + Line Discipline
-│
-├── lib/ # 内核通用库
-│ ├── kprintf.cc # 内核格式化输出
-│ ├── string.cc # memcpy, memset, strlen, ...
-│ └── rbtree.cc # 红黑树
-│
-├── docs/specs/ # 模块 Spec 文档
-├── linker.ld # 链接脚本
-└── Makefile # 构建系统
-```
-
-**头文件规则:**
-- 跨模块可见的接口 → `include/lume/` 或 `include/uapi/`
-- 模块私有头文件 → 与 `.cc` 同目录(如 `mm/pmm.h`)
-- `#pragma once` 替代 include guard
-
----
-
-## 2. 统一术语表 (Ubiquitous Language)
-
-以下术语在代码和文档中必须严格一致,不得混用同义词。
-
-| 概念 | 术语 | 禁止混用 |
-|------|------|---------|
-| 物理处理器核心 | `CPU` | ~~Hart, core, processor~~ (RISC-V 文档中 Hart 仅在 arch/ 层内部使用) |
-| 逻辑调度单元 | `Task` | ~~Process, Thread~~ (对用户态呈现时可说"进程/线程",内核代码统一用 Task) |
-| 任务控制块 | `TaskControlBlock` / `TCB` | ~~Proc, PCB~~ |
-| 物理内存页帧 | `Frame` | ~~physical page~~ |
-| 虚拟页 | `Page` | 仅在虚拟地址语境使用 |
-| 虚拟地址区域 | `VMA` (Virtual Memory Area) | ~~vm_area, segment~~ |
-| 页表操作层 | `pmap` | ~~pagetable, mmu~~ |
-| 内核地址空间 | `kernel space` | ~~supervisor space~~ (代码中 S-mode 指特权级,不指地址空间) |
-| 中断请求号 | `irq` | ~~interrupt number~~ |
-| 文件描述符编号 | `fd` | ~~fileno, handle~~ |
-| 系统调用编号 | `sysno` | ~~syscall_nr, scall~~ |
-
----
-
-## 3. 全局错误处理范式
-
-**选定方案:Linux 负错误码(方案 A)。全局死守,不得例外。**
-
-### 3.1 函数返回值约定
-
-```cpp
-// 返回 int 的函数:
-// 成功 → 0 或正数(如 read 返回字节数)
-// 失败 → 负的错误码(-EINVAL, -ENOMEM, -EFAULT, ...)
-int vfs_read(File *f, char *buf, size_t n);
-
-// 返回指针的函数(仅当失败原因唯一时允许):
-// 成功 → 有效指针
-// 失败 → nullptr
-// 适用场景:失败原因显而易见且唯一(如"内存不足")
-Frame *pmm_alloc_frame();
-
-// 返回指针但失败原因可能有多种时 → 禁止返回裸指针。
-// 必须改为返回 int 错误码 + 出参:
-int task_alloc(TaskControlBlock **out); // 成功: *out = 有效指针, 返回 0
- // 失败: *out 不变, 返回 -ENOMEM / -EINVAL
-```
-
-### 3.2 错误码定义
-
-所有错误码定义在 `include/lume/errno.h`,编号严格对齐 Linux `asm-generic/errno-base.h`:
-
-```cpp
-#define EPERM 1 // Operation not permitted
-#define ENOENT 2 // No such file or directory
-#define ENOMEM 12 // Out of memory
-#define EFAULT 14 // Bad address
-#define EINVAL 22 // Invalid argument
-// ...
-```
-
-### 3.3 禁止事项
-
-- **禁止** 使用布尔值表示可能有多种失败原因的操作
-- **禁止** 使用魔数(如 `-1`)代替命名错误码
-- **禁止** 忽略被调用函数的返回值(必须检查或显式 `(void)` 标记)
-
----
-
-## 4. C++ 命名与格式规范
-
-### 4.1 命名约定
-
-| 元素 | 风格 | 示例 |
-|------|------|------|
-| 类 / 结构体 | `PascalCase` | `TaskControlBlock`, `Spinlock` |
-| 函数 / 方法 | `snake_case` | `pmm_alloc_frame()`, `task.get_pid()` |
-| 局部变量 | `snake_case` | `page_count`, `vma_entry` |
-| 私有成员变量 | `snake_case` + `_` 后缀 | `lock_`, `state_`, `parent_` |
-| 全局变量 | `g_` 前缀 | `g_pmm`, `g_sched` |
-| 编译期常量 | `k` 前缀 + `PascalCase` | `kPageSize`, `kMaxHarts` |
-| 宏 / 枚举值 | `UPPER_SNAKE` | `PAGE_SIZE`, `RUNNABLE` |
-| 命名空间 | `snake_case` | `namespace arch`, `namespace pmap` |
-| 抽象接口类 | 直接命名,无前缀 | `BlockDevice`(不用 `IBlockDevice`) |
-
-### 4.2 文件命名
-
-- 源文件:`snake_case.cc`(C++)、`snake_case.S`(汇编)
-- 头文件:`snake_case.h`
-- 一个 `.h` + 一个 `.cc` 组成一个模块单元,文件名一致
-
-### 4.3 格式(交给工具)
-
-- 缩进、花括号、列宽等由 `.clang-format` 统一管控
-- 代码提交前必须通过 `clang-format` 格式化
-
-### 4.4 C++ 使用边界
-
-| 特性 | 允许 | 禁止 |
-|------|------|------|
-| 类 / 继承 / 虚函数 | ✅ | |
-| 模板(简单泛型) | ✅ | |
-| RAII (LockGuard) | ✅ | |
-| Placement new | ✅ | |
-| 异常 (throw/catch) | | ❌ `-fno-exceptions` |
-| RTTI (dynamic_cast) | | ❌ `-fno-rtti` |
-| STL 容器 | | ❌ 依赖堆分配器 |
-| 全局构造函数(隐式) | | ❌ 使用 Placement New |
-
----
-
-## 5. 并发与锁约定
-
-### 5.1 锁声明要求
-
-每个持有锁的数据结构,必须在头文件注释中声明:
-```cpp
-// 锁契约:
-// 持有: pmm_lock_ (内部自旋锁)
-// 可能获取: 无
-// 调用方禁止持有: sched_lock (避免反向依赖)
-class PhysicalMemoryManager {
- Spinlock pmm_lock_;
- // ...
-};
-```
-
-### 5.2 全局锁序
-
-各 spec 文档必须声明"本模块持有哪些锁、需要获取哪些外部锁"。
-Phase 2 全部完成后,从各 spec 中提取汇总为 `docs/specs/lock_ordering.md` 全局 DAG。
-
-### 5.3 原子操作
-
-- 引用计数(`refcount`)使用 `__atomic_fetch_sub` / `__atomic_fetch_add` + `__ATOMIC_ACQ_REL`
-- **[强制]** 所有在多核间无锁共享的数据,必须使用 `lume::atomic<T>` 类型封装,并显式指定内存序。
-- Spinlock 的 acquire/release 内含隐式 fence,临界区内无需额外屏障
-- **禁止** 用裸 `volatile` 替代原子操作
-- **禁止** 在代码中直接使用 `__atomic_*` 内建函数,必须通过 `lume::atomic<T>` 包装器。
-
----
-
-## 6. Spec 文档标准模板
-
-后续每份 spec 文档必须包含以下章节:
-
-```markdown
-# 模块名称 (Module Name)
-
-## 1. 目标 (Objective)
-一句话描述本模块的职责边界。
-
-## 2. 前置依赖 (Dependencies)
-列出本模块依赖的其他模块及其接口。
-
-## 3. 核心数据结构 (Data Structures)
-结构体定义、内存布局、字段含义。
-
-## 4. 公共 API (Public APIs)
-函数签名、参数语义、返回值约定、错误码。
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-- 本模块持有的锁
-- 本模块可能获取的外部锁
-- 调用方的锁限制
-
-## 6. 错误路径 (Error Paths)
-每个 API 失败时的副作用(是否回滚已分配资源)。
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-(如适用)关键流程的状态转换或调用时序。
-```
-
----
-
-## 7. 构建系统架构
-
-### 7.1 工具链
-
-| 项目 | 选择 |
-|------|------|
-| 构建系统 | GNU Make (非递归模式) |
-| 编译器 | `riscv64-*-gcc` / `riscv64-*-g++` |
-| C++ 标准 | C++23 (`-std=c++23`) |
-| 关键编译选项 | `-ffreestanding -nostdlib -fno-exceptions -fno-rtti -mcmodel=medany` |
-| 代码格式化 | `clang-format`(`.clang-format` 配置) |
-| 静态分析 | `clang-tidy`(通过 `bear -- make` 生成 `compile_commands.json`) |
-| 调试 | QEMU + GDB (`make debug`) |
-| 许可证 | GPL-2.0-or-later |
-| 源文件头 | 必须包含 SPDX 标识符和版权声明 |
-
-### 7.2 构建模式:非递归 Make + 模块片段
-
-采用**单一顶层 Makefile + 各模块 `module.mk` 片段**的非递归模式,兼顾模块化与依赖正确性。
-
-**目录结构示例:**
-```
-lumeOS/
-├── Makefile # 顶层:定义规则、变量、include 所有 module.mk
-├── arch/riscv/module.mk # 声明 arch 层源文件
-├── mm/module.mk # 声明内存管理源文件
-├── kernel/module.mk # 声明内核核心源文件
-├── fs/module.mk # 声明文件系统源文件
-├── drivers/module.mk # 声明驱动源文件
-├── lib/module.mk # 声明通用库源文件
-└── build/ # 编译产出目录 (out-of-tree)
-```
-
-**模块片段 (`module.mk`) 格式:**
-```makefile
-# mm/module.mk
-# 每个模块只声明自己的源文件列表,追加到全局变量
-
-SRCS_CC += mm/pmm.cc mm/slab.cc mm/vmm.cc
-SRCS_CC += mm/cow.cc
-```
-
-**顶层 Makefile 骨架:**
-```makefile
-# === 变量定义 ===
-ARCH := riscv
-BUILD := build
-TARGET := $(BUILD)/kernel.elf
-
-# === 包含所有模块片段 ===
-SRCS_CC :=
-SRCS_S :=
-include arch/$(ARCH)/module.mk
-include mm/module.mk
-include kernel/module.mk
-include fs/module.mk
-include drivers/module.mk
-include lib/module.mk
-
-# === 统一规则 ===
-OBJS := $(patsubst %.cc,$(BUILD)/%.o,$(SRCS_CC)) \
- $(patsubst %.S,$(BUILD)/%.o,$(SRCS_S))
-
-$(TARGET): $(OBJS) linker.ld
- $(LD) -T linker.ld -o $@ $(OBJS)
-
-$(BUILD)/%.o: %.cc
- @mkdir -p $(dir $@)
- $(CXX) $(CXXFLAGS) -c $< -o $@
-
-$(BUILD)/%.o: %.S
- @mkdir -p $(dir $@)
- $(CC) $(CFLAGS) -c $< -o $@
-
-# 自动依赖追踪
--include $(OBJS:.o=.d)
-```
-
-### 7.3 构建规范
-
-- **Out-of-tree 编译:** 所有 `.o` 和 `.d` 文件输出到 `build/` 目录,不污染源码树
-- **自动依赖:** 编译时加 `-MMD -MP` 生成 `.d` 依赖文件,增量构建正确追踪头文件变更
-- **新增模块流程:** 创建目录 → 创建 `module.mk` 声明源文件 → 在顶层 Makefile 一行 `include` → 完成
-- **禁止递归 Make:** 不使用 `$(MAKE) -C subdir`,避免依赖追踪断裂
-
-### 7.4 标准 Make Target
-
-| Target | 含义 |
-|--------|------|
-| `make` / `make all` | 编译内核 ELF |
-| `make run` | QEMU 运行(无 GDB) |
-| `make debug` | QEMU 运行 + 等待 GDB 附加 |
-| `make clean` | 清理 `build/` 目录 |
-| `make fmt` | `clang-format -i` 格式化所有源文件 |
-| `make lint` | `clang-tidy` 静态分析 |
-| `make test` | QEMU 无头冒烟测试 (Phase 4) |
diff --git a/docs/specs/arch_abstraction.md b/docs/specs/arch_abstraction.md
deleted file mode 100644
index a90137c..0000000
--- a/docs/specs/arch_abstraction.md
+++ /dev/null
@@ -1,223 +0,0 @@
-# 架构抽象层 (Architecture Abstraction)
-
-## 1. 目标 (Objective)
-
-为 LumeOS 的平台无关层(MI)提供统一的底层硬件原语接口。本模块负责将 RISC-V 架构特有的控制状态寄存器 (CSR) 操作、汇编级上下文切换 (Context Switch)、陷阱帧 (TrapFrame) 布局、以及 TLB 刷新机制进行封装。**本项目所有内联汇编 (Inline Assembly) 严格限定于本模块内部,上层模块禁止直接操作硬件寄存器。**
-
-## 2. 前置依赖 (Dependencies)
-
-- **全局类型契约:** 依赖 `include/lume/types.h` 提供的 `uint64` 等标准类型。
-
-- **编译器支持:** 依赖 GCC/Clang 的内联汇编能力 (`__asm__ volatile`),必须确保不被过度优化(使用 `memory` clobber 建立编译器屏障)。
-
-- **启动序列契约:** `arch::cpu::id()` 依赖 `tp` 寄存器在 `entry.S` 中被正确初始化为当前 CPU 编号(参见 `linker_and_entry.md`)。在 `tp` 初始化之前,禁止调用本模块任何依赖 CPU ID 的函数。
-
-
-## 3. 核心数据结构 (Data Structures)
-
-### 3.1 上下文切换结构 (`struct Context`)
-
-用于调度器在不同内核流(如不同 Task 或 KThread)之间进行主动切换(Switch)。它只保存 Callee-Saved(被调用者保存)寄存器。
-
-```cpp
-// 定义于 arch/riscv/include/arch/context.h
-namespace arch {
- struct Context {
- uint64 ra; // Return Address (返回地址)
- uint64 sp; // Stack Pointer (栈指针)
- uint64 s[12]; // s0 ~ s11 (Callee-saved 寄存器)
- };
-}
-```
-
-### 3.2 陷阱帧结构 (`struct TrapFrame`)
-
-用于在发生中断、异常或系统调用时,由硬件与汇编入口 `trap_vector` 协同保存当前 CPU 的执行快照。此结构同时跨越用户态和内核态,必须精确布局。
-
-```cpp
-// 定义于 arch/riscv/include/arch/trapframe.h
-// 对齐由分配方保证(页对齐或栈对齐),struct 本身不施加 alignas
-namespace arch {
- struct TrapFrame {
- /* 内核元数据区 (偏移 0 - 39) */
- uint64 kernel_satp; // 0: 内核页表地址 (挂载至 satp)
- uint64 kernel_sp; // 8: 顶层内核栈地址
- uint64 kernel_trap; // 16: 内核 C++ trap_handler 的绝对地址
- uint64 kernel_cpu_id; // 24: 当前 CPU 编号 (trap 入口加载至 tp)
- uint64 epc; // 32: 中断/异常时的指令地址 (sepc)
-
- /* CSR 备份区 (偏移 40 - 47) */
- uint64 sstatus; // 40: 中断前的特权状态 (含 SPP, SPIE 位)
-
- /* 通用寄存器备份区 (偏移 48 - 295) */
- uint64 ra; // 48
- uint64 sp; // 56 (用户态的栈指针)
- uint64 gp; // 64
- uint64 tp; // 72
- uint64 t[7]; // 80: t0-t6 (Caller-saved 临时寄存器)
- uint64 s[12]; // 136: s0-s11 (Callee-saved 寄存器)
- uint64 a[8]; // 232: a0-a7 (函数参数/系统调用参数与返回值)
- };
- static_assert(sizeof(TrapFrame) == 296);
-}
-```
-
-**相比原版的关键修正:**
-- **新增 `sstatus` 字段:** 这是陷阱帧中最容易遗漏但最致命的字段。`sstatus` 包含 `SPP`(之前的特权级)和 `SPIE`(之前的中断使能状态)。若不保存/恢复 `sstatus`,`sret` 返回用户态时将无法正确恢复特权级和中断状态。
-- **将 `kernel_cpu_id` 移入元数据区:** 它不是通用寄存器的备份,而是内核注入的元数据(trap 入口用来设置 `tp`),不应放在"通用寄存器备份区"中。
-- **简化寄存器数组:** 将 `t0_t2[3]` + `t3_t6[4]` 合并为 `t[7]`,将 `s0_s1[2]` + `s2_s11[10]` 合并为 `s[12]`。编译器按偏移访问不受影响,且减少了心智负担。
-
-
-## 4. 公共 API (Public APIs)
-
-所有接口统一在 `arch` 及其子命名空间下,通过静态内联函数或汇编实现,实现**零运行时代价**。这些操作不会引发常规意义的"错误"(如不会返回 `-ENOMEM`),因此不采用错误码范式。
-
-### 4.1 CPU 控制与状态感知 (`namespace arch::cpu`)
-
-```cpp
-namespace arch::cpu {
- // 获取当前 CPU 编号 (从 tp 寄存器中读取)
- // 前置条件:tp 必须已在 entry.S 中初始化
- uint64 id();
-
- // 开启中断 (设置 sstatus.SIE = 1)
- void intr_on();
-
- // 关闭中断 (设置 sstatus.SIE = 0)
- void intr_off();
-
- // 获取当前中断状态 (返回 true 表示中断已开启)
- bool intr_enabled();
-
- // 使 CPU 进入低功耗睡眠,直到下一个中断到来 (wfi 指令)
- void halt_until_interrupt();
-
- // 读取硬件单调时钟计数 (rdtime 指令)
- // 返回自系统启动以来的 tick 数(频率由 FDT timebase-frequency 决定)
- uint64 read_time();
-}
-```
-
-### 4.2 内存管理硬件原语 (`namespace arch::mmu`)
-
-```cpp
-namespace arch::mmu {
- // 读取缺页异常发生时的虚拟地址 (从 stval 寄存器读取)
- uint64 get_fault_address();
-
- // 切换顶级页表
- // 参数:physical_pgdir_addr 为页表的物理地址(非 PPN),
- // 函数内部负责右移 12 位并组装 SV39 模式字段写入 satp
- void set_page_table(uint64 physical_pgdir_addr);
-
- // 读取当前页表物理地址 (从 satp 提取 PPN 并左移还原为物理地址)
- uint64 get_page_table();
-
- // 刷新整个 TLB (sfence.vma zero, zero)
- void flush_tlb_all();
-
- // 刷新特定虚拟地址的 TLB 条目 (sfence.vma vaddr, zero)
- void flush_tlb_page(uint64 vaddr);
-}
-```
-
-### 4.3 陷阱向量控制 (`namespace arch::trap`)
-
-```cpp
-namespace arch::trap {
- // 设置 S-mode 陷阱向量基址 (写入 stvec 寄存器)
- // 参数:handler_addr 为汇编 trap_vector 入口的虚拟地址
- // 模式:Direct(所有异常/中断统一入口)
- void set_vector(uint64 handler_addr);
-
- // 读取当前陷阱原因 (scause 寄存器)
- uint64 get_cause();
-
- // 读取陷阱附加信息 (stval 寄存器)
- uint64 get_value();
-}
-```
-
-### 4.4 上下文切换原语
-
-```cpp
-namespace arch {
- // 汇编实现的上下文切换函数。定义于 arch/riscv/swtch.S
- // 语义:将当前 CPU 寄存器保存到 old_ctx,并将 next_ctx 的内容恢复到 CPU
- // 本函数由 C++ 调用,汇编实现,绝对不会失败。
- extern "C" void context_switch(Context* old_ctx, Context* next_ctx);
-}
-```
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-本模块属于内核的绝对最底层,位于 `Spinlock` 模块的下方,因此**不感知、不持有、也不获取任何高级锁。**
-
-- **调用方契约(中断开关):** 上层模块(如 `Spinlock`)需直接依赖 `arch::cpu::intr_off()` 与 `intr_on()` 来防止单核死锁。
-
-- **内存屏障契约(Memory Barriers):** `flush_tlb_all` 与 `flush_tlb_page` 的底层 `sfence.vma` 指令本身即为硬件级内存屏障。内联汇编实现中仍须添加编译器屏障(`"memory"` clobber),防止编译器跨越 TLB 刷新点重排内存访问。
-
-- **跨核(SMP)同步警告:** 当前 `flush_tlb_page` 仅执行**本地** `sfence.vma`。在实现基于 IPI (核间中断) 的 TLB Shootdown 前,VMM 须确保同一时间只有一个 CPU 在修改共享的页表映射。未来将在本命名空间中增加 `flush_tlb_page_remote()` 接口。
-
-
-## 6. 错误路径 (Error Paths)
-
-底层指令级操作无传统错误返回。
-
-- `flush_tlb_page` 对任何地址执行 `sfence.vma` 都不会触发异常(仅使对应 TLB 表项失效)。
-
-- `context_switch` 若传入无效指针(如 nullptr),加载/存储操作将触发 Store/Load Page Fault,由 Phase 2 的 `trap.md` 规定的异常分发层兜底并触发 `Panic`。
-
-- `set_page_table` 传入非法物理地址将导致后续的所有内存访问引发 Page Fault。此类错误属于编程逻辑错误,无法在本层恢复。
-
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-### 7.1 上下文切换时序 (`context_switch`)
-
-调度器在选择出新的 `Task` 后,调用此接口的时序如下:
-
-```
-[当前 Task A] (执行 sched() 决定放弃 CPU)
- │
- ▼
-[调用 arch::context_switch(&TaskA->context, &TaskB->context)]
- │
- ├─> 1. 保存 ra, sp, s0-s11 到 TaskA->context 内存区块中
- ├─> 2. 从 TaskB->context 内存区块中加载 ra, sp, s0-s11 到物理寄存器
- └─> 3. ret (返回到被加载的 ra 地址)
- │
- ▼
-[恢复至 Task B] (PC 从 Task B 上次挂起的 sched() 处继续执行)
-```
-
-### 7.2 陷阱帧保存/恢复时序 (trap_vector)
-
-```
-[用户态正在运行]
- │
- ├─ 中断/异常/ecall 触发
- ▼
-[trap_vector (汇编入口, arch/riscv/trap/trap_vector.S)]
- │
- ├─> 1. 交换 sscratch <-> tp (sscratch 预存 TrapFrame 地址)
- ├─> 2. 将 31 个通用寄存器写入 TrapFrame
- ├─> 3. csrr sstatus → TrapFrame.sstatus (保存特权状态)
- ├─> 4. csrr sepc → TrapFrame.epc (保存中断 PC)
- ├─> 5. 加载 kernel_sp, kernel_satp, kernel_cpu_id 到 sp, satp, tp
- ├─> 6. sfence.vma (切换到内核页表后刷新 TLB)
- └─> 7. jalr TrapFrame.kernel_trap (跳转至 C++ trap_handler)
- │
- ▼
-[MI 层 trap_handler()] → 分发至 syscall / page fault / IRQ 处理
- │
- ▼
-[usertrapret: 恢复用户态]
- │
- ├─> 1. 写回 TrapFrame.epc → sepc
- ├─> 2. 写回 TrapFrame.sstatus → sstatus
- ├─> 3. 切换回用户页表 (satp)
- ├─> 4. 从 TrapFrame 恢复 31 个通用寄存器
- ├─> 5. 交换 sscratch <-> tp (恢复 TrapFrame 地址到 sscratch)
- └─> 6. sret (返回用户态)
-``` \ No newline at end of file
diff --git a/docs/specs/atomics.md b/docs/specs/atomics.md
deleted file mode 100644
index 841f287..0000000
--- a/docs/specs/atomics.md
+++ /dev/null
@@ -1,80 +0,0 @@
-# 原子操作与内存序 (Atomics & Memory Ordering)
-
-## 1. 目标 (Objective)
-
-为 LumeOS 在 RISC-V 弱内存模型 (RVWMO) 环境下提供一套安全、可控的原子操作库。本模块旨在通过封装 C++ `std::atomic` 风格的接口,强制开发者在进行无锁编程时显式考虑内存序 (Memory Ordering),以避免因指令重排导致的、难以复现的并发 Bug。
-
-## 2. 前置依赖 (Dependencies)
-
-- **编译器支持:** 依赖 GCC/Clang 的 `__atomic_*` 内建函数。
-
-## 3. 核心设计:`lume::atomic<T>`
-
-### 3.1 问题背景:弱内存模型 (RVWMO)
-
-RISC-V 采用弱内存模型,允许 CPU 和编译器进行激进的指令重排。在无锁数据结构(如 Per-CPU 缓存的无锁链表)中,如果仅使用简单的原子操作而没有指定正确的内存序,可能发生以下灾难:
-
-- **场景:** CPU A 分配一个新节点 `node`,填充其数据 `node->data = val`,然后通过原子交换将其链接到链表头 `head.exchange(node)`。
-- **风险:** CPU B 可能先观测到 `head` 指针的更新,但由于指令重排,`node->data` 的写入尚未对 CPU B 可见,导致 CPU B 读取到未初始化的垃圾数据。
-
-`Spinlock` 内部的 `fence` 无法保护这种无锁路径。
-
-### 3.2 解决方案:封装 `std::atomic` 风格接口
-
-LumeOS 将提供 `lume::atomic<T>` 模板类,禁止直接使用 `__atomic_*` 内建函数。
-
-1. **定义 `memory_order` 枚举:**
- ```cpp
- // in include/lume/atomic.h
- namespace lume {
- enum memory_order {
- relaxed = __ATOMIC_RELAXED,
- consume = __ATOMIC_CONSUME,
- acquire = __ATOMIC_ACQUIRE,
- release = __ATOMIC_RELEASE,
- acq_rel = __ATOMIC_ACQ_REL,
- seq_cst = __ATOMIC_SEQ_CST
- };
- }
- ```
-
-2. **创建 `lume::atomic<T>` 模板类:**
- ```cpp
- // in include/lume/atomic.h
- namespace lume {
- template <typename T>
- struct atomic {
- T value;
-
- T load(memory_order order = seq_cst) const {
- return __atomic_load_n(&value, order);
- }
-
- void store(T desired, memory_order order = seq_cst) {
- __atomic_store_n(&value, desired, order);
- }
-
- T fetch_add(T arg, memory_order order = seq_cst) {
- return __atomic_fetch_add(&value, arg, order);
- }
- // ... 其他 fetch_*, exchange, compare_exchange_strong 等方法
- };
- }
- ```
-
-3. **强制使用规范:**
- 在 `00_conventions.md` 中明确规定:所有在多核间无锁共享的数据(如 `Frame::refcount`,PCP 链表头指针),其类型**必须**是 `lume::atomic<T>`,严禁使用原生类型或 `volatile`。
-
- **示例 (PMM):**
- ```cpp
- // in mm/frame.h
- #include <lume/atomic.h>
- struct Frame {
- lume::atomic<uint32_t> refcount;
- // ...
- };
- ```
-
-## 4. 公共 API
-
-`lume::atomic<T>` 的 API 设计将严格对齐 C++ 标准库的 `std::atomic<T>`,降低学习成本。 \ No newline at end of file
diff --git a/docs/specs/cpp_runtime.md b/docs/specs/cpp_runtime.md
deleted file mode 100644
index e3ebd90..0000000
--- a/docs/specs/cpp_runtime.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# C++ 内核运行时 (C++ Kernel Runtime)
-
-## 1. 目标 (Objective)
-
-为 LumeOS 内核提供最小化的 C++ ABI 存根函数。在 `-fno-exceptions -fno-rtti -nostdlib` 环境下,编译器和链接器仍会引用若干 C++ 运行时符号(如纯虚函数陷阱、全局析构注册、DSO handle)。本模块提供这些符号的内核实现,防止链接失败。
-
-**职责边界:**
-- `operator new/delete` 由 Slab 分配器模块 (`mm/slab.cc`) 提供,**不在本模块**。
-- Placement new 由 `include/lume/new.h` 提供,**不在本模块**。
-- 本模块仅提供 ABI 存根和编译器辅助符号。
-
-## 2. 前置依赖 (Dependencies)
-
-- **Panic 机制 (`lib/panic.cc`):** 依赖 `kernel_panic()` 在遇到不可恢复错误时终止系统。
-- **项目约定 (`00_conventions.md`):** 遵循 `-fno-exceptions -fno-rtti` 编译约束。
-
-## 3. 核心数据结构 (Data Structures)
-
-无。本模块仅实现全局函数和符号。
-
-## 4. 公共 API (Public APIs)
-
-这些符号由编译器/链接器隐式引用,内核代码不应直接调用。
-
-```cpp
-// 定义于 lib/cxx_abi.cc
-
-// 当代码通过基类指针调用未实现的纯虚函数时,
-// 编译器生成的 vtable 条目会引用此符号。
-// 这是不可恢复的编程错误。
-extern "C" void __cxa_pure_virtual();
-
-// 全局对象析构注册。内核不支持全局对象析构(全局对象
-// 通过 Placement New 手动管理生命周期)。若编译器生成
-// 对此符号的调用,说明代码中存在违规的全局对象。
-extern "C" int __cxa_atexit(void (*func)(void*), void* arg, void* dso_handle);
-
-// DSO handle — 链接器在某些情况下引用此符号
-// (与 __cxa_atexit 配合标识动态共享对象)。
-// 内核为静态链接,此符号仅需存在即可。
-extern "C" void* __dso_handle;
-```
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-无。所有函数要么立即 panic,要么是静态符号。
-
-## 6. 错误路径 (Error Paths)
-
-- `__cxa_pure_virtual()` → 立即 `kernel_panic("pure virtual function call")`。
-- `__cxa_atexit()` → 立即 `kernel_panic("__cxa_atexit called in kernel")`。
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-无复杂时序。所有路径均为:检测到违规 → panic。
diff --git a/docs/specs/fdt.md b/docs/specs/fdt.md
deleted file mode 100644
index 2a1d542..0000000
--- a/docs/specs/fdt.md
+++ /dev/null
@@ -1,191 +0,0 @@
-# 设备树 (Flattened Device Tree)
-
-## 1. 目标 (Objective)
-
-为 LumeOS 提供一套标准的硬件发现与配置机制,彻底摆脱硬编码的物理地址。本模块负责解析由 Bootloader 传入的 FDT 二进制数据,并分两个阶段将其转化为内核可用的数据结构:
-
-1. **早期扫描 (Early Scan):** 在内存管理(PMM)初始化之前,以只读、无分配的方式扫描 FDT,提取启动所必需的核心信息(如物理内存布局)。
-2. **对象化展开 (Unflattening):** 在内存管理(PMM/Slab)就绪后,将完整的 FDT 解析为一个常驻内存的 C++ `DeviceNode` 对象树,为后续的驱动探测(Driver Probing)提供面向对象的接口。
-
-## 2. 前置依赖 (Dependencies)
-
-- **引导协议契约 (`linker_and_entry.md`):** 依赖 Bootloader 在跳转至内核时,将 FDT 的物理基址置于 `a1` 寄存器。
-- **全局初始化契约 (`global_init.md`):** `fdt_init()` 在 `console_init()` 之后、`pmm_init()` 之前被 BSP 调用。`pmm_init()` 自身会回调 FDT 的早期扫描接口。
-- **内存管理契约 (`pmm.md`, `slab.md`):** 对象化展开阶段依赖 Slab 分配器(`operator new`)来动态创建 `DeviceNode` 对象。
-- **项目约定 (`00_conventions.md`):** 遵循所有命名、错误处理和 API 设计规范。
-
-## 3. 核心数据结构 (Data Structures)
-
-### 3.1 FDT 属性 (`struct FdtProperty`)
-
-表示设备节点中的一个属性(如 `reg`, `compatible`)。
-
-```cpp
-// 定义于 include/lume/fdt_prop.h
-struct FdtProperty {
- const char* name; // 属性名
- const void* value; // 指向 FDT blob 中原始数据的指针
- int len; // 数据长度(字节)
- list_node link; // 链接到下一个属性
-};
-```
-
-### 3.2 设备节点 (`class DeviceNode`)
-
-FDT 对象树的核心,代表一个硬件设备或总线。
-
-```cpp
-// 定义于 include/lume/device_node.h
-class DeviceNode {
-public:
- // 构造/析构
- DeviceNode(DeviceNode* parent, const char* name);
- ~DeviceNode();
-
- // 属性访问
- const FdtProperty* get_prop(const char* name) const;
- uint32_t get_prop_u32(const char* name, uint32_t default_val = 0) const;
- uint64 get_prop_u64(const char* name, uint64 default_val = 0) const;
- const char* get_prop_string(const char* name) const;
-
- // 子节点遍历
- DeviceNode* find_child(const char* name);
- void for_each_child(void (*callback)(DeviceNode*));
-
- // 内部接口,供 FdtManager 构建树时使用
- void add_child(DeviceNode* child);
- void add_prop(FdtProperty* prop);
-
-private:
- const char* name_;
- DeviceNode* parent_;
- list_node children_list_; // list_head of children
- list_node props_list_; // list_head of properties
- list_node sibling_link_; // link in parent's children_list_
-};
-```
-
-### 3.3 FDT 管理器 (`class FdtManager`)
-
-全局单例,负责 FDT 的解析与查询。
-
-```cpp
-// 定义于 include/lume/fdt.h
-class FdtManager {
-public:
- // 由 fdt_init() 通过 Placement New 调用
- FdtManager(uint64 fdt_paddr);
-
- // 阶段二:对象化展开
- void unflatten();
-
- // 驱动探测接口
- DeviceNode* find_compatible(const char* compat_string);
- DeviceNode* get_node_by_path(const char* path);
-
- // 阶段一:早期扫描接口 (静态,无状态)
- static void early_scan_mem(uint64 fdt_paddr, uint64* base, uint64* size);
- static void early_scan_uart(uint64 fdt_paddr, uint64* uart_addr);
-
-private:
- uint64 fdt_paddr_;
- DeviceNode* root_ = nullptr;
- bool is_unflattened_ = false;
-};
-
-// 全局 FDT 管理器实例指针
-extern FdtManager* g_fdt;
-```
-
-## 4. 公共 API (Public APIs)
-
-```cpp
-// === 初始化 API (由 kernel_main 调用) ===
-
-// 阶段一和阶段二的入口。仅保存 FDT 地址,真正的解析被推迟。
-void fdt_init(uint64 fdt_paddr);
-
-// 在 Slab 就绪后调用,执行对象化展开。
-void fdt_unflatten();
-
-
-// === 驱动探测 API (供各驱动 init 函数调用) ===
-
-// 根据 "compatible" 字符串查找第一个匹配的设备节点。
-// 返回值:成功则为 DeviceNode 指针,失败为 nullptr。
-DeviceNode* fdt_find_compatible(const char* compat_string);
-
-// 根据完整路径查找设备节点。
-DeviceNode* fdt_get_node_by_path(const char* path);
-
-
-// === 早期扫描 API (供 PMM 和早期控制台调用) ===
-
-// 扫描 FDT blob 获取 /memory 节点的 base 和 size。
-// 失败则 panic。
-void fdt_early_get_mem_info(uint64* base, uint64* size);
-
-// 扫描 FDT blob 获取 /chosen/stdout-path 对应的 UART 物理地址。
-void fdt_early_get_uart_info(uint64* uart_addr);
-```
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-- **无锁设计:** FDT 的所有初始化和解析操作(`fdt_init`, `fdt_unflatten`)均由 BSP 在多核启动前的**绝对单核期**完成。
-
-- **只读安全:** 一旦 `fdt_unflatten()` 完成,`DeviceNode` 对象树即被视为**全局只读**数据。任何 CPU 都可以随时无锁访问它进行驱动探测和属性查询。
-
-- **禁止修改:** 任何模块在初始化之后都**不得**修改 `DeviceNode` 树的内容。
-
-## 6. 错误路径 (Error Paths)
-
-- **FDT 损坏:** 在 `fdt_init()` 或 `fdt_unflatten()` 中,如果检测到 FDT 的 magic number 无效或结构损坏,必须立即调用 `kernel_panic()`。
-
-- **关键节点缺失:** `fdt_early_get_mem_info()` 如果找不到 `/memory` 节点,说明无法确定物理内存大小,属于致命错误,必须 `kernel_panic()`。
-
-- **内存分配失败:** `fdt_unflatten()` 在使用 `new` 创建 `DeviceNode` 时如果 Slab 返回 `nullptr`,说明内存耗尽,必须 `kernel_panic()`。
-
-- **查询失败:** `fdt_find_compatible()` 或 `fdt_get_node_by_path()` 在未找到匹配节点时,安全地返回 `nullptr`。调用方(驱动)负责处理此情况(通常意味着该硬件不存在,驱动不进行初始化)。
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-### FDT 二阶段解析时序
-
-```
-[entry.S] -> a1 = fdt_paddr
- │
- ▼
-[kernel_main on BSP]
- │
- ├─> 1. fdt_init(fdt_paddr)
- │ └─ g_fdt = new FdtManager(fdt_paddr); // Placement New
- │ (仅保存地址,不进行任何解析)
- │
- ├─> 2. pmm_init()
- │ └─ fdt_early_get_mem_info(&base, &size);
- │ └─ FdtManager::early_scan_mem(fdt_paddr, ...);
- │ ├─ 遍历原始 FDT blob (无内存分配)
- │ ├─ 找到 /memory 节点
- │ └─ 返回 reg 属性值
- │
- ├─> 3. slab_init()
- │ └─ operator new 可用
- │
- ├─> 4. (稍后) fdt_unflatten()
- │ └─ g_fdt->unflatten();
- │ ├─ 再次遍历原始 FDT blob
- │ ├─ for each node: new DeviceNode(...)
- │ ├─ for each prop: new FdtProperty(...)
- │ └─ 构建完整的 C++ 对象树
- │
- ▼
-[驱动初始化阶段, e.g., plic_init()]
- │
- ├─> node = fdt_find_compatible("riscv,plic0");
- │ └─ g_fdt->find_compatible(...);
- │ └─ 遍历已构建的 DeviceNode C++ 对象树 (只读, 无锁)
- │
- ├─> reg_prop = node->get_prop("reg");
- │
- └─> (使用 reg_prop->value 初始化 PLIC 驱动)
-``` \ No newline at end of file
diff --git a/docs/specs/global_init.md b/docs/specs/global_init.md
deleted file mode 100644
index cd14dae..0000000
--- a/docs/specs/global_init.md
+++ /dev/null
@@ -1,208 +0,0 @@
-# 全局初始化序列 (Global Initialization)
-
-## 1. 目标 (Objective)
-
-统筹 LumeOS 从汇编跃迁至 C++ 后的全局初始化流程。定义子系统间的严格启动顺序、全局对象的生命周期管理范式、以及 BSP/AP 的两阶段同步协议。
-
-## 2. 前置依赖 (Dependencies)
-
-- **汇编环境契约:** 依赖 `linker_and_entry.md` 保证的执行环境:BSS 段已被清零、高半区虚拟内存(`early_pgdir`)已映射、`tp` 寄存器已保存当前 CPU ID、`gp` 寄存器已就绪。注意:`early_cpp_init()` 已在 `entry.S` 中由 BSP 调用完毕(在 `kernel_main` 之前),不在本模块的管辖范围内。
-
-- **全局基础契约:** 依赖 `00_conventions.md` 中禁用了 C++ 异常与 RTTI 的环境。
-
-- **并发同步契约:** 依赖 `spinlock.md` 提供的 `Spinlock`(但在 BSP 独占期不使用)。
-
-
-## 3. 核心数据结构与生命周期范式 (Data Structures & Lifecycle)
-
-在内核早期,物理内存管理 (PMM) 和字节级分配器 (Slab) 尚未就绪,传统的 `new` 和隐式的全局构造函数极易引发缺页崩溃或顺序未定义行为。
-
-### 3.1 显式生命周期模型 (Placement New 范式)
-
-对于所有复杂的内核全局单例(如 `PhysicalMemoryManager`, `Scheduler`),**严禁**直接定义为全局变量依赖 `.init_array` 隐式构造。必须采用以下静态缓冲区分配 + 显式 Placement New 的范式:
-
-```cpp
-// 示例:kernel/mm/pmm_global.cc
-
-// Placement new 声明(freestanding 环境无 <new> 头文件,自行提供)
-// 定义于 include/lume/new.h
-inline void* operator new(size_t, void* ptr) noexcept { return ptr; }
-inline void operator delete(void*, void*) noexcept {}
-
-// 1. 在 .bss 段静态分配对齐的内存区块,不触发任何构造函数
-alignas(PhysicalMemoryManager) uint8 g_pmm_buf[sizeof(PhysicalMemoryManager)];
-
-// 2. 暴露全局指针供外部访问
-PhysicalMemoryManager* g_pmm = nullptr;
-
-// 3. 在 kernel_main 的严格时序中被显式调用
-void pmm_init(uint64 fdt_paddr) {
- // 使用 Placement New 在预分配的内存上执行构造函数
- g_pmm = new (g_pmm_buf) PhysicalMemoryManager(fdt_paddr);
-}
-```
-
-**关于 `<new>` 头文件:** 在 `-ffreestanding -nostdlib` 编译环境下,`<new>` 可能不可用或行为不一致。LumeOS 在 `include/lume/new.h` 中自行提供 placement new 声明,不依赖任何标准库头文件。
-
-### 3.2 简单数据结构的按需初始化
-
-对于没有复杂依赖的 Plain Old Data (POD) 或简单锁对象:
-
-- `Spinlock` 等对象直接作为 BSS 段全局变量,由 `entry.S` 清零。随后在所属子系统的 `init()` 方法中调用 `lock.init("name")` 赋予身份。
-
-### 3.3 `.init_array` 的使用边界
-
-`early_cpp_init()` 在 `entry.S` 中遍历 `.init_array`。只有满足以下**全部**条件的全局构造函数才允许出现在此表中:
-
-- 构造函数不依赖任何子系统(PMM、Slab、VMM、Scheduler 均未初始化)。
-- 构造函数不分配动态内存。
-- 构造函数不获取任何锁。
-
-实际上,应该尽量让 `.init_array` 为空。绝大多数全局对象应走 §3.1 的 Placement New 路径。
-
-
-## 4. 公共 API (Public APIs)
-
-### 4.1 内核 C++ 唯一入口
-
-```cpp
-// 定义于 kernel/main.cc
-// 被 entry.S 中的 real_start 在开启 MMU、调用 early_cpp_init 后跳转
-// 所有 CPU 从此入口进入 C++ 世界
-// a0 = cpu_id, a1 = fdt_paddr
-extern "C" void kernel_main(uint64 cpu_id, uint64 fdt_paddr) __attribute__((noreturn));
-```
-
-### 4.2 子系统初始化签名规范
-
-所有子系统的初始化入口必须遵循统一签名,并在 `kernel/main.cc` 内部按图谱依次调用。每个 `xxx_init()` 函数成功时无返回值,失败时直接 `kernel_panic()`:
-
-```cpp
-void console_init(); // 1. UART 就绪,此后 kprintf/kernel_panic 可输出
-void fdt_init(uint64 fdt_paddr); // 2. 解析 FDT,构建设备节点表
-void pmm_init(); // 3. 从 FDT 获取内存布局,建立 Buddy 分配器
-void slab_init(); // 4. 建立 kmem_cache,此后 operator new 可用
-void vmm_init(); // 5. 建立精细化内核页表,废弃 early_pgdir
-void trap_init(); // 6. 设置 stvec,注册 IRQ 分发器
-void plic_init(); // 7. 配置 PLIC 中断控制器(阈值、优先级、使能位)
-void timer_init(); // 8. 配置定时器中断(调度器时钟源)
-void sched_init(); // 9. 构造 BSP 的 Idle Task 和初始就绪队列
-```
-
-### 4.3 AP 初始化签名
-
-AP 在 BSP 完成全局初始化后执行,仅限 Per-CPU 私有数据:
-
-```cpp
-void vmm_init_ap(); // 切换 satp 至 BSP 建好的内核页表
-void trap_init_ap(); // 设置本 CPU 的 stvec
-void plic_init_ap(); // 配置本 CPU 在 PLIC 上的 Context 使能
-void timer_init_ap(); // 启动本 CPU 的定时器中断
-void sched_init_ap(); // 初始化本 CPU 的 O(1) 就绪队列、创建 Idle Task
-```
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-这是整个内核生命周期中**唯一一段不受自旋锁约束的特殊时期**,必须严格遵循以下阶段隔离:
-
-### 5.1 两阶段同步协议
-
-LumeOS 启动过程中存在**两个独立的同步屏障**,不要混淆:
-
-| 同步点 | 位置 | 变量 | 含义 |
-|--------|------|------|------|
-| 第一道 | `entry.S` (汇编层) | `boot_sync_flag` | AP 等待 BSP 建立 `early_pgdir`,完成后所有 CPU 齐步进入虚拟地址空间 |
-| 第二道 | `kernel_main` (C++ 层) | `ap_boot_sync` | AP 等待 BSP 完成全部子系统初始化,完成后 AP 开始 Per-CPU 初始化 |
-
-### 5.2 绝对单核期 (BSP 独占)
-
-- 在 `kernel_main` 启动初期,AP 卡在第二道屏障 `ap_boot_sync` 处自旋。
-
-- BSP 拥有对全局数据结构的**绝对独占权**。在此期间调用 `pmm_init`、`vmm_init` 等函数时,**无需获取该子系统的 `Spinlock`**(也不应获取,因为锁可能尚未初始化)。
-
-### 5.3 多核唤醒与并发期 (AP 启动)
-
-- BSP 完成所有全局初始化后,通过 `__atomic_store_n(&ap_boot_sync, 1, __ATOMIC_RELEASE)` 唤醒 AP。`RELEASE` 语义保证 AP 读到 `ap_boot_sync == 1` 时,所有全局单例对象必然已构造完毕。
-
-- AP 进入后,**只能执行 Per-CPU 的局部初始化**(如设置自身的 `stvec`、初始化 PLIC Context、创建 Per-CPU Idle Task)。
-
-- 一旦 AP 的 Per-CPU 初始化完成并开启中断,所有子系统对全局数据的访问必须严格遵守 `spinlock.md` 契约。
-
-
-## 6. 错误路径 (Error Paths)
-
-初始化阶段的错误处理极度苛刻:
-
-- **console_init 之前的 Panic:** 此时 UART 尚未就绪,`kernel_panic()` 无法输出任何信息。唯一行为是关中断 + `wfi` 死循环(静默死亡)。可通过 JTAG/GDB 附加调试。
-
-- **console_init 之后的 Panic:** 可输出 Panic 消息和调用栈信息后死循环。
-
-- 任何子系统的 `init` 方法如果检测到硬件缺失(如 FDT 解析不到内存节点)或关键资源耗尽(Slab 无法建立早期缓存),必须**立即调用 `kernel_panic()`**。
-
-- 此阶段系统尚未具备任务调度与资源回收能力,无后路可退。
-
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-### 7.1 全局初始化依赖 DAG 图
-
-`kernel_main` 必须严格按照自顶向下的单向依赖顺序执行,任何逆序调用将导致 `kernel_panic` 或缺页崩溃。
-
-```
- entry.S (汇编世界)
- │
- early_cpp_init() ← 遍历 .init_array (应尽量为空)
- │
- ════════════════
- kernel_main()
- ════════════════
- │
- ┌─────────────┴──────────────┐
- │ │
- [BSP (cpu_id == 0)] [AP (cpu_id != 0)]
- │ │
- 1. console_init() 自旋等待
- └─ UART 就绪 ap_boot_sync == 1
- └─ 此后 Panic 可输出 │
- │ │
- 2. fdt_init(fdt_paddr) │
- └─ 解析 FDT 设备树 │
- │ │
- 3. pmm_init() │
- └─ Buddy 分配器就绪 │
- │ │
- 4. slab_init() │
- └─ operator new 可用 │
- │ │
- 5. vmm_init() │
- └─ 完整内核页表就绪 │
- └─ 废弃 early_pgdir 恒等映射 │
- │ │
- 6. trap_init() │
- └─ stvec 挂载 trap_vector │
- │ │
- 7. plic_init() │
- └─ PLIC 中断控制器就绪 │
- │ │
- 8. timer_init() │
- └─ 定时器中断就绪 │
- │ │
- 9. sched_init() │
- └─ Idle Task (Task 0) 创建 │
- └─ Per-CPU 就绪队列初始化 │
- │ │
- ──[RELEASE 屏障]──────────────────> 读到 1
- ap_boot_sync = 1 │
- │ 1. vmm_init_ap()
- │ 2. trap_init_ap()
- │ 3. plic_init_ap()
- │ 4. timer_init_ap()
- │ 5. sched_init_ap()
- │ │
- ▼ ▼
- arch::cpu::intr_on() arch::cpu::intr_on()
- BSP 变为 Idle Task AP 变为 Idle Task
- 进入调度循环 进入调度循环
-```
-
-**BSP 进入调度的方式:** BSP 在 `sched_init()` 中将自身的执行上下文注册为 CPU 0 的 Idle Task (Task 0)。开启中断后,第一个定时器中断触发调度器接管执行流。不是通过 `sched_yield()` 主动让出,而是被定时器中断被动抢占进入调度循环。 \ No newline at end of file
diff --git a/docs/specs/linker_and_entry.md b/docs/specs/linker_and_entry.md
deleted file mode 100644
index a59d28d..0000000
--- a/docs/specs/linker_and_entry.md
+++ /dev/null
@@ -1,208 +0,0 @@
-# 链接器与引导入口 (Linker & Entry)
-
-## 1. 目标 (Objective)
-
-定义 LumeOS 在 RISC-V 64 架构上的早期内存布局与汇编启动序列。负责兼容多种 Bootloader(OpenSBI、GRUB、U-Boot),建立高半区内核(Higher-Half Kernel)映射,初始化早期 C++ 运行环境(BSS、GP 寄存器、全局构造函数),并安全地将各个 CPU 同步导入虚拟地址空间的 `kernel_main`。
-
-## 2. 前置依赖 (Dependencies)
-
-- **引导协议契约 (Boot Protocol):** 为了同时支持 OpenSBI(直接跳转偏移 0)和 GRUB/U-Boot(解析元数据后引导),LumeOS 采用 **RISC-V Linux Boot Protocol**。内核文件起始处必须包含标准的 64 字节 Image Header。
-
-- **寄存器传参契约:** 无论哪种引导器,在跳转至内核执行的第一条指令时,必须保证 `a0` = 当前 CPU ID (Hart ID),`a1` = FDT (Device Tree) 的物理基址。
-
-- **编译模型契约:** 内核必须使用 `-mcmodel=medany` 编译,以支持基于 PC 的相对寻址,确保在 MMU 开启前后代码均能正确执行。
-
-- **硬件 MMU 契约:** 目标硬件必须支持 RISC-V SV39 分页模式。
-
-
-## 3. 核心数据结构与内存布局 (Data Structures & Memory Map)
-
-### 3.1 虚拟与物理地址基址
-
-- **物理加载基址 (Physical Base):** `0x80200000` (跳过低地址的 OpenSBI 固件区,对齐 2MB 以支持大页映射)。
-
-- **内核虚拟基址 (Virtual Base):** `0xFFFFFFC080200000` (SV39 地址空间顶部,硬编码偏移量 `PAGE_OFFSET = 0xFFFFFFC000000000`)。
-
-- **虚拟-物理偏移常量:** `KERNEL_VA_OFFSET = 0xFFFFFFC000000000`,用于虚拟/物理地址互转:`VA = PA + KERNEL_VA_OFFSET`,`PA = VA - KERNEL_VA_OFFSET`。
-
-
-### 3.2 链接脚本段分布 (`linker.ld`)
-
-必须在所有代码之前放置 `.head.text` 段,以确保 Image Header 绝对位于二进制文件的第 0 字节处。所有段强制 4KB 对齐:
-
-```
-+-----------------------+ 0xFFFFFFC080200000 (Virtual) / 0x80200000 (Physical)
-| .head.text (镜像头) | -> 严格位于内核入口 0 字节处,包含 Linux Boot Header
-+-----------------------+
-| .text (执行代码) | -> ALIGN(4096), 权限: RX
-+-----------------------+
-| .rodata (只读数据) | -> ALIGN(4096), 权限: R-
-| (含 __init_array) | -> 全局构造函数指针表
-+-----------------------+
-| .data (已初始化数据) | -> ALIGN(4096), 权限: RW
-| (含 __global_pointer$)| -> 位于 .sdata 附近,用于优化全局变量访问
-| (含 early_pgdir) | -> 4KB 静态早期页表
-+-----------------------+
-| .bss (未初始化数据) | -> ALIGN(4096), 权限: RW
-+-----------------------+
-| boot_stack (早期栈) | -> ALIGN(4096), 为每个 CPU 预留 8KB 栈空间
-+-----------------------+
-```
-
-**链接脚本必须导出的符号:**
-
-| 符号名 | 含义 |
-|--------|------|
-| `_start` | 内核入口点(Image Header 首字节) |
-| `_stext` / `_etext` | .text 段边界 |
-| `_srodata` / `_erodata` | .rodata 段边界 |
-| `_sdata` / `_edata` | .data 段边界 |
-| `_sbss` / `_ebss` | .bss 段边界(用于启动清零) |
-| `__global_pointer$` | GP 寄存器锚点 |
-| `__init_array_start` / `__init_array_end` | C++ 全局构造函数表边界 |
-| `_kernel_end` | 内核镜像结束地址(PMM 初始化起点) |
-
-### 3.3 早期页表 (Early Page Table)
-
-- **`early_pgdir`:** 一块静态分配的 4KB `.data` 内存,用作初始顶级页表 (Root Page Table)。
-
-- 内含两个 1GB 的超级大页(Giga Page)映射:
-
- 1. **恒等映射 (Identity Map):** `0x80000000 -> 0x80000000`,保证开启 MMU 瞬间下一条指令能正确取指。
-
- 2. **高半区映射 (Higher-Half Map):** `0xFFFFFFC080000000 -> 0x80000000`,供后续 C++ 代码正常运行。
-
-- **生命周期:** 此恒等映射为临时性过渡,在 VMM 建立完整页表后必须被撤销。高半区映射将被 VMM 接管并细化为 4KB 粒度的精确权限映射。
-
-
-## 4. 公共 API 与核心符号 (Public APIs & Symbols)
-
-### 4.1 RISC-V OS Image Header 规范
-
-在 `entry.S` 的最开始(`.head.text` 段),必须按照以下结构手写 64 字节的元数据。
-定义参照 Linux `arch/riscv/include/asm/image.h` 中的 `struct riscv_image_header`:
-
-```asm
- .section .head.text, "ax"
- .globl _start
-_start:
- /* code0 (u32, offset 0): 可执行跳转指令,OpenSBI 裸启入口 */
- j real_start
- /* code1 (u32, offset 4): 保留 */
- .word 0
- /* text_offset (u64, offset 8): Image 加载偏移 */
- .dword 0x200000
- /* image_size (u64, offset 16): 镜像大小,链接后由脚本填充,初期可写 0 */
- .dword 0
- /* flags (u64, offset 24): 内核标志位 (bit 0: 0=LE, 1=BE) */
- .dword 0
- /* version (u32, offset 32): Header 版本 (major << 16 | minor),当前 0.2 */
- .word 0x0002
- /* res1 (u32, offset 36): 保留 */
- .word 0
- /* res2 (u64, offset 40): 保留 */
- .dword 0
- /* magic (u64, offset 48): RISCV_IMAGE_MAGIC = "RISCV\0\0\0" (LE) */
- .dword 0x5643534952
- /* magic2 (u32, offset 56): RISCV_IMAGE_MAGIC2 = "RSC\x05" (LE) */
- .word 0x05435352
- /* res3 (u32, offset 60): 预留给 PE/COFF 偏移 (UEFI),目前填 0 */
- .word 0
-```
-
-### 4.2 汇编函数签名
-
-```cpp
-// 定义于 arch/riscv/boot/entry.S
-// _start 中的 `j real_start` 跳转目标,执行早期硬件初始化。
-void real_start() __attribute__((noreturn)); // 汇编实现,无 C++ 调用约定
-
-// 定义于 arch/riscv/boot/entry.S 或 kernel/main.cc
-// 仅由 CPU 0 调用,遍历 .init_array 执行全局构造函数。
-void early_cpp_init();
-
-// 定义于 kernel/main.cc
-// C++ 内核总入口。各 CPU 在开启 MMU 后汇聚于此。
-// 参数:cpu_id = 当前 CPU 编号,fdt_paddr = FDT 物理基址。
-void kernel_main(uint64 cpu_id, uint64 fdt_paddr) __attribute__((noreturn));
-```
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-此时 `Spinlock` 尚未初始化,必须使用汇编级的极简同步机制来避免多核访问冲突。
-
-- **本模块持有的锁:** 无高级锁。
-
-- **本模块可能获取的外部锁:** 无。
-
-- **原子同步契约 (SMP Sync):**
-
- 1. 在 `.data` 段定义一个全局标志 `uint32 boot_sync_flag = 0;`。
-
- 2. 只有 **CPU 0** (或 `a0` 读取到的第一个 CPU) 作为主核心 (BSP),获准执行 BSS 清零、早期页表填充等破坏性操作。
-
- 3. **副核心 (AP, Application Processors)** 必须使用原子加载指令在汇编层盲等 `boot_sync_flag` 变为 1。具体实现为 `lw` + 循环比较(不需要 `amoswap`,因为只有 BSP 写入,AP 只读)。
-
- 4. BSP 完成 `early_pgdir` 写入并唤醒 AP 前,必须执行 `fence rw, rw` 以保证所有先前的内存写入对其他 CPU 可见,随后使用 `fence.i` 刷新指令缓存(如有需要),最后将 `boot_sync_flag` 设为 1。
-
-
-## 6. 错误路径 (Error Paths)
-
-在早期的裸机启动阶段,内核没有任何错误恢复能力。
-
-- **检测点:** 所有 CPU 在 `real_start` 入口处可选地检查 `misa` 或 `marchid` 判断基本硬件兼容性(如 64 位检查)。
-
-- **失败行为:** 立即关闭本 CPU 的中断使能(`csrc sstatus, SSTATUS_SIE`),进入 `wfi` 死循环。无串口输出(此时 UART 尚未初始化)。
-
-- **无回滚:** 早期启动无任何资源可回收,失败即死。
-
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-以下描述了从底层固件直到进入 `kernel_main` 的全流程:
-
-```
-[引导分流]
- ├──> OpenSBI 裸启: 直接跳转到内存基址 (0x80200000)
- │ └─ 命中 _start 处的第一条指令 `j real_start`
- │
- └──> GRUB / U-Boot 引导: 解析位于 0x80200000 处的 64 字节 Header
- ├─ 验证 magic ("RISCV\0\0\0") 与 magic2 ("RSC\x05")
- ├─ 验证 text_offset
- └─ 跳转到 0x80200000 (此时 a0=cpu_id, a1=fdt_paddr)
- └─ 同样命中 _start 处的第一条指令 `j real_start`
-
- │ (汇聚点)
- ▼
-[real_start]
- │
- ├─> 1. 设置 gp 寄存器 (la gp, __global_pointer$)
- │ // 极其关键:medany 模型下访问全局变量依赖此寄存器
- │
- ├─> 2. 设置早期内核栈 (la sp, boot_stack + (cpu_id + 1) * 8192)
- │
- ├─> 3. 判断是否为主核心 (CPU 0)?
- │ ├── [是 (BSP)]
- │ │ ├─ 3.1 循环清理 BSS 段 (_sbss 至 _ebss 填 0)
- │ │ ├─ 3.2 填充 early_pgdir (建立恒等映射与高半区映射)
- │ │ ├─ 3.3 fence rw, rw (确保内存修改对其他 CPU 可见)
- │ │ └─ 3.4 释放副核心 (boot_sync_flag = 1)
- │ │
- │ └── [否 (AP)]
- │ └─ 3.1 汇编级自旋等待,直到 boot_sync_flag == 1
- │
- ├─> 4. 高半区蹦床 (Higher-Half Trampoline - 所有 CPU 执行)
- │ ├─ 4.1 将 early_pgdir 物理地址写入 satp 寄存器 (MODE=SV39)
- │ ├─ 4.2 执行 sfence.vma 刷新 TLB
- │ ├─ 4.3 计算 kernel_main 的高半区虚拟地址
- │ └─ 4.4 jr 绝对跳转至虚拟地址,彻底抛弃低位物理 PC
- │
- ▼
-[进入虚拟世界: call early_cpp_init] (仅 BSP 执行)
- │
- └─> 遍历 __init_array_start 到 __init_array_end
- 依次调用全局构造函数,完成 C++ early runtime setup
- │
- ▼
-[跳转至 C++ 逻辑: call kernel_main(a0, a1)] (所有 CPU 汇合)
-``` \ No newline at end of file
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 线性内存。对于多内存区域的真实硬件,需演进为稀疏内存模型。
diff --git a/docs/specs/slab.md b/docs/specs/slab.md
deleted file mode 100644
index dc6953a..0000000
--- a/docs/specs/slab.md
+++ /dev/null
@@ -1,233 +0,0 @@
-# SLUB 分配器 (SLUB Allocator)
-
-## 1. 目标 (Objective)
-
-在物理内存管理器 (PMM) 之上,为内核提供高效的字节级内存分配器。采用 **SLUB** 设计(Simple List of Unfull Blocks),通过复用 PMM 的 `Frame` 描述符存储 per-page 元数据、将空闲链表嵌入对象体内、以及 Per-CPU 活跃页机制,实现低碎片、低锁竞争的小对象分配。本模块是内核 `operator new` 的直接后端。
-
-**为何选择 SLUB 而非经典 Slab:**
-- `Frame` 结构已包含 `cache` 指针和 `obj_count` 字段,无需额外的 per-page `struct Slab` 头部。
-- 省去 full/partial/empty 三链表管理,仅需一个 partial 链表。
-- Per-CPU 缓存仅需一个"当前活跃页"指针,无需动态分配对象数组(避免 slab_init 的鸡生蛋问题)。
-- Linux 自 2.6.23 起默认 SLUB,6.8 已完全移除经典 Slab。
-
-## 2. 前置依赖 (Dependencies)
-
-- **全局初始化契约 (`global_init.md`):** `slab_init()` 在 `pmm_init()` 之后、`vmm_init()` 之前被 BSP 调用。
-- **物理内存契约 (`pmm.md`):** 依赖 `pmm_alloc_frame()` / `pmm_free_frame()` 以及 `Frame` 描述符中的 `slab.cache` 和 `slab.obj_count` 字段。还依赖 `pa_to_frame()` / `frame_to_pa()` 进行地址转换。
-- **并发同步契约 (`spinlock.md`):** 依赖 `Spinlock` 保护全局 partial 链表。
-- **架构抽象契约 (`arch_abstraction.md`):** 依赖 `arch::cpu::id()` 访问 Per-CPU 缓存;依赖 `arch::cpu::intr_off()/intr_on()` 保护 Per-CPU 操作免受中断重入。
-- **项目约定 (`00_conventions.md`):** 遵循所有命名和类型规范。
-
-## 3. 核心数据结构 (Data Structures)
-
-### 3.1 空闲对象链表(嵌入式)
-
-空闲对象的前 `sizeof(void*)` 字节存储下一个空闲对象的指针。对象被分配后,该区域归用户使用。因此**最小对象尺寸 = `sizeof(void*)` = 8 字节**。
-
-```
-[ Free Object ] [ Free Object ] [ Free Object ]
-+-------------+ +-------------+ +-------------+
-| next ---------.------->| next ---------.------->| next = NULL |
-| (unused) | | (unused) | | (unused) |
-+-------------+ +-------------+ +-------------+
-```
-
-### 3.2 Frame 描述符中的 Slab 元数据
-
-复用 `include/lume/frame.h` 中已有的字段(无需新增结构体):
-
-```cpp
-// 当 Frame.state == FrameState::Slab 时有效
-struct {
- KmemCache* cache; // 此页属于哪个 KmemCache
- uint32 obj_count; // 此页上已分配的对象数量
-} slab;
-```
-
-- 此外,需要在 `Frame` 的 `free` union 成员中增加一个 `void* freelist` 字段,或者直接将 freelist 头指针嵌入 union。为保持 Frame 结构简洁,**freelist 头指针存储在页面固定偏移处(页起始的前 8 字节)**,不侵入 Frame 结构。
-
-**修正方案:** 在 `Frame` 的 `slab` union 成员中增加 `void* freelist` 字段:
-
-```cpp
-struct {
- KmemCache* cache; // 所属缓存
- uint32 obj_count; // 已分配对象数
- void* freelist; // 页内空闲对象链表头
-} slab;
-```
-
-### 3.3 Per-CPU 活跃页
-
-每个 CPU 对每个 KmemCache 维护一个"当前活跃页"(cpu_slab)。分配时优先从此页的 freelist 弹出对象,无需获取全局锁。
-
-```cpp
-// 定义于 mm/slab.h (模块私有)
-struct PerCpuSlab {
- Frame* active; // 当前 CPU 正在使用的 slab 页(可能为 nullptr)
-};
-```
-
-### 3.4 内核内存缓存 (`class KmemCache`)
-
-```cpp
-// 定义于 mm/slab.h
-class KmemCache {
-public:
- KmemCache() = default;
- void init(const char* name, uint32 obj_size, uint32 obj_align);
-
- void* alloc();
- void free(void* obj);
-
-private:
- Frame* get_partial(); // 从 partial 链表取一个页
- void put_partial(Frame* f); // 将页放入 partial 链表
- Frame* new_slab(); // 从 PMM 申请新页并格式化
-
- Spinlock lock_; // 保护 partial 链表
- list_node partial_; // 部分填充的 slab 页链表
-
- PerCpuSlab cpu_slab_[kMaxCPUs]; // Per-CPU 活跃页
-
- const char* name_ = "uninit";
- uint32 obj_size_ = 0; // 对齐后的对象尺寸
- uint32 obj_align_ = 0; // 对齐要求
- uint32 objs_per_slab_ = 0; // 每页可容纳的对象数
-};
-```
-
-### 3.5 通用尺寸缓存
-
-```cpp
-// 预创建的 2^N 尺寸缓存: 8, 16, 32, 64, 128, 256, 512, 1024, 2048
-inline constexpr int kNumSizeClasses = 9;
-inline constexpr uint32 kSizeClasses[kNumSizeClasses] = {
- 8, 16, 32, 64, 128, 256, 512, 1024, 2048
-};
-
-extern KmemCache g_size_caches[kNumSizeClasses];
-```
-
-## 4. 公共 API (Public APIs)
-
-```cpp
-// === 初始化 ===
-void slab_init(); // 初始化所有通用尺寸缓存
-
-// === 对象缓存 API ===
-void kmem_cache_init(KmemCache* cache, const char* name,
- uint32 size, uint32 align);
-void* kmem_cache_alloc(KmemCache* cache);
-void kmem_cache_free(KmemCache* cache, void* obj);
-
-// === 通用分配 API ===
-void* kmalloc(uint32 size); // 自动选择尺寸缓存
-void kfree(void* ptr); // 通过 Frame 反查 cache,自动归还
-
-// === C++ Runtime ===
-void* operator new(size_t size);
-void* operator new[](size_t size);
-void operator delete(void* ptr) noexcept;
-void operator delete[](void* ptr) noexcept;
-void operator delete(void* ptr, size_t) noexcept;
-void operator delete[](void* ptr, size_t) noexcept;
-```
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-- **持有锁:** 每个 `KmemCache` 持有一把 `Spinlock lock_`。
-
-- **锁的作用域:** `lock_` **仅保护** `partial_` 链表。
-
-- **Per-CPU 保护:** 访问 `cpu_slab_[cpu_id]` 时必须关闭中断(同 PMM 的 PCP 策略),防止中断重入。
-
-- **快速路径(关中断,无锁):** 从当前 CPU 的 `active` 页的 `freelist` 弹出/压入对象。
-
-- **慢速路径(需要锁):**
- - alloc:当 `active` 页无空闲对象时,获取 `lock_` 从 `partial_` 取页(或调用 PMM 新建)。
- - free:当归还对象使一个页变为完全空闲时,获取 `lock_` 归还 PMM。
-
-- **与 PMM 交互:** `new_slab()` 调用 `pmm_alloc_frame()` 时**不持有** `lock_`(先释放锁,申请页,再获取锁挂入链表),避免 Slab lock → PMM lock 嵌套。
-
-## 6. 错误路径 (Error Paths)
-
-- **初始化失败:** `slab_init()` 若 PMM 无法提供页面,`kernel_panic()`。
-
-- **分配失败:** `kmalloc()` / `kmem_cache_alloc()` 在 OOM 时返回 `nullptr`。
-
-- **释放错误:** `kfree(nullptr)` 为 no-op。传入非法指针(不属于任何 slab 页)时 `kernel_panic()`。
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-### 7.1 `kmem_cache_alloc` 时序
-
-```
-[kmem_cache_alloc(cache) on CPU X]
- │
- ├─> 1. 关中断
- ├─> 2. active = cache->cpu_slab_[X].active
- │
- ├─> 3. if (active && active->slab.freelist != NULL) ?
- │ ├── [是 (Fast Path)]
- │ │ ├─ obj = active->slab.freelist
- │ │ ├─ active->slab.freelist = *(void**)obj
- │ │ ├─ active->slab.obj_count++
- │ │ ├─ 恢复中断
- │ │ └─ return obj
- │ │
- │ └── [否 (Slow Path)]
- │ ├─ 4.1 将 active (若满) 从 cpu_slab 移出
- │ ├─ (满页不需要跟踪,但其 Frame 中 cache 指针仍有效)
- │ ├─ 4.2 恢复中断
- │ ├─ 4.3 LockGuard guard(cache->lock_)
- │ ├─ 4.4 new_active = get_partial() // 从 partial 链表取
- │ │ └─ 若无,释放锁 → new_slab() → 重新获取锁
- │ ├─ 4.5 释放锁
- │ ├─ 4.6 关中断
- │ ├─ 4.7 cache->cpu_slab_[X].active = new_active
- │ ├─ 4.8 从 new_active->slab.freelist 弹出 obj
- │ ├─ 4.9 恢复中断
- │ └─ return obj
- │
- ▼
-[返回 obj* 或 nullptr]
-```
-
-### 7.2 `kfree` 时序
-
-```
-[kfree(ptr)]
- │
- ├─> 1. pa = ptr 的物理地址 (对于 identity/higher-half,减去偏移)
- ├─> 2. frame = pa_to_frame(pa & ~(kPageSize-1))
- ├─> 3. cache = frame->slab.cache
- │
- ├─> 4. 关中断
- ├─> 5. 将 obj 压入 frame->slab.freelist
- ├─> 6. frame->slab.obj_count--
- │
- ├─> 7. if (obj_count == 0) ?
- │ ├── [是:页完全空闲]
- │ │ ├─ 若此页是当前 CPU 的 active,清除 active
- │ │ ├─ 恢复中断
- │ │ ├─ LockGuard: 从 partial_ 链表移除 (如果在链表中)
- │ │ └─ pmm_free_frame(frame) // 归还 PMM
- │ │
- │ └── [否]
- │ ├─ 若此页不是任何 CPU 的 active 且不在 partial,
- │ │ 则需获取锁放入 partial (满→部分满的过渡)
- │ └─ 恢复中断
- │
- ▼
-[完成]
-```
-
-## 8. 已知缺陷与未来挑战
-
-### 8.1 缓存收缩
-
-当前不主动收缩 partial 链表。未来可增加 `kmem_cache_shrink()` 供内存回收线程调用。
-
-### 8.2 大对象分配
-
-大于 2048 字节的分配直接退化为 `pmm_alloc_frames()`。当前由 `kmalloc` 透明处理。
diff --git a/docs/specs/spinlock.md b/docs/specs/spinlock.md
deleted file mode 100644
index b5dd92b..0000000
--- a/docs/specs/spinlock.md
+++ /dev/null
@@ -1,204 +0,0 @@
-# 自旋锁与并发同步 (Spinlock & Synchronization)
-
-## 1. 目标 (Objective)
-
-为 LumeOS 提供多核环境下的底层互斥机制。本模块实现基于原子操作的自旋锁(Spinlock)和基于 RAII 范式的局部锁守卫(LockGuard)。同时,严格定义锁操作前后的硬件中断屏蔽策略(避免单核中断死锁)以及底层内存序保证(Memory Ordering)。
-
-## 2. 前置依赖 (Dependencies)
-
-- **全局类型契约:** `include/lume/types.h`。
-
-- **架构原语契约:** 依赖 `arch_abstraction.md` 中的 `arch::cpu::id()`, `arch::cpu::intr_on()`, `arch::cpu::intr_off()`, `arch::cpu::intr_enabled()`。
-
-- **Panic 机制:** 依赖底层的内核崩溃函数 `kernel_panic(const char* msg)`。
-
-- **全局初始化契约:** `g_cpu_sync_states[]` 为 BSS 段全局数组,由 `entry.S` 的 BSS 清零保证初始值为零。`Spinlock` 作为全局对象时,必须通过 `init()` 方法显式初始化(参见 `global_init.md`),不得依赖构造函数。
-
-
-## 3. 核心数据结构 (Data Structures)
-
-### 3.1 CPU 中断嵌套跟踪器
-
-为了支持锁的嵌套(如持有 `A` 锁时去获取 `B` 锁),必须在每 CPU 维度跟踪锁的深度,确保只有释放**最后一把锁**时,才恢复真实的中断状态。
-
-```cpp
-// 定义于 kernel/sync/cpu_state.h
-namespace sync {
- struct CpuSyncState {
- int lock_depth; // 当前 CPU 持有的自旋锁数量 (嵌套深度)
- bool intr_was_on; // 在获取第一把锁之前,中断是否处于开启状态
- };
- // BSS 段全局数组,由 entry.S 清零初始化
- inline constexpr uint64 kInvalidCpuId = ~0ULL;
- extern CpuSyncState g_cpu_sync_states[kMaxCPUs];
-}
-```
-
-### 3.2 自旋锁类 (`Spinlock`)
-
-```cpp
-// 定义于 kernel/sync/spinlock.h
-class Spinlock {
-public:
- // 默认构造:locked_ = 0, name_ = "uninit", cpu_id_ = kInvalidCpuId
- // 全局 Spinlock 在 BSS 清零后通过 init() 显式初始化
- Spinlock() = default;
-
- // 显式初始化(用于全局对象或 Placement New 场景)
- void init(const char* name);
-
- // 禁用拷贝与移动 (锁对象具有固定的内存地址身份)
- Spinlock(const Spinlock&) = delete;
- Spinlock& operator=(const Spinlock&) = delete;
-
- void acquire();
- void release();
- bool is_held_by_current_cpu() const;
-
-private:
- uint32 locked_ = 0; // 锁状态:0=空闲, 1=占用
- const char* name_ = "uninit"; // 锁名称 (用于 Panic 输出)
- uint64 cpu_id_ = sync::kInvalidCpuId; // 持有者 CPU 编号
-};
-```
-
-### 3.3 RAII 锁守卫 (`LockGuard`)
-
-```cpp
-// 定义于 kernel/sync/spinlock.h
-class LockGuard {
-public:
- explicit LockGuard(Spinlock& lock) : lock_(lock) {
- lock_.acquire();
- }
-
- ~LockGuard() {
- lock_.release();
- }
-
- // 禁用拷贝与移动
- LockGuard(const LockGuard&) = delete;
- LockGuard& operator=(const LockGuard&) = delete;
-
-private:
- Spinlock& lock_;
-};
-```
-
-## 4. 公共 API 与中断管理协议 (Public APIs)
-
-### 4.1 中断压栈/出栈协议 (Internal API)
-
-**这是 Spinlock 安全性的核心。** 必须在 `Spinlock::acquire()` 和 `release()` 内部隐式调用,严禁外部业务层手动调用。它实现了 `_irqsave` / `_irqrestore` 的语义。
-
-```cpp
-namespace sync {
- /**
- * @brief 保存当前中断状态、关闭中断,并增加锁嵌套深度。
- *
- * 如果是获取第一把锁 (lock_depth 从 0 变 1),则将当前的中断使能状态
- * (sstatus.SIE) 保存到 per-cpu 的 intr_was_on 字段中。
- * 随后,无论何种情况,都关闭中断。
- */
- void push_intr_save();
-
- /**
- * @brief 减少锁嵌套深度,并在释放最后一层锁时恢复之前的中断状态。
- *
- * 如果锁嵌套深度降为 0,则检查 intr_was_on 字段。只有当获取第一把锁
- * 之前中断是开启的时候,才重新开启中断。
- */
- void pop_intr_restore();
-}
-```
-
-### 4.2 锁语义约定
-
-本模块属于内核生命线,发生任何违反并发契约的行为(如重复加锁、越权解锁)均属于致命代码逻辑错误。 **此类函数无返回值,一旦检测到契约被破坏,直接触发 `kernel_panic()` 宕机。**
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-### 5.1 内存序保证 (Memory Order Guarantee)
-
-为了确保临界区内的读写操作不会被编译器或 CPU 的乱序执行(Out-of-Order Execution)重排到临界区外,必须使用带有内存屏障语义的原子操作。
-
-- **Acquire 语义:** `Spinlock::acquire()` 内部的原子交换必须使用 `__ATOMIC_ACQUIRE`。在 RISC-V 层面,这将生成带有 `.aq` (Acquire) 后缀的原子指令(如 `amoswap.w.aq`),确保锁获取之后的任何内存读写,都不会被重排到拿锁之前。
-
-- **Release 语义:** `Spinlock::release()` 内部的原子写零必须使用 `__ATOMIC_RELEASE`。使用 `__atomic_store_n(&locked_, 0, __ATOMIC_RELEASE)`,在 RISC-V 层面生成 `fence rw, w` + `sw`。注意:release 不需要原子 RMW 指令(`amoswap`),普通的 release-store 即可——因为此时本 CPU 已经是唯一的锁持有者,不存在竞争写。
-
-### 5.2 自旋优化 (TTAS: Test-and-Test-and-Set)
-
-朴素的 `while(__atomic_exchange_n(...))` 会在每次迭代都发出总线级原子操作,导致缓存一致性协议风暴。必须使用 TTAS 模式:
-
-```cpp
-void Spinlock::acquire() {
- sync::push_intr();
- // 外层:非原子读,利用本地缓存副本空转,不产生总线流量
- while (true) {
- while (__atomic_load_n(&locked_, __ATOMIC_RELAXED))
- ; // 在 L1 cache 上旋转,等待释放信号via cache invalidation
- // 内层:看到可能空闲,才发起真正的原子交换
- if (__atomic_exchange_n(&locked_, 1, __ATOMIC_ACQUIRE) == 0)
- break; // 成功获取
- }
- cpu_id_ = arch::cpu::id();
-}
-```
-
-### 5.3 业务层使用契约 (Caller Contract)
-
-1. **禁止睡眠:** 在持有 `Spinlock`(或处于 `LockGuard` 作用域内)的任何期间,**绝对禁止**调用可能导致当前 Task 休眠或主动放弃 CPU 的函数(如 `sleep()`, `yield()`, 或由于分配内存触发了等待)。
-
-2. **优先 RAII:** 常规业务逻辑中应通过 `LockGuard` 对象管理锁的生命周期,利用 C++ 析构确保锁在异常或提前 return 时必定释放。`acquire()/release()` 公开暴露仅供**调度器内部**等必须跨函数边界持有锁的特殊场景使用(如 `sleep()` 中释放锁 + 上下文切换 + 醒来后重新获取)。
-
-3. **锁序遵守:** 嵌套获取多把 Spinlock 时,必须严格遵循全局锁序 DAG(将在 Phase 2 完成后汇总为 `lock_ordering.md`)。任何违反锁序的代码在 Code Review 中必须被驳回。
-
-
-## 6. 错误路径与 Panic 触发点 (Error Paths)
-
-在以下情况下,自旋锁必须立即执行 `kernel_panic()` 阻断系统:
-
-1. **死锁防御 (Double Lock):** 在 `acquire()` 中,调用 `push_intr()` 关中断后、原子操作前,检查 `is_held_by_current_cpu()`。若为 `true`,说明当前 CPU 试图获取自己持有的锁,必然死锁,立即 Panic。打印锁名称与 CPU ID。
-
-2. **越权释放 (Invalid Release):** 在 `release()` 中,若 `is_held_by_current_cpu()` 为 `false`,说明代码逻辑严重错乱(锁未被持有、或被其他 CPU 持有),立即 Panic。
-
-3. **中断状态校验:** 在 `acquire()` 入口(`push_intr()` 之前),若中断已被开启但 `lock_depth > 0`,说明存在中断状态泄漏(某处代码在持有锁的同时非法开启了中断),可选 Panic。此检查在 `#ifdef DEBUG` 下启用以避免正式构建的性能损失。
-
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-### 7.1 Spinlock Acquire / Release 硬件级时序
-
-```
-[当前 CPU (CPU X) 请求 LockGuard]
- │
- ├─> 1. push_intr()
- │ ├─ 读取当前中断状态: was_on = arch::cpu::intr_enabled()
- │ ├─ 关中断: arch::cpu::intr_off()
- │ └─ if (lock_depth == 0) intr_was_on = was_on; lock_depth++
- │
- ├─> 2. 断言: is_held_by_current_cpu() == false (否则 Panic: double lock)
- │
- ├─> 3. TTAS 自旋获取
- │ ├─ 外层 while: __atomic_load_n(&locked_, RELAXED) 非原子读空转
- │ └─ 内层 CAS: __atomic_exchange_n(&locked_, 1, ACQUIRE) == 0 → 成功
- │
- ├─> 4. 记录属主: cpu_id_ = arch::cpu::id()
- │
- ▼
-[执行临界区 C++ 业务逻辑 (关中断、无休眠)]
- │
- ▼
-[LockGuard 析构,触发 release()]
- │
- ├─> 1. 断言: is_held_by_current_cpu() == true (否则 Panic: invalid release)
- │
- ├─> 2. 擦除属主: cpu_id_ = kInvalidCpuId
- │
- ├─> 3. __atomic_store_n(&locked_, 0, __ATOMIC_RELEASE)
- │ └─ RISC-V: fence rw, w + sw zero → 临界区写入全局可见后才释放锁
- │
- └─> 4. pop_intr()
- ├─ lock_depth--
- └─ if (depth == 0 && intr_was_on) arch::cpu::intr_on()
-``` \ No newline at end of file
diff --git a/docs/specs/testing_and_ci.md b/docs/specs/testing_and_ci.md
deleted file mode 100644
index 9d869d8..0000000
--- a/docs/specs/testing_and_ci.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# 测试与持续集成 (Testing & CI)
-
-## 1. 目标 (Objective)
-
-为 LumeOS 项目定义自底向上的自动化测试标准与持续集成(CI)规范。通过建立在系统早期启动阶段驻留执行的 Boot Self-Test(KUnit)框架,严格确保内存管理、调度器、同步原语等底层基础设施无隐患。配合 `make test` Makefile 目标以及退出码(Exit Code)规范,构筑防止代码腐化的防线。
-
-## 2. 前置依赖 (Dependencies)
-
-- **全局类型契约:** `include/lume/types.h`。
-- **输出机制:** 早期格式化输出需求依赖 `early_puts` 和 `early_putc` 等纯串口驱动原语。
-- **宕机机制:** 依赖 `include/lume/panic.h` 定义的 `kernel_panic` 用于对测试失败执行终端处决。
-- **QEMU CI 环境:** 自动化截取退出码依赖硬件特性的 `sifive_test` 接口(通过 OpenSBI 提供 System Reset/Poweroff 的底层能力)。
-
-## 3. 核心机制设计
-
-为了不侵入或依赖过于复杂的上下文结构,测试系统在操作系统生命周期的“最初始安全阶段”进行:
-- **执行点:** 位于 `kernel_main()` 核心初始化逻辑收尾后(所有关键数据结构已分配完毕),但在多核被唤醒(AP 启动)以及用户态进程加载之前。
-- **单核无中断:** 测试套件固定且绝对运行于 BSP (CPU 0) 的单核互斥环境中。在这些断言执行时,硬件中断是被严格关闭的。
-
-## 4. KUnit 宏签名与接口规范 (Public APIs)
-
-在 `include/lume/selftest.h` 中对外暴露以下断言宏。所有测试文件的断言仅允许使用下述原语:
-
-### 4.1 核心断言宏
-
-所有断言宏若验证通过通常无反馈,一旦发现断言失败即发生 `Panic` 导致系统停机。
-
-```cpp
-// 最基础的条件真实性断言
-#define ST_ASSERT(cond)
-
-// 验证两个数值、指针或枚举绝对相等的断言
-// 失败时会自动将变量与地址分别序列化输出以协助排查
-#define ST_ASSERT_EQ(a, b)
-
-// 验证两个量绝对不相等的断言
-#define ST_ASSERT_NE(a, b)
-```
-
-### 4.2 控制与排版原语
-
-```cpp
-// 在每个用例的前置输出 `[test] <name> ... `
-void st_begin(const char* name);
-
-// 在用例顺利通过后输出 `PASS` 并换行
-void st_pass();
-
-// C++ 自检主函数,由各个测试子模块(如 test_pmm.cc)自行声明填充。
-// 必须注册到 kernel_main 中调用的 `selftest_run_all()` 总表中。
-void selftest_xxx();
-```
-
-## 5. Panic 退出码与 QEMU CI 自动退出 (Exit Codes)
-
-为了让 GitHub Actions 或者外部自动化测试流水线有效地判决 LumeOS 是否正确运行,我们需要与 QEMU 沟通,而不是靠正则表达式提取输出文字。
-
-### 5.1 失败与宕机 (Panic)
-
-当某个 `ST_ASSERT` 失效时:
-1. `kernel_panic("selftest failed", detail);` 触发。
-2. 串口向屏幕喷出宕机回溯(行号与文件名)。
-3. **调用 SBI 接口终止运行:**内核使用 OpenSBI (EID `0x53525354` System Reset Extension),发起 System Failure 指令并传送特定的退出码(例如 Exit Code 127)。
-
-### 5.2 成功退出校验
-
-当所有的 `selftest` 在 `make test` 命令中走通并通过所有的断言验证时:
-1. 输出 `All self-tests PASSED`。
-2. 不会进入系统的死循环(挂机状态)。
-3. 核发送带有 Exit Code 0 的 SBI 成功关机请求,使得宿主机的 `make test` 返回码为成功,绿灯放行 CI 。
-
-## 6. `make test` 规范 (Make Target)
-
-`make test` 须作为一个专职的自动化冒烟测试管道:
-
-- `make test` 将编译特制的测试版本(例如自动注册带有 CI 自动关机行为的 Flag )。
-- **屏蔽图形学延误:** 测试应当在 Makefile 使用 `-nographic` 的纯无头界面(Headless)运行 QEMU。
-- **无等待结束:** QEMU 只要执行测试程序,系统即可在极短时间内得到退出码反馈结果,不会陷入一直等待。
-- **集成于构建流:** `make fmt && make lint && make test` 是提交到 Main 分支之前在开发者本地应当成为默认习惯的行为指令链。
-
-## 7. 错误路径 (Error Paths)
-
-因为其测试属性:只要未跑通,便进入灾难模式(Panic)。此时不考虑优雅释放任何当前持有的锁,亦不关闭或清理页表,而是立刻抛血书以保护现场,等待开发者进行后续 GDB 对照排查。
diff --git a/docs/specs/vmm.md b/docs/specs/vmm.md
deleted file mode 100644
index 7492a02..0000000
--- a/docs/specs/vmm.md
+++ /dev/null
@@ -1,158 +0,0 @@
-# 虚拟内存管理器 (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
-```