引导加载程序实际上如何传递给内核?

引导加载程序实际上如何传递给内核?

假设我有一个带有kernelinitrd线的引导加载程序。出于所有意图和目的,我现在正在进行 2 或 3 个“内核”阶段:

  1. 固件
  2. grub(或其他引导加载程序)
  3. 实际的Linux内核

以上是针对 MBR 的。对于 EFI,引导加载程序(或引导管理器)只是一个 EFI 应用程序,它在固件是“内核”时运行:

  1. 固件,加载 EFI 应用程序
  2. 实际的Linux内核

实际的内核切换过程是什么? MBR grub 实际上做了什么才能从 2 变为 3,或者 EFI 固件从 1 变为 2?它类似于吗kexec

其次,在 EFI 的情况下,一些钩子被传递到 EFI 应用程序,然后传递到 Linux 内核(这样我们就可以做 efibootmgr 等事情),这是如何传递的?

最后,是否可以多次这样做?例如,如果我在加载“常规”操作系统之前需要做一些自定义工作,例如测量和验证 TPM 条目、解密等,也许使用 grub、rEFInd 或其他工具不容易完成的事情,我可以加载“临时”阶段内核和 initrd,执行它们,然后移交?

答案1

一些注释,主要是关于 BIOS/GRUB 系统。

带有 GRUB 的 BIOS 系统:

BIOS 启动时间地址0xfffffff0(x86)。

进行各种测试,例如 POST。如果一切顺利,则按照 CMOS 中配置和保存的顺序检查设备。第一个具有有效 MBR(偏移量 510 处的签名为0x55aa)的引导设备将加载到地址为 的内存中0x7c00

然后 BIOS 将控制权交给从 MBR 的 offset 处加载的代码(字节)0。那是;留下控制的数据应该是处理器指令。一个程序。

例如,如果您查看 MBR 映像,您可能会发现类似于eb6390开头的内容。这翻译成两条机器指令:

eb63 => jump to 0x63 (offset 0x65 in MBR as count is from end of instruction)
90   => No Operation
  • boot.S在 GRUB 源中。汇编中MBR中的第一条指令:

    jmp LOCAL(after_BPB)
    nop
    

从这里开始,GRUB 加载下一阶段。通常第一扇区core.img

  • diskboot.S在正常磁盘引导上的 GRUB 源中。

跳转到此代码,然后加载core.img.这包括例如Reed-Solomon 纠错、解压缩等startup_raw.S。当前的 GRUB 是基于模块的,这些也在这个阶段加载。

GRUB 配置文件被读取等,当它确定要运行哪个内核时,它将它从/boot目录加载到内存中。然后初始 RAM 磁盘映像initrd被加载到内存中。

引导加载程序还将配置字符串的内存地址写入内核内存空间。即启动选项。看标头字段标记的“调整”

另请注意,引导加载程序在加载阶段通常会在实模式和保护模式之间交替。这样能够加载超过 1 MB 限制的数据。

完成此操作后,引导加载程序将控制权交给内核,就像 BIOS 通过 MBR 将控制权留给引导加载程序一样。这是在实模式下完成的。

内核(通常)是基于模块的。例如,这些模块中有文件系统模块。在启动时,内核可能必须从文件系统中读取文件,它需要一个模块来读取……这就是initrd起作用的地方。开始所需的模块位于此处。

(U)EFI:

(U)EFI 启动过程如果使用 uefigrub 安装等,则与 BIOS/GRUB 处于同一轨道。还可以选择使用EFI 引导存根它允许 EFI 固件将内核作为 EFI 可执行文件加载。

更远,从内核 3.14 开始kexec也是可用的,但不适用于冷启动。

相关内容