Bootloader
Bootloader作为最早执行的代码,职责是进行平台相关的设置,为Kernel创造运行环境。某种意义上,Kernel是Bootloader的用户程序。
- 第一版中使用GRUB,它可以完成从磁盘加载内核代码,及进入32位保护模式的工作,并以multiboot2格式提供必要信息。剩余部分Boot代码,完成进入64位long mode的工作,它和kernel共存于同一个Rust项目中,使用nasm编译。整个构建流程需要依赖很多Rust工具链以外的程序。
- 第二版中抛弃了GRUB,作者用Rust和汇编从头写了一个bootloader,从磁盘加载内核代码,进入64位long mode,并根据kernel elf设置好页表,以自定义格式向kernel提供信息。整个bootloader作为一个独立项目存在。此外作者还写了bootimage工具,用来编译kernel并和bootloader打包在一起生成bin,统一了构建流程。
RustOS for x86_64此前一直在使用第一版的boot流程,直到2018.09.12才迁移到bootimage工具链。此次改动后,配置开发环境的难度大大降低(尤其对macOS),Boot和Kernel也实现了分离。
至于RISCV,参考ucore的做法使用Berkeley bootloader(BBL),作为M态运行环境,而Kernel运行在S态。目前BBL直接借用ucore中的C代码,以后也许可以仿照x86_64的做法,编写Rust版本的bootloader。
哦对了,如果要跑在我们自己写的RV32I CPU上的话,只需有一个极小的bootloader。
执行过程:
- GRUB识别multiboot_header,从磁盘中加载内核到内存,进入32位保护模式
- boot.asm:加载GDT,构造初始页表并开启页机制
- long_mode_init.asm:进入64位long mode,设置rsp寄存器,跳转到Rust代码
多核启动过程:
- entryother.asm:依次 从16位->32位->64位,开启页机制,跳转到Rust代码(借用自xv6)
- 上述多核boot代码被放置到0x7000,在第一个核启动后,通过lapic向其它核发送信号,让它们从0x7000开始执行。
具体可参考博客第一版前两篇文章:
执行过程,分为三阶段:
- 1.boot.s:从0x7c00起<512B的代码,被BIOS放入内存后执行。工作是进入保护模式,从磁盘中加载bootloader剩余代码到内存。
- 2.second_stage.s:将磁盘中的kernel(elf格式文件)加载到内存(0x400000),设置初始页表,开启页机制,进 入64位long mode。
- 3.main.rs:解析elf文件并在页表中建立映射。写入BootInfo信息,跳转到kernel入口点。
目前此bootloader尚无官方文档☹️
bbl位于
riscv-pk
文件夹,相比官方仓库,经过了精简和修改。bbl除了作为Bootloader,还提供M态运行环境,S态的Kernel可通过系统调用ecall使用bbl的服务,包括读写串口、CPU核间通信等。
- 精简bootloader?
- 向x86_64 bootloader中加入多核启动功能
- 在RISCV中加入多核启动功能
Last modified 4yr ago