本规范用于统一内核代码风格、注释撰写以及项目文件组织,降低维护成本与重构风险。除非特殊说明,遵循 Rust 官方惯例与现有项目结构。新增代码或修改旧代码时请自检是否满足本规范。
Comix 项目统一使用中文进行接口和文档注释
- 每个公共模块(
mod.rs或独立文件)使用//!释义模块目的、设计取舍和与其它模块的关系。 - 若模块内部存在不变量(如:页表条目的合法组合、锁使用上下文),必须在模块顶注释中列出。
- 公共 API(
pub)使用///,首行简述,后续分段:- 参数说明(使用列表
- name: 含义) - 返回值说明(含错误场景与 errno 或 Result 类型)
- 时序 / 调用条件(如:只能在关中断状态下调用)
- 示例(简短,可省略复杂依赖)
- 参数说明(使用列表
- 私有函数只在非显而易见逻辑时添加行内注释或块注释。
示例:
/// 分配一个物理页并映射到给定虚拟地址
/// 参数:
/// - va: 需要页对齐的虚拟地址
/// - flags: 页权限(必须包含 valid)
/// 返回: Ok(()) 映射成功;Err(MapError::AlreadyMapped) 已存在;其它错误传递上层
/// 安全:调用者必须保证 va 不指向内核保留区域
- 每个
unsafe {}上方添加// SAFETY:注释,说明:- 不变量(如:指针来自经过校验的页框、长度匹配)
- 为什么执行内存读写 / 汇编 / 寄存器操作是安全的
示例:
// SAFETY: frame_ppn 来自分配器,指向独占页;长度不超过 PAGE_SIZE
unsafe { ptr::copy_nonoverlapping(src, dst, len); }- 每段逻辑前使用注释块(功能、寄存器约定、修改的 CSR)。
- 保存 / 恢复顺序与 TrapFrame 偏移保持一一对应,偏移推荐通过宏或包含的
.inc生成(后续重构)。
- 避免重复“翻译代码”式注释;仅在出现:
- 魔数(写出来源)
- 性能 / 内存布局技巧
- 架构相关细节 时添加解释。
- 统一格式:
// TODO(tag): 描述,可选 tag(perf / safety / clarity)。 - 仅保留真正计划处理的项;过期项需清理。
- 使用仓库内
rustfmt.toml,禁止关闭 rustfmt。 - 不使用
#![allow(clippy::all)];逐步引入 Clippy 规则,局部抑制使用#[allow(...)]并注释原因。
| 类型 | 约定 |
|---|---|
| 模块 / 文件 | 全小写,下划线分词(memory_space) |
| 结构体 / 枚举 / Trait | PascalCase(MemorySpace, TaskState) |
| 方法 / 变量 / 函数 | snake_case(activate, alloc_frame) |
| 常量 / 静态 | UPPER_SNAKE_CASE(PAGE_SIZE, STACK_ALIGN_MASK) |
| 枚举成员 | PascalCase(User, Kernel) |
| 泛型参数 | 单字母或语义化(T, P: PageProvider) |
- 系统调用内部返回负 errno(
-libc_errno),内核内部使用Result<T, E>。 - 错误枚举实现
Debug+Display,日志中使用{:?}简明输出。 - 避免滥用
expect/unwrap,除非:- 初始化阶段(panic 可接受)
- 明确不变量已保证(需注释阐明)
- 使用统一日志宏(
log::info!,log::warn!);禁止直接println!(除非常早期 boot 阶段)。 - panic 信息包含:模块名前缀 + 关键上下文(
"page_table: invalid PTE flags: ...")
只允许在以下模块 / 场景出现:
- 页表和地址空间操作(MMU / satp 切换)
- Trap 与上下文切换(汇编入口、恢复)
- 用户态内存复制(
copy_from_user/copy_to_user) - 设备 / CSR 访问
其它模块出现 unsafe 需重构或写明合理性。
- 中断上下文只允许使用自旋锁;禁止睡眠锁、阻塞操作、内存分配(除预分配池)。
- 嵌套获取自旋锁必须保持全序(按模块定义顺序)。
- 避免持锁调用跨模块高层 API;将重入口风险最小化。
- 地址使用类型封装(后续重构):
VirtAddr,PhysAddr,Ppn,Vpn,禁止滥用裸usize。 - 指针算术集中在内存管理层;调用者传入长度必须与对象大小匹配。
- 不在普通逻辑代码里直接对物理地址做
as *mut u8,应通过安全封装函数。
- 优先组合(struct 包含)而非继承 / 深层 trait 对象。
- trait 用于抽象可替换组件(如:调度器、页分配器),尤其是内核中使用到的全局对象。
- 不引入复杂宏元编程;保持简单、展开后可读。
- 高频路径(调度 / Trap / 页表)避免分配与格式化字符串。
- 小循环优先手写而非迭代器链;但保持可读性权衡。
- 不在中断或 Trap 入口打印日志(除致命错误)。
- tests 模块使用
#[cfg(test)]内内联。 - 纯算法(地址计算、映射合并)单元测试;涉及硬件依赖放到后续仿真集成测试。
- 不在测试中使用不稳定内部 API;暴露小型测试辅助接口。
| 层级 | 职责 | 依赖方向 |
|---|---|---|
| arch | 架构专有:寄存器、Trap、启动、页表格式 | 不依赖上层 |
| mm | 物理/虚拟内存抽象、分配器、地址类型 | 仅少量架构细节 |
| kernel | 调度、任务、系统调用、CPU 管理 | 依赖 mm + arch |
| fs / vfs | 文件系统与名称解析层 | 依赖 kernel(任务上下文) |
| sync | 锁与并发原语 | 不依赖高层 |
| log | 日志设施 | 不依赖高层 |
| user(嵌入) | 用户态程序二进制 | 不参与编译逻辑 |
禁止反向依赖:高层不得让底层引用其内部结构(例:mm 不应引用 Task)。
- 除
arch模块外,采用扁平化的组织方式,mod路径不超过三层(例如,`crate::kernel::task)。 - 过大的模块单独使用一个
mod.rs汇总导出公共接口。 - 文件命名语义化:
trap_handler.rs,frame_allocator.rs,task_manager.rs。 - 超过 ~800 行的文件需拆分(例如:页表操作与入口管理)。
- 宏放置:单独
macros.rs或靠近使用处,避免全局污染。
arch/<isa>/子目录结构与riscv保持一致(trap、mm、platform)。- 公共抽象(如:
PageTableOps)放在非架构目录,RISC-V 提供实现。
- 架构相关常量置于
arch/riscv/constant.rs。 - 全局可调参数集中到
config.rs,避免散落硬编码。 - 不允许多处定义同一页大小 / 对齐值。
- 后续生成 TrapFrame 偏移可使用
build.rs输出const,防止汇编与 Rust 偏移不一致。 - QEMU 启动脚本单一入口(
qemu-run.sh),Makefile 封装常用目标:run/debug/gdb/fmt/clippy.
- 避免引入重量级依赖(serde / alloc-heavy crates),保持可控二进制大小与可审计。
- 单次提交聚焦单一主题(“实现 syscall write 参数校验”)。
- 提交信息格式:
- 前缀:
feaf: .../test: .../docd: ... - 主体:简述改动与动机,列出兼容性注意点。
- 前缀:
| 领域 | 不变量 |
|---|---|
| 页表 | 映射条目 valid ⇒ 物理页独占或引用计数递增;U 页不可被内核写入除非 SUM=1 |
| Trap | sscratch 始终指向当前任务 TrapFrame;kernel_sp 有效可写 |
| 调度 | 任务状态转移遵循:Ready → Running → {Blocked |
| 内存复制 | 用户指针必须通过边界检查(地址区间 + 页权限),失败返回 -EFAULT |
| 常量 | 说明 |
|---|---|
| PAGE_SIZE | 页大小(与架构一致) |
| STACK_ALIGN_MASK | 栈对齐掩码 |
| KERNEL_BASE | 内核虚拟地址基址(若使用高半区) |
| USER_STACK_SIZE | 默认用户栈大小 |
本规范将随项目演进更新,新增模块请在 PR 中引用本文件并补充相关规则。欢迎提出改进建议。