diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-04-17 00:50:38 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-04-17 00:50:38 +0800 |
| commit | ab83dfb9a607807a6373f9bd47190848b822cf6e (patch) | |
| tree | c809f259600cecebf1ad36e018a07748de36a452 /docs/specs | |
| parent | 72f698b2109523fbe327a40a0a70601fe470a1ca (diff) | |
| download | lume-ab83dfb9a607807a6373f9bd47190848b822cf6e.tar.gz lume-ab83dfb9a607807a6373f9bd47190848b822cf6e.tar.xz | |
feat: add project conventions
Diffstat (limited to 'docs/specs')
| -rw-r--r-- | docs/specs/00_conventions.md | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/docs/specs/00_conventions.md b/docs/specs/00_conventions.md new file mode 100644 index 0000000..91b98c9 --- /dev/null +++ b/docs/specs/00_conventions.md @@ -0,0 +1,367 @@ +# 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` +- Spinlock 的 acquire/release 内含隐式 fence,临界区内无需额外屏障 +- **禁止** 用裸 `volatile` 替代原子操作 + +--- + +## 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++17 (`-std=c++17`) | +| 关键编译选项 | `-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) | + |
