我正在尝试让 grub1 与 GPT 一起工作。目前在虚拟机上,作为迁移真实计算机之前的测试步骤。
我已经为/boot
和 另一个分区创建了一个分区,我想在其中嵌入 grub stage1.5。这是 gdisk 显示的 GPT 分区表:
Number Start (sector) End (sector) Size Code Name
1 2048 104447 50.0 MiB 8300 boot
2 104448 206847 50.0 MiB EF00 EFI
3 206848 16984063 8.0 GiB 8E00
4 1024 2047 512.0 KiB EF02 GRUB1
不要理会 EFI 分区,在这种情况下不会使用它。只是我打算稍后将系统升级到UEFI(我知道,告别grub1),想早点创建分区。
现在,由于 grub1 不理解 GPT,我创建了一个混合 MBR,由第 1 和第 4 分区组成。 gdisk 对于混合 MBR 是这么说的:
Number Boot Start Sector End Sector Status Code
1 1 1023 primary 0xEE
2 * 2048 104447 primary 0x83
3 1024 2047 primary 0xEF
4 104448 20971519 primary 0xEE
我的目的是将stage1.5放在1MB以下的小分区上,并在分区boot
(GPT 1/MBR 2)处有真正的引导分区(带有stage2、grub配置和内核映像)。但是我无法让 grub 安装阶段。
grub
运行命令时find /grub/menu.lst
显示(hd0,0)
,所以看起来它正在使用正在运行的内核分区布局,即嵌入分区所在的位置(hd0,3)
。然而给予root (hd0,3)
给了我
文件系统类型未知,分区类型 0x83
文件系统类型并不奇怪,因为分区是空的,但我已经设置了分区类型并且它是不可见的。
当我尝试将 stage1.5 嵌入分区时(使用embed (hd0,0)/grub/e2fs_stage1_5 (hd0,3)
我收到错误:
错误17:无法挂载所选分区
我尝试在该分区上创建 reiserfs3 (因为 reiserfs3 有 16KB 的空间用于嵌入引导加载程序),但错误是相同的。然而,我创建的 FS 是非标准的,日志位于单独的设备上,因为 512KB 不足以创建普通的 FS。
我已经检查过 (hd0,3) 是正确的驱动器,因为向分区的第一个扇区写入一些内容并cat (hd0,3)+1
在 grub shell 中运行会给出预期的输出。
关于如何运行它的任何其他选项?我正在考虑手动将 stage1.5 嵌入到所选分区(cat /boot/grub/e2fs_stage1_5 > /dev/sda4
)中,并对其进行适当修改(我猜测它只是第一个扇区中的阻止列表和第二个扇区中的 stage2 位置),并从那里开始,但我想让它正常工作。
我使用的版本是 Gentoo 的 sys-boot/grub-0.97-r18。
答案1
事实证明,比预想的更容易,也更难。
首先,Gentoo(以及据我所知的许多其他发行版)已经对 Grub 进行了修补,使其能够读取 GPT,因此不需要混合 MBR 的整个麻烦,它可以与纯 GPT 一起使用。
这更容易,因为标准setup (hd0,0)
确实有效,就像“制作可启动系统”一样。然而,按照我的标准,系统不够健壮 - 因为setup
无法将 stage1.5 嵌入到任何地方,所以它求助于修补 stage2 并将其在 MBR 中的磁盘位置包含在内。因此,如果有任何东西移动了 stage2,改变了之前所在的块,我就会得到一个无法启动的系统。更糟糕的是,我可能不会首先注意到它 - 升级将 stage2 移动到不同的位置,但旧的位置保持不变。系统仍在启动,我什么也没注意到。但由于启动期间使用的代码现在是文件系统 POV 中的可用空间,因此稍后会随机覆盖它并繁荣。
因此,我采取了问题末尾概述的步骤,手动嵌入 stage1.5。
首先,复制相应的 stage1.5 文件,然后在该副本上启动十六进制编辑器。如果您手头没有,我已经成功使用 vim 和 xxd - 编辑文件,键入:!xxd<enter>
将文件编辑为十六进制,键入:!xxd -r<enter>
并保存。文件末尾有一个额外的换行符,但它是无害的。请注意,在这种情况下,右侧的 ASCII 部分将被完全忽略,仅使用十六进制数字。您需要在此文件中编辑 3 项内容:
- 放入块号第二将在 offset 处嵌入 stage1.5 的块
0xf8
。请注意,它是小端字节序,并且相对于磁盘的开头。由于 BIOS 引导分区从扇区 1024 开始,因此为 1025 或0x0401
或(以小端字节序表示)字节0104
。 - 将 stage1.5 的 512 字节扇区数减一置于 offset 处
0x1fc
。由于我的 stage1.5 是 9908 字节(9909 加上额外的换行符),它有 20 个扇区(19 个扇区是19*512=9728
10240 字节,20 个扇区是 10240 字节,所以我需要13
在其中放入 19 或十六进制)。 ff
将偏移量 219 处更改为00
.不要触摸ff
附近的 。
以下是原始文件和修改后的文件的十六进制转储的差异:
-000001f0 00 00 00 00 00 00 00 00 02 00 00 00 00 00 20 02 |.............. .|
+000001f0 00 00 00 00 00 00 00 00 01 04 00 00 13 00 20 02 |.............. .|
00000200 ea 70 22 00 00 00 03 02 ff ff ff 00 00 00 00 00 |.p".............|
-00000210 02 00 30 2e 39 37 00 ff ff ff ff 2f 62 6f 6f 74 |..0.97...../boot|
+00000210 02 00 30 2e 39 37 00 ff ff 00 ff 2f 62 6f 6f 74 |..0.97...../boot|
其工作方式是,stage1.5 的第一个扇区从接近末尾处读取数字,并从磁盘开头的指定扇区开始读取那么多扇区。这会将 stage1.5 的剩余扇区加载到内存中,然后执行它们。第三部分实际上是stage2在磁盘上的一个位置,grub需要在这里找到正确的分区。如果有人感兴趣的话,相关代码位于stage2/disk_io.c
grub 的源代码中,只需记住您使用的部分位于 中#ifdef STAGE1_5
,而加载其余部分的第一个扇区位于 中stage2/start.S
。可能有可能在几个不连续的部分中有stage1.5,但我还没有尝试过。
编写修改后的 stage1.5 后,只需将其复制到目标分区(我的示例中的第四个分区),根据您的喜好使用cat
或dd
。
最后,在grub shell中执行
install /boot/grub/stage1 (hd0) (hd0)1024+20
(hd0) 是您正在使用的设备的 grub 名称,1024
是嵌入式 stage1.5 的开始(顺便说一下,BIOS 引导分区的开始),并且20
是 stage1.5 的大小(以块为单位)。这样就完成了整个过程。