BIOS会在启动时,检查逻辑0扇区(即硬盘的第一个扇区)的结尾是否存在标志 0x55
, 0xaa
,以此判断该扇区是否可引导。按照传统的MBR(Master Boot Record)引导流程,逻辑0扇区包含一个特殊的引导程序。这个程序的任务是检查位于逻辑0扇区偏移 0x1BE
处的分区表。分区表最多可以记录四个分区,这也是为什么 MBR 分区的硬盘只能有四个主分区的原因。
在分区表中,每个分区可以有一个“可引导”标记。MBR引导程序会根据某种规则选取一个被标记为“可引导”的分区,将该分区的第一个扇区(称为VBR,Volume Boot Record)加载到内存中(一般加载到地址 0x7C00
以保证兼容性)。随后,程序跳转到VBR,由VBR负责加载并启动该分区中的操作系统。
然而,MBR和VBR的大小都仅有一个扇区,也就是512字节,这对稍微复杂的引导程序来说已经不够用。此外,在16位实模式下,CPU的寻址范围最大只有1MB(实际可用空间还小于1MB,需考虑BIOS和其他数据占用)。因此,对于体积超过1MB或需要加载到1MB以上地址的内核文件,MBR和VBR的能力不足。
切换到保护模式虽然可以突破1MB寻址范围的限制,但由于仅实模式支持调用BIOS功能,在保护模式下无法直接调用BIOS来实现硬盘驱动和文件系统管理。这就需要自行实现这些功能,极大地增加了引导程序的复杂度。为了避免在引导内再实现一边磁盘驱动和文件系统,我选择了使用GRUB。
在GRUB中,将被称为stage1.5
阶段的GRUB核心加载器(从磁盘启动是diskboot
,从光盘是cdboot
等等)存放在存放磁盘中的某个空闲空间(默认是MBR后的一个扇区),一个定制的MBR引导程序(如 boot.S
,编译后生成 boot.img
)负责加载这一阶段的程序到内存中。
这时候就又出现一个问题,怎么存放GRUB核心呢?GRUB提供了两种方式:
core.img
写入硬盘上未被分区表划分的空闲空间。core.img
被当作一个普通文件存储在文件系统中,由MBR程序加载到内存中。core.img
如果采用基于文件系统的方式,问题在于MBR程序如何知道 core.img
的具体位置。GRUB 的core.img
是通过grub-mkimage
命令生成的,它由多个部分组成,包括:
core.img
的第一部分,大小为一个扇区。grub-core
,以支持压缩后的存储形式。当执行 grub-install
时,工具会自动将 diskboot
的位置写入 boot.img
中。diskboot
的末尾包含一个 blocklist
,用于记录 grub-core
的各个部分在磁盘上的位置。这样,diskboot
可以顺利加载完整的 grub-core
。
综上,GRUB 2 的启动流程如下:
boot.img
),运行其中的引导程序。diskboot
。diskboot
根据 blocklist
读取并加载 grub-core
,必要时解压。grub-core
最终加载目标操作系统的内核文件,并完成引导。稍微深入了解过GRUB后,感觉像是迷你内核一样,功能这么丰富。