这一章的主要内容是从零创建一个能够在riscv上正确启动并退出的内核框架,增加的文件如下,下面逐个解释
.
├── bootloader
│ └── rustsbi-qemu.bin
├── os
│ ├── .cargo
│ │ └── config
│ ├── Cargo.toml
│ ├── Makefile
│ └── src
│ ├── console.rs
│ ├── entry.asm
│ ├── lang_items.rs
│ ├── linker.ld
│ ├── logging.rs
│ ├── main.rs
│ └── sbi.rs
└── .vscode
└── settings.json
除了环境中需要安装rust工具链和qemu,项目中还需要相应的配置:
os/.cargo/config
文件用于设置默认的编译目标和编译选项.vscode/settings.json
文件用于设置rust-analyzer
插件使其能够按照同样的编译目标运行 issue
特权层二进制接口(SBI)是RISC-V平台下引导程序环境的规范。它提供了特权层的运行环境,使得特权层软件能使用环境调用指令,来执行平台相关的操作。典型的的特权层接口应用有:一、类似于Unix的操作系统中,机器级和特权级的访问接口;二、监视特权级和虚拟特权级中,作为虚拟化环境的调用接口。
FROM: wikipedia
SBI是操作系统的引导程序和运行时。机器上电时,SBI将配置环境,准备设备树,最终将引导启动操作系统。 操作系统需要访问硬件或者特殊的功能,这时候就需要通过ecall指令陷入M层的SBI运行时,由SBI完成这些功能再提供。 SBI的实现体现了RISC-V层级和模块化的开发特点,我们可以方便地更换SBI实现,无需重装操作系统,就能支持M层不同的功能, 比如无盘机、网络启动和管理等等,都是更高级的SBI实现能完成的。FROM: luojia65
也可以说是bios?
rustsbi是rust语言的sbi实现,而rustsbi-qemu则是qemu平台的rustsbi实现。
因为前两天rustsbi-qemu更新了但没有release所以需要自己编译,编译生成的rustsbi-qemu.bin
放到bootloader
文件夹。
os/src/sbi.rs
文件提供了操作系统调用sbi的函数封装,内容就是通过内嵌汇编执行ecall
linker script决定了可执行映像(image)的链接方式,以及各个段的装载地址(装载域)和执行地址(运行域)。
linker.ld
文件用于调整入口地址和段排布以和rustsbi的保持一致,重点是入口地址0x80200000
。
在加入这个文件而没有下一节的文件时编译结果是空文件而非实验指导书所描述的因未设置栈而跑飞,已有类似提问
global_asm!宏用于引入外部asm文件而非内嵌脚本
由该宏引入的entry.asm
文件定义了两个段,对应上一节的ld文件内容:
.text.entry
是主函数入口,在设置了栈指针后即跳至rust语言编写的入口,真正进入“主函数”.bss.stack
是一个64kb的栈
extern关键字用于定义外部函数接口,但这一章用extern定义的都并非一般意义上的“外部函数”,而是在ld文件中定义的各个段的地址符号,在使用时也是当作地址值而非函数入口使用的。
HOWEVER.
I do think that the "run-time failure panic" is a fundamental issue.
FROM: Linus Torvalds
rust中的panic代表了不可恢复错误,用户态默认的panic handler是展开堆栈至退出或直接退出。然而作为操作系统,理应尽可能不产生不可恢复错误,但如果出现了又该怎么处理呢?好像也只有死循环或关机两种选择,否则又怎么会叫做不可恢复错误呢。
本章实现的panic handler并不是尝试恢复错误或减小损失,而是在打印错误信息后直接关机,主要作用除了多一个打印错误信息的逻辑还有使panic!、unreachable!等panic宏可用。
console.rs
文件定义了几个与标准库表现一致的标准输出函数及宏,通过调用sbi puchar实现逐字符输出。是否有性能问题?
logging.rs
文件通过log crate
定义了五个级别的彩色字符串日志输出