现在的电脑基本上都是采取UEFI启动了,之前看过一些资料,大抵都讲道“现在UEFI不需要制作引导分区了,系统会自动从EFI分区下的\EFI\Boot\Bootx64.efi
文件启动”,这种说法其实是以偏概全了。导致很多情况下出现了一些奇怪的问题(比如当我准备把操作系统安装到一个移动硬盘上的时候)。
究其错误的原因,从根本上来说是忽略了了主板上NVRAM(非易失性随机访问存储器,主板上自带的一小块配置存储器,不在硬盘上,你把整块硬盘都擦了它还在)中启动配置的存在。
1. 真正的UEFI启动逻辑
def 从EFI文件启动(文件路径): |
所以,总结说来,UEFI并不是单纯地找到启动设备上的EFI分区里的某固定文件路径就启动了,而是会结合NVRAM中的配置来完成整个过程。NVRAM中的启动配置包括一系列启动项和响应的预设优先顺序,Linux下可以用efibootmgr -v
命令查看。它会在以下情况下发生更改:
- 当安装操作系统完成后,操作系统会自动添加一条启动项,如ubuntu会生成一条名为
ubuntu
的项目并指向EFI分区的\EFI\ubuntu\shimx64.efi
文件,而Windows会生成一条名为Windows Boot Manager
的项目指向EFI分区的\EFI\Microsoft\Boot\bootmgfw.efi
文件。 - 在操作系统中通过
efibootmgr
等工具手动修改,使用grub-install
命令时如果没有指定--no-nvram
也会添加一个启动项 - 在BIOS(UEFI不是BIOS,但是习惯上还是管机器的UEFI配置界面叫BIOS)中修改
- 由于Windows用户实在太多了,有的主板生产商会自动为Windows添加启动项(避免小白搞坏配置),甚至强制将其列为第一优先级(这就很恶心了)
- 手动从某个设备成功启动后,硬件可能会自动地将其对应的EFI文件加入启动项(因硬件而异)
- 硬件检测到不存在的设备/文件,自动删除启动项(因硬件而异)
- ……
总之这个NVRAM中的启动项配置的编辑策略各不相同,甚至不排除可能有的主板出于安全(恰烂钱)考虑拒绝你对它进行编辑,强制你从Windows启动,所以需要根据自己的电脑自行实验。一般来说,台式机自由度比较大,绝大多数都是允许你自行编辑的,且不会强制更改你自定义优先级;而高端或者新的笔记本也和台式机差不多,但是又老又旧的笔记本的坑就比较多了。
因此,到这里就可以解释如下现象了:
为啥删除了EFI分区下的
\EFI\BOOT
目录也还能正常启动?因为NVRAM中的启动项配置直接指向
\EFI\ubuntu
或者\EFI\microsoft
目录,不依赖于\EFI\BOOT
,\EFI\BOOT
下的东西只在直接从该设备启动时生效,相当于作为一个后备。为啥换了主板后就只能从Windows启动了?
NVRAM在主板上,换了后自然全没了,剩下Windows是因为前面说的有的主板为了方便小白使用自动探测Windows启动项的存在并添加之,Linux就没福气了,这可以需要通过引导盘进入Live环境后用
efibootmgr
修复。为什么安装Linux后安装Windows,无法进入Linux(Grub)?
还是能进入的,只不过Windows把自己设置成了第一优先级,默认直接进Windows;所以一般先装Windows再装Linux,这样Linux把自己设置成第一优先级,可以在Grub界面二选一。不过其实这都是小问题,改一下NVRAM配置就行,并不是很多教程说的必须先装Windows,没那么死板。
2. 关于安全启动(SecureBoot)
所有教你安装Ubuntu之前关闭SecureBoot的教程可以一律拉黑
2020年了,Ubuntu它早就向微软购买了安全启动认证密钥,所以它的\EFI\ubuntu\shimx64.efi
文件是可以通过机器安全启动校验的。这个EFI文件的作用就是作为一个入口跳板,通过SecureBoot后再去加载后续EFI文件完成启动操作。
3. Grub是如何被加载的
\EFI\ubuntu\shimx64.efi
同目录下有一个\EFI\ubuntu\grub.cfg
。内容如下
search.fs_uuid 62c89a8b-9df9-4acd-bc18-8622a8d501d0 root hd0,gpt2
set prefix=($root)'/boot/grub'
configfile $prefix/grub.cfg
第一行的uuid是我Ubuntu系统所在分区的uuid,(似乎root后的hd0,gpt2
可以省略,删掉也没影响)。找到这个分区后,根据第二第三行的配置,Grub的EFIb部件会从中读取/boot/grub/grub.cfg
文件作为grub启动配置(该文件其实就是执行grub-update
的输出)。
然后,就是展示你熟悉的Grub窗口,在然后根据选择的Grub启动项进入操作系统,不过这已经不是UEFI的范畴了。
4. 系统安装时候的一个天坑
想象中,最理想的形式应该是系统安装时可以让用户自主选择安装到哪个EFI分区,这对双硬盘/移动硬盘用户绝对是好东西,可以保证每个硬盘上的系统互相独立,拔掉硬盘到别的电脑上也能继续用。
但是!
Windows就不必说了,向来是帮用户做决定,直接自作主张安装到它找到的第一个EFI分区中去,不让你选择。
Ubuntu倒是有一个界面让你选择安装启动引导器的设备,不过这好像是一个陈年老bug,一直没有修复,它也和Windows一样,也是不理会选择结果,直接奔着扫描到的第一个EFI分区去了。参见ubuntuforums。
所以,如果真的想要做到双硬盘独立的双系统,你可以这么事后补救:
- 进入第二个系统
umount
现有的/boot/efi
并重新挂载上正确的分区(应该是空的)- 使用
grub-install
,重建缺失的EFI文件 - 修改
/etc/fstab
更正挂载到挂载选项,否则即使会在正常启动操作系统后挂载上错误的/boot/efi
目录 - 恢复第一个操作系统的EFI分区(因为默认的安装策略修改了它)
- 如果第一个系统是同版本ubuntu,那么需要修正旧的EFI分区下的
\EFI\UBUNTU\grub.cfg
文件中的uuid即可,把它改回去指向第一个戏台的根目录 - 如果是其他的Linux系统,可以重启回第一个操作系统后使用
grub-install
重构它的EFI分区 - 如果第一个系统是Windows,那么应该删除EFI分区下的整
ubuntu
目录和BOOT
目录下的所有子文件,并把\EFI\Microsoft\Boot\bootmgfw.efi
复制到\EFI\BOOT\Bootx64.efi
(EFI文件系统不分文件名大小写)
- 如果第一个系统是同版本ubuntu,那么需要修正旧的EFI分区下的
- 使用
efibootmgr
调整启动项目(就是修改NVRAM配置)
上面的操作都挺麻烦的,其实最简单的办法还是防止这种事情发生,原理很简单,把无关硬盘在本次装机运行周期内移除。可以在Try Ubuntu
环境下执行如下操作。
对于
SATA
类型的硬盘(设备号形如/dev/sda
),方法很简单echo 0 | sudo tee /sys/block/<如sda>/device/delete
而对于
NVME
类型的硬盘(设备号形如/dev/nvme0n1
),就有些麻烦了# 查看设备的PCI路径
realpath /sys/block/<如nvme0n1>
# 输出结果应该大致为 /sys/devices/pci0000:00/0000:00:0e.0/nvme/nvme0/nvme0n1
# 然后根据输出结果,将对应的NVME设备移除
echo 1 | sudo tee /sys/devices/pci0000:00/0000:00:0e.0/remove或者直接一行命令
echo 1 | sudo tee $(realpath /sys/block/nvme0n1)/../../../remove
当然,如果是台式机,那还可以使用物理学方法,没那么多花里胡哨的,关机拔线就完事了
此命令会在将整个磁盘设备彻底隐藏(重启后恢复),因此当然不需要担心安装到了错误的EFI分区了。