0%

UEFI -- 又被坑了一次

事情的起源是这样的:

想把笔记本上的 1060 用起来,但是 Windows 下 Cuda 的 nvcc 只跟 VS 的编译器绑定,没法换成 Mingw,这就很不开心了。虽然实在为了在 Windows 下跑程序方便,还是把 VS 2015 装上了(吃了我整整几十个 G 的空间,心疼),但是用起来仍然是非常不爽。
虽说以前也经常折腾 Win + Linux 的双系统,这次换完笔记本之后觉得破坏原本的分区引导什么的贼不清真 ╮(╯_╰)╭ 然后并不想装。

那最后还是要用啊,怎么办,好烦。

后来终于有了个(自己觉得)特别 6 的想法。我搞个 U 盘装上就好了哇!用 Linux 的时候插上,不用拔了,特别清真!

然后。。。晚上下了个单,第二天 U 盘就到啦。。。(还特意买个新 U 盘。。。主要是老 U 盘容量都太小)。

然后。。。就没有然后了,中间一直坑。


感觉主要原因还是自己对 EFI 的了解没有原来想象中的那么清楚,一知半解下瞎搞,出问题自然怪不了别人。

前面写过一篇测试:

主要是针对 BIOS 的引导和 MBR 分区格式的简单分析。

BIOS+MBR vs UEFI+GPT

老一代的系统用的是 MBR 分区表加主板上的 BIOS 引导方式。

MBR 看上去就像个单链表的形式,简单地说就是在每个磁盘分区的开头会固定有一块区域(512B)用于标记整个分区的信息,包括分区大小、是否有引导等等,然后一个分区的标记结束之后再根据偏移就能找到下一个分区。整块硬盘的第一个扇区还标记了整个盘上的引导情况。

BIOS 要做的就是直接读硬盘开头的 512B 的内容就好了,特别简单粗暴。当然相对而言,当时如果系统引导坏了,修起来也比较麻烦,要用专门的工具软件。


后来由于 MBR 分区的缺陷,比如长度有限,所以主分区最多只能有 4 个,硬盘总大小不能超过 2T 等等,当年还是妥妥的够的,不过随着科技的不断发展,SSD 都有好多 T 的了,老的标准已经不再适用,后来就出现了 GPT 分区格式。

GPT 其实我仍然没有详细了解,直观上感觉就是 MBR 的升级版,相比 MBR 更长,因而能表达更多的信息,支持更多的分区和容量,还有备份,所以不容易坏,等等等等,还有很多很厉害的特性。

UEFI(Unified Extensible Firmware Interface) 是一种用来替代 BIOS 的标准,话说它一开始叫 EFI,后来统一之后改叫 UEFI,不明真相的我之前一直以为这个 U 是 “Un” 的前缀,就是非 EFI 的意思…太天真。

相对 BIOS 来说,UEFI 的固件也是固化在主板上的,大致的功能都是类似的,也是由它来读取硬盘上的引导信息,然后加载。

UEFI 一般来说都是跟 GPT 搭配的,当然据说 BIOS+GPT 和 UEFI+MBR 也有,不过会出各种问题,这就在本篇讨论的范围之外了。

既然 GPT 的分区信息不再限制在扇区开头的 512B 范围内了,相对应的 UEFI 检索引导信息的时候也会更加灵活。它会扫描整块硬盘上所有的分区,找到 EFI 分区读取里面的 .efi 文件就可以直接引导了。

所谓 EFI 分区就是个 FAT32 的分区,只是额外带有一个 EFI 标记。所以 EFI 分区不再限制必须要放在开头的第一个分区里面,它可以在整块硬盘的任意一个分区位置。当然,读还是从前向后读的,所以默认情况下是最先找到的 EFI 分区中的 .efi 文件会被加载。

好了,上面是我以前的了解。当时并没有了解清楚里面的细节,然后就坑了。

What’s Wrong?

装 U 盘我是直接在 VMware 里面完成的,把 U 盘做成 GPT 分区,UEFI 装机模式。

一开始我往 U 盘里面装的是 Manjaro,这是个基于 Arch 的发行版,然后发现在虚拟机里面能引导起来,关机重启之后无效。不明觉厉,当时觉得可能是这玩意太新了,蜜汁 Bug。

然后退而换 Fedora。

Fedora 的装机过程很顺利,装好之后 U 盘都不用拔,直接重启笔记本就很顺利地引导进去了。然后开始装 Nvidia 的显卡驱动等等等等。

过程也挺顺利的,关键是最后发现我用 DP 口输出出来的第二块屏幕无效,这强迫症就很不爽了。原因大概是我笔记本上自带的屏幕直连的是集显,但是 DP 口是连在独显上的,Intel 的驱动和 Nvidia 的驱动在这块上需要额外配置一下才能正常使用。

然后就一顿操作,然后就失败了。网上也搜不到很好的解决方案。

最后看到有人说目前已知的笔记本双显卡的 Linux 解决方案里面最简单的就是直接用 Ubuntu 了,这里面官方自己配过,装显卡驱动也只要在设置里面点一下就好。

自己手动配置实在太麻烦,我妥协了。

然后又格了 U 盘开始装 Ubuntu。


重点来了。

装 Ubuntu 的时候发现这玩意做 EFI 分区的行为跟 Fedora 不太一样。

我原本虚拟机里面是有个 UEFI 的系统的(Win10)。Fedora 的做法是我指定了装在 U 盘这块驱动器上,它就不会动其他的部分,EFI 分区什么的都只会在 U 盘上进行操作。

装 Ubuntu 时,虽然我已经指定了目标位置是 U 盘,装完之后 U 盘上会建立一个 EFI 分区,但是里面是空的,它在安装时扫描到虚拟机硬盘里面的 EFI 分区之后,直接把它给改了!!!

这就是为什么装双系统的时候,你会发现原本的 Windows boot loader 会被干掉。而如果你从 Ubuntu 做的 Grub 里面选择 Windows 来启动,下次 Windows 又会把 Grub 干掉。网上能找到大量的这种求助帖。

原因就是它们用的是同一个 EFI 分区。

于是我把虚拟机里面那块硬盘给删了,又重新插 U 盘装了一遍。这次 EFI 分区里面有内容了。

遂重启。

然而失败了。笔记本上的 EFI 固件死活读不到 Ubuntu 这个启动项。我以为是 EFI 里面的内容在装机时出错了,重新在虚拟机里测试的时候却是正常的。

又重新装了几次 Ubuntu 和 Fedora,我才发现 Ubuntu 生成的 EFI 分区跟 Fedora 生成的有区别。Fedora 装完生成的分区目录是这样的:

1
2
3
4
5
6
7
/EFI
--/BOOT
--/BOOTx64.efi
--/fedora
--/xxx.efi
--/xxx.efi
-- ...

而 Ubuntu 生成的 EFI 分区中少了 /BOOT 这个目录!!

1
2
3
4
5
/EFI
--/ubuntu
--/xxx.efi
--/xxx.efi
-- ...

。。。那么看来问题就出在这里了。

BOOTx64.efi

在网上找到一份这样的资料:

里面大致把 UEFI 的引导问题都讲的比较清楚了。

所以这下真相大白了。虽然 UEFI 固件会自动识别出来 EFI 分区并且去读里面的 .efi 文件,但是一般的 UEFI 固件读取的只会是 EFI/BOOT/BOOTx64.efi 这个文件。一些设置项更多的 UEFI 固件可能能支持让你手动选择 .efi 文件,例如 VMware 里面那个固件就是。

这就是为什么我用 U 盘做好的 Ubuntu 能在虚拟机里正常引导,但是没办法在笔记本上启动。

那么问题就解决了。

打开 EFI 分区,新建一个名字叫 BOOT 的文件夹,把 ubuntu/shimx64.efiubuntu/grubx64.efi 拷过去。然后把 shimx64.efi 改名为 BOOTx64.efi

重启,Enjoy。