boot.md 3.2 KB

启动加载阶段

MBR 阶段

BIOS 从磁盘的第一个扇区加载 MBR(Master Boot Record)到内存地址 0x7C00 并执行。MBR 代码会设置段寄存器并切换到保护模式。

首先 MBR 代码通过 BIOS 中断 0x15 获取内存信息,并保存到内存中。具体操作包括调用 e820 内存检测功能,获取内存布局信息。这一步骤确保之后系统能够正确识别和利用所有可用的物理内存。然后设置32位的 GDT 并加载到 GDTR 寄存器中。之后会通过 BIOS 中断读取 Stage1 的一小段代码到内存中,然后用ljmp指令跳转到 Stage1 执行,同时开启保护模式。通过这些操作,系统从实模式切换到保护模式,为后续的内存管理和多任务处理提供基础。

Stage1

MBR 代码使用 BIOS 功能从磁盘读取 Stage1 到内存地址 0x1000 并跳转执行。Stage1 代码使用刚才 MBR 中初始化的那个临时栈,并通过 BIOS 中断读取磁盘中的内核镜像(分成了多个 32K 块),并将其复制到内存中的指定位置。

然后,Stage1 代码设置分页结构并启用分页。具体操作包括设置内核的 PML4、PDPT、PD和 PT 表项,并启用 CR0 寄存器中的分页位。分页机制的启用使得系统能够管理虚拟内存,并提供内存保护和隔离功能。再之后,Stage1 会初始化 64位模式使用的 GDT 和设置 IDT(中断描述符表),然后将其加载。通过这些操作,Stage1 确保了内核在进入保护模式后能够正确运行,并为内核的初始化提供了必要的环境。此时,Stage1 代码跳转到内核 64 位模式的入口,正式进入 64 位模式运行。

下一步初始化

内核代码初始化内存管理、CPU 状态、多处理器支持及启动调度器等。具体操作包括设置真正的内核页表、保存内存信息、初始化 buddy 系统等。

内核初始化过程中,首先进入 C++ 中的 kinit.cpp,设置真正的内核页表,确保内核地址空间的正确映射。接着,通过保存从 Stage1 获取的内存信息,包括内存大小和 e820 内存布局信息。然后,调用 setup_buddy 函数初始化伙伴系统,管理物理内存的分配。然后进入 Rust 中的内核初始化阶段。

在 Rust 中的内核初始化阶段,首先调用 init_thiscpu 函数初始化当前 CPU 的状态,包括设置 GDT 和 TSS。接着,初始化中断控制器和定时器。然后,初始化多任务处理系统,包括创建调度器和空闲任务。接下来,挂载文件系统,并加载 init 进程。init 进程是一个 init 脚本,使用 busybox 运行,用于配置文件系统环境并且启动真正的用户 init进程。最后,内核进入正常运行状态,准备处理用户请求和执行应用程序。整个过程确保内核从启动到运行的过程顺利进行,并为后续的操作系统功能提供基础。

还需要做的改进

我们希望实现多平台多架构兼容,但是启动的这个位置我们还没有做多平台共通的接口。一个想法是可以将所有这些 bootstrap 用的代码都放到 arch 中,在一系列的初始化操作都完成以后,再将控制权交给共通部分的函数处。这个实现正在完成过程当中。