> For the complete documentation index, see [llms.txt](https://rcore.gitbook.io/rust-os-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://rcore.gitbook.io/rust-os-docs/bootloader.md).

# Bootloader

## 简介

Bootloader作为最早执行的代码，职责是进行平台相关的设置，为Kernel创造运行环境。某种意义上，**Kernel是Bootloader的用户程序**。

RustOS开发之初，借用的是《[Writing an OS in Rust](https://os.phil-opp.com/second-edition/)》第一版的代码，而现在作者已经推出了第二版，第一版不再维护。两个版本的Bootloader有很大不同：

* 第一版中使用GRUB，它可以完成从磁盘加载内核代码，及进入32位保护模式的工作，并以multiboot2格式提供必要信息。剩余部分Boot代码，完成进入64位long mode的工作，它和kernel共存于同一个Rust项目中，使用nasm编译。整个构建流程需要依赖很多Rust工具链以外的程序。
* 第二版中抛弃了GRUB，作者用Rust和汇编从头写了一个[bootloader](https://github.com/rust-osdev/bootloader)，从磁盘加载内核代码，进入64位long mode，并根据kernel elf设置好页表，以自定义格式向kernel提供信息。整个bootloader作为一个独立项目存在。此外作者还写了[bootimage](https://github.com/rust-osdev/bootimage)工具，用来编译kernel并和bootloader打包在一起生成bin，统一了构建流程。

RustOS for x86\_64此前一直在使用第一版的boot流程，直到2018.09.12才迁移到bootimage工具链。此次改动后，配置开发环境的难度大大降低（尤其对macOS），Boot和Kernel也实现了分离。

至于RISCV，参考[ucore](https://ring00.github.io/bbl-ucore/)的做法使用[Berkeley bootloader(BBL)](https://github.com/riscv/riscv-pk)，作为M态运行环境，而Kernel运行在S态。目前BBL直接借用ucore中的C代码，以后也许可以仿照x86\_64的做法，编写Rust版本的bootloader。

哦对了，如果要跑在我们自己写的RV32I CPU上的话，只需有一个极小的bootloader。

## 代码及运行过程

### x86\_64 第一版（已废弃）

[代码在此](https://github.com/wangrunji0408/RustOS/tree/32b335adc01114e94e4c262bcdc6cc40a05f418c/kernel/src/arch/x86_64/boot)

执行过程：

* 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开始执行。

具体可参考博客第一版前两篇文章：

* [A minimal Multiboot Kernel](https://os.phil-opp.com/multiboot-kernel/)
* [Entering Long Mode](https://os.phil-opp.com/entering-longmode/)

### x86\_64 第二版

[官方仓库](https://github.com/rust-osdev/bootloader)

执行过程，分为三阶段：

1. boot.s：从0x7c00起<512B的代码，被BIOS放入内存后执行。工作是进入保护模式，从磁盘中加载bootloader剩余代码到内存。
2. second\_stage.s：将磁盘中的kernel（elf格式文件）加载到内存（0x400000），设置初始页表，开启页机制，进入64位long mode。
3. main.rs：解析elf文件并在页表中建立映射。写入BootInfo信息，跳转到kernel入口点。

目前此bootloader尚无官方文档☹️

### RISCV for QEMU

bbl位于 `riscv-pk`文件夹，相比官方仓库，经过了精简和修改。

bbl执行完毕后，跳转到固定地址（0x80020000），[代码在此](https://github.com/wangrunji0408/RustOS/blob/master/kernel/src/arch/riscv32/boot/entry.asm)，之后仅需设置sp寄存器，然后跳转到Rust代码。

bbl除了作为Bootloader，还提供M态运行环境，S态的Kernel可通过系统调用ecall使用bbl的服务，包括读写串口、CPU核间通信等。

### RISCV for FPGA

[一个极小bootloader](https://github.com/wangrunji0408/RustOS/blob/master/kernel/src/arch/riscv32/boot/boot.asm)，代替bbl。

## TODO

* [ ] 精简bootloader？
* [x] 向x86\_64 bootloader中加入多核启动功能
* [x] 在RISCV中加入多核启动功能
