|
本帖最后由 不点 于 2024-12-27 20:53 编辑
有不少人问 grub4dos for legacy BIOS 下的 map --hook 的问题。
下面通过一个菜单实例,来理解 map --hook 的必要性。
title find and load NTLDR of Windows NT/2K/XP\n find and load NTLDR of Windows NT/2K/XP
find --set-root --ignore-floppies --ignore-cd /ntldr
map () (hd0)
map (hd0) ()
map --hook
find --set-root --ignore-floppies --ignore-cd /ntldr
rootnoverify (hd0) —— 这句添乱了,不该有这句。请看后文解释。
chainloader /ntldr
boot
下面详细解释每一句的作用。
find --set-root --ignore-floppies --ignore-cd /ntldr ——————这一句是确定当前默认的工作设备(也就是 root 设备)。找到含有 /ntldr 文件的那个设备,就把它设定为当前工作设备。假定这条 find 命令找到了 (hd2,3),并把当前 root 设定为 (hd2,3) 了。
map () (hd0) —————— 将当前默认设备所在的 BIOS 盘号映射为 “第一硬盘”。相当于执行 map (hd2) (hd0)
map (hd0) () —————— 将“第一硬盘”映射为当前默认设备所在的 BIOS 盘号。相当于执行 map (hd0) (hd2)
map --hook —————— 让前面的 map 生效。如果没有 map --hook,前面的 map 都只是一个 “暗示”,并未真正起效。如果没有 map --hook,此时你在 grub4dos 低下就会发现,hd0 的内容还是原先的 hd0 的内容;同样,hd2 的内容,也依旧是原先 hd2 的内容,也就是说,hd0 与 hd2 没有进行互换。 执行了 map --hook 以后,你会发现,两者确实互换了:hd0 的内容是原先 hd2 的内容,而 hd2 的内容是原先 hd0 的内容。
find --set-root --ignore-floppies --ignore-cd /ntldr —————— 两个盘号互换以后,需要再次查找 /ntldr 文件,并确定新的当前默认设备是哪个设备。既然已经互换了,那么,此时它找到的,就应该是 (hd0,3) 了,于是,(hd0,3) 就被设定为当前 root 设备了。
rootnoverify (hd0) —————— 这一句放在这里是错误的,此时不该有这句。如果没有这一句,此时当前root设备就是 (hd0,3)。而有了这一句,当前 root 设备变成 (hd0)——代表整个硬盘,而不是代表分区 (hd0,3)——那么,接下来的 chainloader /ntldr 就会因 “找不到 /ntldr 文件” 而失败。
chainloader /ntldr —————— 这一句是加载当前 root 设备的 /ntldr 文件,把它当作引导扇区代码。
boot —————— 这一句,首先是根据 “当前 root 为 (hd0,3)” 来设定 CPU 的 DL 寄存器的值为 0x80,然后把控制权交给前面已经加载的引导扇区代码。
【补充】第二条 find 命令的作用,就是在交换两个盘号之后,把 root 设备也进行相应的“更新”。比如,原来的 ntldr 是在 (hd2,3) 上,交换盘号之后,它就是在 (hd0,3) 上了。
然而,我们已经在第一次执行 find 命令时,找到了这个分区,(比如说)它就是 (hd2,3)。此时我们可以考虑“偷懒”,不再执行 find 命令,而是仅仅把当前 root 设备的设定,从 (hd2,3) 变更到 (hd0,3) 即可。
好的,我们就是想要让这第二条 find 命令不再执行了。
此时,我们心里明白,当前 root 设备依旧是 (hd2,3)。我们同时也知道,此时 ntldr 已经位于新的 (hd0,3) 上了。那么,我们就需要让 (hd0,3) 成为当前 root 设备。因此,执行 root (hd0,3) 就可以了。然而,如果我们直接执行 root (hd0,3),这就不具有通用性了(因为分区号 3 是写死的,不能适应别的情况)。好在我们有个巧招,就是,执行 root (hd0,) 即可。此处,我们省略了分区号 3(然而要注意,逗号不可以省略——如果没有逗号,那就代表整个硬盘 hd0 了,而不是代表一个分区)。一般来说,grub4dos 发现了省略的分区号,就会用当前 root 设备的分区号来(自动)填补。所以,(hd0,) 就等价于 (hd0,3)。而我们执行 root (hd0,) 就具有通用性了。也就是说,这第二条 find 命令,可以用一条 root (hd0,) 命令来完美取代。这种“偷懒”能够减少一次 find 命令的执行,应该算是合理的吧?
【再补充】上述菜单示例中的 map --hook 调整为 map --rehook 更好一些。当 map 项目不存在时,map --hook 命令会报错,无法执行。换用 map --rehook 命令,就会忽略错误,继续执行。
总的来说,菜单改成下面这样,更完美一些:
title find and load NTLDR of Windows NT/2K/XP\n find and load NTLDR of Windows NT/2K/XP
find --set-root --ignore-floppies --ignore-cd /ntldr
map () (hd0)
map (hd0) ()
map --rehook
root (hd0,)
chainloader /ntldr
boot
这样更改以后,也能够适应当 find 找到的是 (hd0,x) 的情况。详细解释一下。
find --set-root --ignore-floppies --ignore-cd /ntldr —— 假定找到了 (hd0,3) 上的 ntldr,设定 root 为 (hd0,3)
map () (hd0) —— 相当于执行 map (hd0) (hd0),把 hd0 映射成自己,也就是撤销对 hd0 的映射项目。
map (hd0) () —— 也相当于执行 map (hd0) (hd0),把 hd0 映射成自己,也就是撤销对 hd0 的映射项目。
map --rehook —— 此时由于磁盘映射项目不存在,map --rehook 将不执行任何动作。但如果是 map --hook,则会报错。
root (hd0,) —— 这句也没问题。执行这条命令之前 root 是 (hd0,3),执行后,root 仍然是 (hd0,3)。
chainloader /ntldr —— 加载当前 root 设备根目录下的 ntldr (“引导代码”)到内存。
boot —— 启动前面已经加载的引导代码(递交控制权)。
|
|