《Rust编程实战》19.2 操作系统开发

区分 Rust 的安全代码、no_std 与可启动内核,梳理启动、内存、中断和设备访问的前置条件,以及教学项目的学习与验证路径。

19.2 操作系统开发

本节是进入操作系统实践的路线说明,不是一个完整内核。读完后应能区分「不使用标准库」「生成目标代码」「在模拟器中启动」三个阶段,知道下一步需要补什么。

前置知识:Rust 所有权与错误处理、基本汇编、地址空间、中断,以及目标架构的调用约定。

19.2.1 内存安全需要有边界

安全 Rust 的检查可帮助防止悬挂引用等错误,但驱动、页表和内存映射经常需要原始指针或 unsafe。这些部分的正确性取决于实现者维护的约束,不能把「使用 Rust」等同于整个内核不会出错。死锁、资源泄漏、设备配置错误也不由借用检查器自动消除。

把危险操作封装成较小的接口,明确地址是否有效、访问是否对齐、对象何时失效、谁有权限写入,比笼统宣称完全安全更有用。

19.2.2 no_std 不是一个可以启动的操作系统

#![no_std] 使 crate 不依赖 std,仍可使用 core。它不自动提供堆分配器、文件系统、线程、TCP 栈或启动代码。是否需要 alloc、如何提供分配器,取决于项目设计。基础范围见 Embedded Rust Book 。

下面只是一个独立的逻辑库,保存为 tick.rs 后可检查其编译,不含入口、链接脚本和引导程序:

#![no_std]

pub fn next_tick(current: u64) -> Option<u64> {
    current.checked_add(1)
}
rustc --edition=2021 --crate-type=lib tick.rs

即使这一步通过,也只能证明库能编译,不能宣告裸机内核可以启动。目标架构不同,还需要对应 target、链接布局、panic 处理与启动协议。关于独立程序的完整步骤,可参照 Writing an OS in Rust ,并固定所用教程与工具链版本。

19.2.3 把启动过程拆成可验收的阶段

阶段应得到的结果常见误判
生成镜像链接成功,入口与地址布局符合引导协议把普通宿主二进制当作内核镜像
最小启动模拟器启动并产生串口或其他可观察输出仅凭编译成功判断启动成功
内存与异常分配、释放及异常处理有边界测试只测试成功分配,不测试耗尽或非法访问
中断与设备能处理重复中断、错误状态及超时把一次正确输出当作稳定运行
调度与隔离切换、取消与权限边界有验证用语言的线程模型代替内核调度设计

每阶段保存工具链、target、模拟器版本、构建命令、启动命令和实际日志。涉及地址、页大小和寄存器的结论按目标架构分别核验。

19.2.4 从教学项目进入

rCore 教程 提供操作系统学习路线。开始前先读对应版本的环境要求,再按项目提供的方式构建;不要把另一套教程的架构、链接脚本和启动参数混进来。

第一次练习只追求一个可解释的结果:能启动、能输出、能说明控制权从哪里进入。之后再逐步进入异常、地址空间、进程与文件系统。没有阶段日志时,不把「某个项目用了 Rust」当作本机验证证据。

19.2.5 练习与检查点

  1. 说明上述 tick.rs 与一个可启动内核之间还缺哪些部分。答案至少应包含入口、引导、目标架构和链接布局。
  2. 为内存分配器列出耗尽、重复释放、对齐三类验证场景。区分运行测试与 unsafe 接口需要维护的安全条件。
  3. 在项目 README 中分别列出构建成功与启动成功的证据,避免把两者混写。

2026-10-12 修订:删除没有范围限定的安全与性能宣传,明确 no_std 和可启动内核的区别,补齐阶段验收与参考入口。本节没有声称已完成裸机启动实验。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「rust」更多文章

  1. 性能剖析与优化
  2. 测试与基准:criterion 与 proptest
  3. Serde 与序列化生态