OS开发笔记(2)——GRUB启动流程

GRUB如何突破实模式的限制

BIOS与MBR引导机制

BIOS会在启动时,检查逻辑0扇区(即硬盘的第一个扇区)的结尾是否存在标志 0x55, 0xaa,以此判断该扇区是否可引导。按照传统的MBR(Master Boot Record)引导流程,逻辑0扇区包含一个特殊的引导程序。这个程序的任务是检查位于逻辑0扇区偏移 0x1BE 处的分区表。分区表最多可以记录四个分区,这也是为什么 MBR 分区的硬盘只能有四个主分区的原因。

在分区表中,每个分区可以有一个“可引导”标记。MBR引导程序会根据某种规则选取一个被标记为“可引导”的分区,将该分区的第一个扇区(称为VBR,Volume Boot Record)加载到内存中(一般加载到地址 0x7C00 以保证兼容性)。随后,程序跳转到VBR,由VBR负责加载并启动该分区中的操作系统。

MBR和VBR的局限性

然而,MBR和VBR的大小都仅有一个扇区,也就是512字节,这对稍微复杂的引导程序来说已经不够用。此外,在16位实模式下,CPU的寻址范围最大只有1MB(实际可用空间还小于1MB,需考虑BIOS和其他数据占用)。因此,对于体积超过1MB或需要加载到1MB以上地址的内核文件,MBR和VBR的能力不足。

16位的寻址限制

切换到保护模式虽然可以突破1MB寻址范围的限制,但由于仅实模式支持调用BIOS功能,在保护模式下无法直接调用BIOS来实现硬盘驱动和文件系统管理。这就需要自行实现这些功能,极大地增加了引导程序的复杂度。为了避免在引导内再实现一边磁盘驱动和文件系统,我选择了使用GRUB。

GRUB的解决方案

在GRUB中,将被称为stage1.5阶段的GRUB核心加载器(从磁盘启动是diskboot,从光盘是cdboot等等)存放在存放磁盘中的某个空闲空间(默认是MBR后的一个扇区),一个定制的MBR引导程序(如 boot.S,编译后生成 boot.img)负责加载这一阶段的程序到内存中。

这时候就又出现一个问题,怎么存放GRUB核心呢?GRUB提供了两种方式:

  1. 使用磁盘未分配空间
    GRUB将包含核心功能的 core.img 写入硬盘上未被分区表划分的空闲空间。
  2. 基于文件系统引导
    core.img 被当作一个普通文件存储在文件系统中,由MBR程序加载到内存中。

GRUB如何找到core.img

如果采用基于文件系统的方式,问题在于MBR程序如何知道 core.img 的具体位置。GRUB 的core.img 是通过grub-mkimage命令生成的,它由多个部分组成,包括:

  • diskboot:负责从磁盘加载 core.img 的第一部分,大小为一个扇区。
  • decompresser:用于解压 grub-core,以支持压缩后的存储形式。
  • core:核心程序模块,可以根据需要加载各种功能扩展(grub模块)。

当执行 grub-install 时,工具会自动将 diskboot 的位置写入 boot.img 中。diskboot 的末尾包含一个 blocklist,用于记录 grub-core 的各个部分在磁盘上的位置。这样,diskboot 可以顺利加载完整的 grub-core

GRUB的引导过程

综上,GRUB 2 的启动流程如下:

  1. MBR引导
    BIOS 加载 MBR(即 boot.img),运行其中的引导程序。
  2. 加载diskboot
    MBR 程序根据记录的位置加载 diskboot
  3. 加载并解压grub-core
    diskboot 根据 blocklist 读取并加载 grub-core,必要时解压。
  4. 启动操作系统内核
    grub-core 最终加载目标操作系统的内核文件,并完成引导。

感想

稍微深入了解过GRUB后,感觉像是迷你内核一样,功能这么丰富。

posted @ 2024-12-06 23:37  迷路的鹿1202  阅读(15)  评论(0编辑  收藏  举报