移动 /boot,如何更新 grub 以找到新位置 /boot/grub2/i386-pc/{core,boot}.img

移动 /boot,如何更新 grub 以找到新位置 /boot/grub2/i386-pc/{core,boot}.img

Grub2 系统硬编码 stage2 文件的位置。此信息存储在引导加载程序分区中。我知道 grub-install 会写这个以及更多。

我的问题是 grub2-install 如何确定 /boot 目录(它自己的分区)所在的位置。 grub-mkconfig 可以解决这个问题,但是,grub-install 似乎没有调用 grub-mkconfig。

我真的很想深入解释这是如何解决的。

底线问题是:“当 /boot 的位置发生更改时,更新 mbr/bios-boot 分区中的引导加载程序代码的正确方法是什么”?

官方文档或维基百科的指针将不胜感激。

答案1

您混淆了 GRUB Legacy 和 GRUB2 术语。术语“stage2”仅适用于 GRUB Legacy(即版本 0.9x)。但我想我明白你的意思。

i386-pcGRUB 版本安装到 MBR 以及 MBR 和第一个分区之间的间隙或安装到 BIOS 引导分区时,这些/boot/grub2/i386-pc/{core,boot}.img文件仅由 所使用grub2-install,而不是由实际引导过程使用。

由于i386-pcGRUB 架构上的操作系统没有可靠的方法来获取有关 BIOS 在引导时最后如何看到磁盘排序的信息,因此grub-install如果配置为依赖 BIOS 磁盘支持(通常的方式),则在安装时基本上有两个可用选项:

  • 如果/boot/grub[2]/device.map已提供文件,请使用其中的信息将操作系统设备映射到 GRUB 设备名称(这将直接对应于 BIOS 磁盘编号)
  • 如果该device.map文件不可用,请大胆猜测当前操作系统磁盘顺序与 BIOS 磁盘检测顺序相同。这个猜测可能正确,也可能不正确。

(具体来说,当从 USB 运行安装程序或实时媒体时,通常会将 USB 存储设备检测为第一个“磁盘”;这可以消除 的猜测grub-install,因为一旦安装的操作系统自行启动, USB 存储的 BIOS 级磁盘模拟将不再存在,因为此时 BIOS 不会从 USB 介质启动。)

嵌入实际 MBR 块中的 GRUB 引导代码包含两条同时写入其中的信息grub-install:引导驱动器号和 GRUB 接下来应读取的 LBA 块号。在现代版本的 GRUB 中,驱动器号通常编码为0xff,意思是“使用用于读取 MBR 的相同磁盘 BIOS”。

当在 MBR 分区磁盘上时,LBA 块号通常为0x0000000000000001,指向 MBR 和第一个分区之间的间隙。在 MBR 分区磁盘上,GRUB 核心映像的其余部分、基本模块和前缀字符串(将指向目录位置/boot/grub)将嵌入其中。在 GPT 分区磁盘上,所有这些都将被写入分区bios-boot,并且实际 MBR 引导代码中嵌入的 LBA 块号将更高,因为它将指向分区的开头bios-boot

嵌入代码的第一个块包括一个块列表,用于标识接下来要读取哪些块:当嵌入到 MBR 分区磁盘时,这将是从 LBA 块 #2 开始的一系列连续块。本系列的长度主要取决于与 GRUB 核心映像一起嵌入的基本模块的数量和类型。大多数嵌入代码将被 LZMA 压缩,然后使用 Reed-Solomon 纠错码进行保护,因此修改它通常会迫使您从本质上重写整个代码。不幸的是,标识目录位置的前缀字符串/boot/grub[2]肯定会在压缩部分内。

在现代系统上,MBR 和第一个分区的开头之间的间隙通常正好是 2047 个块,以将第一个分区对齐到磁盘中的 1 MiB 处。但是较旧的系统可能已使用fdisk不关心数据对齐的版本进行分区,而是尝试保持 DOS 兼容性,将分区的开头定位在磁盘磁道的开头(尽管经典的 C/H/S 磁盘几何结构具有长期以来只是由磁盘固件维护的虚构)。在这些情况下,MBR 和第一个分区的开头之间的间隙可能要小得多。因此,为了最大限度地提高兼容性,需要grub-install将绝对最少数量的基本 GRUB 模块与核心映像一起嵌入,以最大限度地减少嵌入代码的大小。对于因 PC 硬件和 BIOS 实施而产生的其他相关限制,请参阅 GRUB 文档i386-pc在这方面被认为是“严重受限的平台”。

在基于 MBR 的磁盘上进行简单的 RedHat/Debian 安装时,作为/boot磁盘上第一个分区的单独分区,典型的嵌入式模块集如下:

  • biosdisk.mod使用 BIOS 功能进行磁盘访问
  • part_msdos.mod了解MBR分区表
  • /boot支持分区的文件系统所需的任何模块

至少(如果/boot分区初始化为 ext2 文件系统),ext2 文件系统支持所需的 GRUB 模块将为ext2.modfshelp.mod。这是一种实用的配置,可能会产生现代 GRUB 架构可实现的最小嵌入式代码大小之一i386-pc

/grub如果 GRUB 目录在单独的文件系统上命名/boot,并且/boot是磁盘上的第一个分区,则嵌入的前缀字符串通常为(,msdos1)/grub.请注意,GRUB 磁盘标识符丢失:这意味着“使用 BIOS 从中读取 MBR 的同一磁盘”。表示msdos1磁盘上的第一个 MBR 样式分区,只是从文件系统根目录开始的目录/grub路径。/boot/grub/boot

因此,仅使用嵌入在 MBR 间隙或 BIOS 引导分区中的代码,GRUB 将能够使用 BIOS 读取normal.mod磁盘(,msdos1)/grub/i386-pc/normal.mod支持和文件系统元数据,以找到正确的块。之后,将分别读取配置文件(,msdos1)/grub/grub.cfg

还可以将 例如ahci.modsearch_fs_uuid.mod与 GRUB 核心映像一起嵌入,以使 GRUB 能够直接访问 AHCI SATA 控制器并通过 UUID 识别正确的分区/文件系统,但其ahci.mod大小超过 3 倍biosdisk.mod,这使得命中图像大小更有可能受到限制。

当 /boot 的位置发生更改时,更新 mbr/bios-boot 分区中的引导加载程序代码的正确方法是什么?

唯一实际的答案是“通过再次运行来重写嵌入式引导加载程序代码grub[2]-install”。执行此操作时,请确保已将新/boot安装为/boot,如有必要,请提供/boot/grub/device.map包含适合系统配置内容的文件在下次启动时。

在 Debian 以及 Ubuntu 和 Mint 等衍生产品上,包管理系统会记住 GRUB 版本的安装目标设备i386-pc。您可以使用 查看此信息sudo debconf-show grub-pc,并使用 进行更新sudo dpkg-reconfigure grub-pc

RedHat 的包装中似乎没有类似的功能。

RedHat 及其衍生产品不会升级嵌入式引导代码。

作为比较,在x86_64-efiGRUB 架构上,通常没有大小限制来阻止您嵌入所有可用的 GRUB 模块grubx64.efi文件中,生成一个可以进行安全启动签名的 UEFI 二进制文件,并且永远不需要加载任何可执行代码来实现额外的功能。实际上,这保证了只要系统可以读取,即使目录被完全破坏,grubx64.efi所有 GRUB 正常模式命令行功能都将可用。/boot/grub[2]

相关内容