rCore OS 学习笔记

用的书:

https://rcore-os.github.io/rCore-Tutorial-Book-v3/index.html

本人从未学过 rust 语言,所以就硬上。

开发环境搭建

官网文档有问题。得 apt install python3-pip python3-serial

另外 make run 编译失败:

解决方法:此处 (注意修改完要 commit)

基本执行环境

创建可执行应用包:

cargo new os --bin

编译运行:

cargo run

strace 工具:运行一个程序,并输出过程中向内核请求的所有系统调用、返回值。

pluveto on devhost0com in ~/osmy/os(18886d15h5m|master*)
$ strace ./target/debug/os 
execve("./target/debug/os", ["./target/debug/os"], 0x7fff7ebfa4e0 /* 64 vars */) = 0
...
write(1, "Hello, world!\n", 14Hello, world!
)         = 14
sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
munmap(0x7fb4c82d2000, 12288)           = 0
exit_group(0)                           = ?
+++ exited with 0 +++

编译时指定目标三元组:

 cargo run --target riscv64gc-unknown-none-elf

或者使用配置文件 .cargo/config

core 库:Rust 有一个对 Rust 语言标准库–std 裁剪过后的 Rust 语言核心库 core,它不需要操作系统提供支持就可以使用。

裸机启动过程

  1. 开机
  2. PC 寄存器会指向 0x1000
  3. 0x1000 的代码控制跳转到 0x80000000 处,即 BootLoader 程序–RustSBI
  4. RustSBI 完成基本的硬件初始化后, 会跳转操作系统的二进制代码 $(KERNEL_BIN) 所在内存位置 0x80200000 ,执行操作系统的第一条指令

现行通用的多阶段引导模型为:

ROM -> LOADER -> RUNTIME -> BOOTLOADER -> OS

Loader 要干的事情,就是内存初始化,以及加载 Runtime 和 BootLoader 程序。而 Loader 自己也是一段程序,常见的 Loader 就包括 BIOS 和 UEFI,后者是前者的继任者。

@denglj

RISCV-SBI 仓库:riscv-non-isa/riscv-sbi-doc: Documentation for the RISC-V Supervisor Binary Interface (github.com)

OpenSBI 仓库:riscv-software-src/opensbi: RISC-V Open Source Supervisor Binary Interface (github.com)

RISCV 的运行模式:M 模式,S 模式,U 模式。(Machine,Supervisor,User)

机器模式(M-mode):最高权限模式。最重要的特性是拦截和处理异常(不寻常的运行时事件)的能力

  • 一类是同步异常,这类异常在指令执行期间产生,如访问了无效的存储器 地址或执行了具有无效操作码的指令时。
  • 另一类是中断,它是与指令流异步的外部事件, 比如鼠标的单击。

在 M 模式运行期间可能发生的同步例外有五种:

  • 访问错误异常 当物理内存的地址不支持访问类型时发生(例如尝试写入 ROM)。

  • 断点异常 在执行 ebreak 指令,或者地址或数据与调试触发器匹配时发生。

  • 环境调用异常 在执行 ecall 指令时发生。

  • 非法指令异常 在译码阶段发现无效操作码时发生。

  • 非对齐地址异常 在有效地址不能被访问大小整除时发生,例如地址为 0x12 的 amoadd.w。

有三种标准的中断源:软件、时钟和外部来源。

八个控制状态寄存器(CSR)是机器模式下异常处理的必要部分:

  • mtvec(Machine Trap Vector)它保存发生异常时处理器需要跳转到的地址。
  • mepc(Machine Exception PC)它指向发生异常的指令。
  • mcause(Machine Exception Cause)它指示发生异常的种类。
  • mie(Machine Interrupt Enable)它指出处理器目前能处理和必须忽略的中断。
  • mip(Machine Interrupt Pending)它列出目前正准备处理的中断。
  • mtval(Machine Trap Value)它保存了陷入(trap)的附加信息:地址异常中出错的地址、发生非法指令异常的指令本身,对于其他异常,它的值为 0。
  • mscratch(Machine Scratch)它暂时存放一个字大小的数据。
    • 为避免覆盖整数寄存器中的内容,中断处理程序先在最开始用 mscratch 和整数寄存器(例如 a0)中的值交换。
    • 通常,软件会让 mscratch 包含指向附加临时内存空间的指针,处理程序用该指针来保存其主体中将会用到的整数寄存器。
  • mstatus(Machine Status)它保存全局中断使能,以及许多其他的状态。

当一个 hart 发生异常时,硬件自动经历如下的状态转换:

  • 异常指令的 PC 被保存在 mepc 中,PC 被设置为 mtvec (对于同步异常,mepc 指向导致异常的指令;对于中断,它指向中断处理后应该恢复执行的位置)
  • 根据异常来源设置 mcause,并将 mtval 设置为出错的地址或者其它适用于特定异常的信息字。
  • 把控制状态寄存器 mstatus 中的 MIE 位置零以禁用中断,并把先前的 MIE 值保留到 MPIE 中。
  • 发生异常之前的权限模式保留在 mstatus 的 MPP 域中,再把权限模式更改为 M (如果处理器仅实现 M 模式,则有效地跳过这个步骤)

llvm_asm 宏

llvm_asm!(assembly template
   : output operands
   : input operands
   : clobbers
   : options
   );

需要先 #![feature (llvm_asm)]

为什么要清空 .bss

bbs 主要记录未初始化和初始化为 0 的全局(static 修饰的局部)变量的位置,而不会记录其具体数据,因为这部分的数值会默认设置为 0

如果这块区域不是全零,且执行环境也没提前清零,那么会与应用的假定矛盾,导致程序出错。