使用Rust在树莓派上编写操作系统 - 00 - 前言

在我们开始之前

以下文本是文档的1:1副本,会出现在每章教程所对应的内核主要源文件的顶部。文档描述了相应源文件的结构,并尝试解释该实现背后的原理。请阅读该文档,以熟悉将会在教程中遇到的内容,文档将帮助你更好地浏览代码,并理解每一章教程之间的递进关系。

另请注意,以下文本将引用第一批教程中尚不存在的源文件(如**/memory.rs)或函数。随着教程的推进,它们将逐渐被添加。

玩得开心!

代码组织和架构

代码分为不同的模块,每个模块代表一个典型的内核子系统。子系统的顶层模块文件直接位于src文件夹中。例如,src/memory.rs将包含与所有内存管理相关的代码。

处理器架构代码的可见性

内核的某些子系统基于特定目标处理器架构的底层代码。对于每个支持的处理器架构,在src/_arch中都存在一个子文件夹,例如,src/_arch/aarch64

这些架构文件夹反映了在src中布置的子系统模块。例如,属于内核MMU子系统(src/memory/mmu.rs)的架构相关代码将位于src/_arch/aarch64/memory/mmu.rs。里面的文件将以模块的方式,通过path属性加载到src/memory/mmu.rs中。通常使用以arch_为前缀,后接通用模块名称,作为导入的模块名称。

例如,这是src/memory/mmu.rs的前几行:

1
2
3
#[cfg(target_arch = "aarch64")]
#[path = "../_arch/aarch64/memory/mmu.rs"]
mod arch_mmu;

大多数情况下,arch_module中的项会被父模块以公开方式重导出。如此,针对各架构的模块就可以对外提供其各项实现,而调用者不必关心哪个架构已经被条件编译了。

BSP代码

BSP即Board Support Package。BSP代码位于src/bsp.rs下,包含目标板特定的变量和函数,例如目标板内存的映射、目标板特有设备的驱动程序实例之类的东西。

就像处理器架构代码那样,BSP代码的模块结构,类似内核子系统代码的模块结构,只不过这次没有重导出。这意味着必须从bsp命名空间开始调用其提供的任何内容,例如bsp::driver::driver_manager()

内核接口

archbsp都包含条件编译的代码,具体取决于编译内核的目标环境和板卡。例如,树莓派3树莓派4中断控制器的硬件是不同的,但我们希望其余的内核能够很方便地与两者中的任何一个一起使用。

为了在archbsp通用内核代码之间提供一个清晰的抽象,我们在只要有可能有意义的地方封装了interfacetrait。这些trait定义在各子系统模块中,以强制我们实现面向接口编程,而是不面向实现编程。例如,将有一个通用IRQ处理接口,由两个版本树莓派各自的中断控制器驱动实现,并且只将该接口导出到内核的其余部分。

1
2
3
4
5
6
7
8
9
10
11
        +-------------------+
| Interface (Trait) |
| |
+--+-------------+--+
^ ^
| |
| |
+----------+--+ +--+----------+
| kernel code | | bsp code |
| | | arch code |
+-------------+ +-------------+

总结

对于逻辑内核子系统,相应的代码可以分发在不同的物理位置。以内存子系统为例:

  • src/memory.rssrc/memory/**/*
    • 通用代码并不知道目标处理器架构和BSP特征。
      • 示例:一个用于将内存块归零的函数。
    • archBSP中的代码实现的内存子系统的接口。
      • 示例:定义MMU函数原型的MMU接口。
  • src/bsp/__board_name__/memory.rssrc/bsp/__board_name__/memory/**/*
    • 特定BSP的代码。
    • 示例:特定板子的内存映射(DRAM和MMIO设备的物理地址)。
  • src/_arch/__arch_name__/memory.rssrc/_arch/__arch_name__/memory/**/*
    • 特定处理器架构的代码。
    • 示例:实现__arch_name__处理器架构的MMU接口。

从名称空间的角度来看,内存子系统代码位于:

  • crate::memory::*
  • crate::bsp::memory::*

启动流程

  1. 内核的入口点是函数cpu::boot::arch_boot::_start()
  • 其实现位于src/_arch/__arch_name__/cpu/boot.rs

下面不是翻译,是我写的使用方法。


下载

直接克隆本教程即可使用:

1
gh repo clone rust-embedded/rust-raspberrypi-OS-tutorials

rust-analyzer

我的macOS貌似通过macports装了另一个版本的Rust,要知道通过rustup安装的Rust位于~/.cargo/bin/中,而port安装的Rust位于/opt/local/bin/中。这导致vscode启动时,默认加载的环境变量可能会使用port的版本,而该版本并不是rustup安装的,可能缺少rust-src等组件,这会导致rust-analyzer工作异常。尝试解决:

  • 😕 直接export环境变量后启动vscode,能解决问题,但是每次启动很麻烦,并不优雅。

  • 😕 修改shell的各个profile环境变量,但是这会牵连出很多未知问题,因为可能影响到其他程序的环境变量搜索顺序。(附:shell各profile的加载顺序介绍12

  • 😕 尝试修改rust项目中配置文件的rustc设置,发现对rust-analyzer并不起作用。

  • 😕 直接卸载port版本,简单有效,但是由于忘记了port版本是不是我有意识安装的,所以并不知道会不会对其他程序产生影响。

  • 🎉 修改vscode的rust-analyzer插件的extraEnv配置,该配置位于:扩展: rust-analyzer -> 扩展设置 -> 搜索extraEnv -> 在 setting.json 中编辑,打开编辑器,向extraEnv字典新增两行路径:

    setting.json
    1
    2
    3
    4
    "rust-analyzer.server.extraEnv": {
    "RUSTC": "/Users/zealot/.cargo/bin/rustc",
    "RUSTDOC": "/Users/zealot/.cargo/bin/rustdoc"
    }

    重新加载即可。

运行

自第一章起,每一章都是一个可执行的小系统,比如进入01_WAIT_FOREVER目录,即可执行make qemu来编译,并在虚拟环境中运行内核。

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×