老笔记本,一直用的ubuntu14.04与win7双系统。因为怕折腾,一直没有升级ubuntu,毕竟里面有数年常用的数据、软件,升级的话不折腾几天是搞不定的。不过ubuntu14.04的支持基本到头了,趁着ubuntu20.04 LTS新鲜出炉,决定尝试一下。
这一尝试,首先出现的问题就是引导挂了。只进入了grub shell,然后我进入LiveCD用boot-repair一顿操作,把win7的启动也弄挂了,这。。。只能手动慢慢修了。要修就得先知道UEFI是怎么工作的,这里先简单说下UEFI的启动过程。
支持UEFI的主板上都有NVRAM(Non-Volatile Ram即掉电也不丢失数据的存储空间),安装操作系统的时候,通常都会在NVRAM写入引导项,这个列表除了安装操作系统时写入的引导项,还有一些固定的硬件引导项,比如硬盘、U盘、网络启动)。在开机的时候,进入BIOS应该是能看到这个列表的,不同的主板操作不一样,我机子上的NVRAM列表看起来是这样的:
ubuntu是安装ubuntu时写入的引导项,IPV4、Boot From EFI File则是一些固定的硬件引导项。
实现UEFI启动,硬盘上还需要有一个ESP分区(EFI system partition),然后安装操作系统时,会在ESP分区写入引导文件。我机子上的ESP分区大概是这样的:
~$ sudo tree /boot/efi/EFI -L 3 /boot/efi/EFI ├── Boot │ ├── BOOTX64.CSV │ ├── bootx64.efi │ ├── grub.cfg │ ├── grubx64.efi │ ├── mmx64.efi │ └── shimx64.efi ├── Microsoft │ └── Boot │ ├── BCD │ ├── BCD.LOG │ ├── BCD.LOG1 │ ├── BCD.LOG2 │ ├── bootmgfw.efi │ ├── bootmgr.efi │ ├── BOOTSTAT.DAT │ ├── cs-CZ │ ├── da-DK │ ├── de-DE │ ├── el-GR │ ├── en-US │ ├── es-ES │ ├── fi-FI │ ├── Fonts │ ├── fr-FR │ ├── hu-HU │ ├── it-IT │ ├── ja-JP │ ├── ko-KR │ ├── memtest.efi │ ├── nb-NO │ ├── nl-NL │ ├── pl-PL │ ├── pt-BR │ ├── pt-PT │ ├── ru-RU │ ├── sv-SE │ ├── tr-TR │ ├── zh-CN │ ├── zh-HK │ └── zh-TW └── ubuntu ├── BOOTX64.CSV ├── grub.cfg ├── grubx64.efi ├── mmx64.efi └── shimx64.efi 28 directories, 19 files
其中,Boot目录是ESP分区的默认目录,Microsoft是win7的引导目录,ubuntu则是ubuntu的引导目录,注意,ESP分区是fat格式,这些目录及文件名不区分大小写。
当开机时,主板加电,会从NVRAM中读取引导列表,按顺序一个个去尝试引导启动,如果成功,就会进入对应的操作系统。例如,我的机子在开机时选择ubuntu的话,则主板会根据NVRAM中ubuntu这个项中的信息,直接加载ESP分区中的ubuntu/shimx64.efi,然后ubuntu/shimx64.efi会启动grub,接着由grub启动ubuntu,完成ubuntu的启动。如果选择从硬盘启动(我机子的BIOS中没显示这个项,后面会说到),那就会在硬盘中查找ESP分区(ESP分区在同一个硬盘可以有多个,会一个个去试),如果ESP分区中存在/Boot/bootx64.efi,就运行这个文件,完成引导,所以Boot目录称为ESP的默认目录。
回到之前的问题,我安装ubuntu后,没能引导进系统,而是挂在grub shell了,说明UEFI已经正确加载了ubuntu/shimx64.efi,但在grub那一步,grub没能成功启动ubuntu,这可能是配置错误,比如grub.conf错误。但我的系统是全新安装的,grub的配置不大可能会出问题,可能是一些环境变量不对,尝试手动加载。我的硬盘是gpt模式,ubuntu安装在第7个区分,没有使用独立的boot分区,因此boot目录是在ubuntu分区的boot目录下,即(hd0,gpt7)/boot/grub。如果不记得安装在哪个分区,可以用ls (hd0,gpt7)这样一个个去试,会打印一些分区信息
grub > ls (hd0), (hd0,gpt8),(hd0,gpt7),(hd0,gpt6),(hd0,gpt5),(hd0,gpt4),(hd0,gpt3),(hd0,gpt2),(hd0,gpt1) grub > set root=(hd0,gpt7) grub > set prefix=(hd0,gpt7)/boot/grub grub > insmod normal grub > normal
如果成功,会出现后面那个grub菜单,即可进入系统。如果失败,或者无法引导进入系统,那么说明grub已经没救了(至少以我的水平救不了了),你需要一个LiveCD之类的盘了。进入系统后,就需要修复一下grub了
sudo update-grub Sourcing file `/etc/default/grub' Sourcing file `/etc/default/grub.d/init-select.cfg' 正在生成 grub 配置文件 ... 找到 Linux 镜像:/boot/vmlinuz-5.4.0-26-generic 找到 initrd 镜像:/boot/initrd.img-5.4.0-26-generic Adding boot menu entry for UEFI Firmware Settings 完成
update-grub会搜索当前系统,查找各种启动,然后完成修复。按我的理解,update-grub只是修复grub引导,即对应/boot/grub目录下的东西,并不会修改ESP分区以及NVRAM的东西,但Adding boot menu entry for UEFI Firmwre Settings实在让人困惑,这个像是往NVRAM添加引导项。
如果进入的是LiveCD,那么当前系统并不是你想要修复的系统,你想修复的系统还在硬盘上,那么手动修复就复杂多了,我没这样操作过。在LiveCD可以使用boot-repair来修复
sudo add-apt-repository ppa:yannubuntu/boot-repair && sudo apt-get update sudo apt-get install -y boot-repair && boot-repair
boot-repair是一个带UI的程序,在菜单里找到它直接按提示操作就好。我的机子修复好以后,ubuntu能进了,但是win7的导引没了。而且,出现了新的问题
每次启动时,都会提示
System BootOrder not found. Initializing defaults. Creating boot entry "Boot0001" with label "ubuntu" for file "\EFI\ubuntu\shhimx64.efi"
而且这个Boot0001会依次增加为Boot0001、Boot0002、Boot0003,这样一直加下去,但是能正常进入ubuntu系统。根据上面UEFI的启动过程,可以推断,提示这个的时候,主板还没加载任何efi文件,而是在尝试引导某个NVRAM中的启动项时失败,然后主板在ESP分区找到了\EFI\ubuntu\shimx64.efi这个文件,并用这个文件引导ubuntu。我的直觉是NVRAM列表有问题,需要修复下。在ubuntu下,可以用efibootmgr来管理NVRAM列表
~$ efibootmgr BootCurrent: 0002 Timeout: 0 seconds BootOrder: 0002 Boot0000* ubuntu Boot0001* ubuntu Boot0002* ubuntu $ efibootmgr -v BootCurrent: 0002 Timeout: 0 seconds BootOrder: 0002 Boot0000* ubuntu HD(1,GPT,2b776bfe-665b-4a9a-995f-4c74e11712a4,0x800,0x95800)/File(\EFI\ubuntu\shimx64.efi) Boot0001* ubuntu HD(1,GPT,2b776bfe-665b-4a9a-995f-4c74e11712a4,0x800,0x95800)/File(\EFI\ubuntu\shimx64.efi) Boot0002* ubuntu HD(1,GPT,2b776bfe-665b-4a9a-995f-4c74e11712a4,0x800,0x95800)/File(\EFI\ubuntu\shimx64.efi) sudo efibootmgr -b 0001 -B sudo efibootmgr -b 0002 -B sudo efibootmgr -o 0000 sudo efibootmgr -b 0000 -a
通过efibootmgr指令可以看到主板已经给NVRAM列表添加了几个ubuntu,通过efibootmgr -v可以查看他们的参数(当选择NVRAM的一个启动项时,主板知道去哪个分区运行哪个efi文件,就是根据这些参数来的)。但是并没有看出什么问题,似乎一切正常。于是我把多余的删除了
sudo efibootmgr -b 0001 -B # 把启动项0001删了 sudo efibootmgr -b 0002 -B # 把0002删了 sudo efibootmgr -o 0000 # 设置0000为第一启动顺序 sudo efibootmgr -b 0000 -a #设置0000为活动启动项
重启,结果发现还是一样,主板又自动加了一个0001回来,参数还是一模一样。我怀疑是哪里操作错误,没修改到NVRAM列表,于是把它们又删了,还故意创建了一个win的引导项
~$ sudo efibootmgr -c -d /dev/sda -p 1 -L "Windows Boot Manager" -l "\EFI\microsoft\bootmgfw.efi" BootCurrent: 0002 Timeout: 0 seconds BootOrder: 0001,0000 Boot0000* ubuntu Boot0001* Windows Boot Manager
重启,发现NVRAM列表确实有修改到,多了Windows Boot Manager,不过问题依然存在。
至此,NVRAM像是没有问题的,那么我就怀疑ESP分区了。于是我直接把ESP分区给格了。然后重新安装
:~$ sudo update-grub Sourcing file `/etc/default/grub' Sourcing file `/etc/default/grub.d/init-select.cfg' 正在生成 grub 配置文件 ... 找到 Linux 镜像:/boot/vmlinuz-5.4.0-26-generic 找到 initrd 镜像:/boot/initrd.img-5.4.0-26-generic Adding boot menu entry for UEFI Firmware Settings 完成 :~$ sudo grub-install /dev/sda 正在为 x86_64-efi 平台进行安装。 安装完成。没有报告错误。
update-grub是修复/boot/grub的,我这里并没修改,其实是不需要运行的,不过为了保险再修复一次。grub-install是把当前系统的启动信息安装到ESP分区,会在ESP分区生成ubuntu目录和Boot目录,并且在NVRAM添加引导项。然后检测ESP分区(在ubuntu20.04里,已挂载到/boot/efi/EFI目录,ls就能看到文件)的各个文件,确认Boot和ubuntu目录确实存在,并且各文件的日期也是刚更新的,然后重启,问题依然存在。
到了这里,我已经技穷了,实在想不出来有啥可以操作的了。甚至还试了下在LiveCD下修复
mkdir /mnt/sda7 mount /dev/sda7 /mnt/sda7 grub-install --boot-directory=/mnt/sda7 /dev/sda # 由于LiveCD不是要修复的系统,需要把要修复的系统mount到当前系统 # 然后修复的时候指定启动目录为需要修复的系统目录
然而并没有什么区别。疯狂地google "System BootOrder not found"这些关键字,发现有不少例子,都没能说明白啥原因造成,不过我也尝试了他们的一些做法:
1. 在BIOS设置中把ubuntu放到第一项,但是我的BIOS没有这个选项,尝试失败
2. 尝试创建一个启动项,手动指定到ESP分区的/ubuntu/shimx64.efi。我机子的BIOS确实有一个Customized Boot,不过不管我输入啥,在NVRAM列表中都不会出现这个选项,只能放弃了
3. 直接使用Boot From EFI File从ESP分区的/boot/bootx64.efi启动,能进入系统,但问题依旧
4. 直接从NVRAM中选择ubuntu进入,问题解决,但我机子的BIOS无法设置ubuntu为第一启动项,所以这个不是办法
5. 接使用Boot From EFI File从ESP分区的/ubuntu/shimx64.efi启动,问题解决,但是这个只能手动启动
6. 把ESP分区里的/ubuntu/shimx64.efi覆盖/Boot/bootx64.efi,问题依然
7. 把ESP分区Boot目录里的文件全删了,复制ubuntu目录中的所有文件到Boot目录,然后把shimx64.efi改名bootx64.efi,问题解决
现在,"System BootOrder not found"这个问题是如何出现的,没法知道原因。google得到的结果里,多数也归为BIOS固件和UEFI的兼容问题,并且不少都提到hp笔记本的固件,我的刚好就是hp笔记本。没办法解决这个问题,只能绕过它。从结果上看,这有几个问题。第一,grub-install在ESP分区生成的Boot/bootx64.efi,在我的笔记本上无法正常引导ubuntu;第二,hp的BIOS没有按UEFI标准来引导系统,NVRAM列表上一直有ubuntu,但是没有硬盘的选项,而启动的时候,却直接从硬盘启动,然后执行/Boot/bootx64.efi,正常应该是先尝试NVRAM中设定的选项;第三,hp这个BIOS很坑,不仅不能像别的那样设定NVRAM的启动顺序,它一直有一个OS Boot Manager,这个OS Boot Manager用efibootmgr看不到,改不了,选中的时候主是从硬盘启动,我怀疑直接从硬盘启动就是这个隐藏选项的问题
ubuntu的启动问题总算解决了,下一步,就是要修复win7的启动。windows系统启动时,加载ESP分区的EFI/Microsoft/bootmgfw.efi文件,bootmgfw.efi读取目录下的BCD文件(boot configuration data),BCD保存了win的启动信息,比如在哪个分区。如果是多个win系统,也是在这里配置。根据BCD,加载对应分区的“\windows\system32\winload.efi”,之后winload.efi加载windows内核,启动完成。
win也提供了启动修复工具:bcdboot.exe。进入PE,确保win系统分区和ESP分区已挂载,我这里刚好是C和H盘,和bcdboot的帮助文档一致
执行
bcdboot c:\windows /s h: /f UEFI /l zh-cn :: 表示c:\windows为系统目录 :: h为ESP分区 :: 启动方式为UEFI :: 启动语言为中文简体
执行完后,检查ESP分区,正确创建了Microsoft目录。PS:看网上有些人说bcdboot修复会覆盖ESP分区里的Boot目录,我试了下,在我机子并不会出现这种情况,如果出现了再用ubuntu的启动文件重新覆盖一次。
重启,我发现在BIOS里并没有windows的引导项。但是,我用efibootmgr来检查,win7引导项是有在NVRAM列表中的,而我的ubuntu反而不见了。。。也不知道是bcdboot给清了,还是主板BIOS的问题,不过反正ubuntu那个引导项从来不会排在第一启动项,所以我也不纠结这个,直接默认从硬盘启动就好。
:~$ efibootmgr -v BootCurrent: 0000 Timeout: 0 seconds No BootOrder is set; firmware will attempt recovery Boot0000* Notebook Hard Drive BBS(HD,,0x0)....................................................................... Boot0001* SD Card BBS(7,,0xa0)....................................................................... Boot0002* Windows Boot Manager HD(1,GPT,2b776bfe-665b-4a9a-995f-4c74e11712a4,0x800,0x95800)/File(\EFI\Microsoft\Boot\bootmgfw.efi)WINDOWS.........x...B.C.D.O.B.J.E.C.T.=.{.9.d.e.a.8.6.2.c.-.5.c.d.d.-.4.e.7.0.-.a.c.c.1.-.f.3.2.b.3.4.4.d.4.7.9.5.}....................
在UEFI模式下,Linux + Win双系统引导只有两种方式,一是由BIOS引导,在NVRAM列表里直接选择启动哪个系统,不过我这里在BIOS里没有出现win的引导项,而且没法设置默认ubuntu启动,所以不考虑;二是由Linux的grub来引导win系统。不存在win引导linux的选项,因为到目前为止,一旦加载ESP分区的/Microsoft/Boot/bootmgfw.efi。它就会读取BCD中的配置,如果有多个系统,就会出现一个选择菜单,如果这里加了一个linux系统,它是不认linux系统的数据,引导不成功的,所以它可以引导多个windows,但不能引导linux系统。
进入ubuntu,用update-grub来更新grub配置
~$ sudo update-grub Sourcing file `/etc/default/grub' Sourcing file `/etc/default/grub.d/init-select.cfg' 正在生成 grub 配置文件 ... 找到 Linux 镜像:/boot/vmlinuz-5.4.0-26-generic 找到 initrd 镜像:/boot/initrd.img-5.4.0-26-generic 找到 Windows Boot Manager 位于 /dev/sda1@/EFI/Microsoft/Boot/bootmgfw.efi Adding boot menu entry for UEFI Firmware Settings 完成
如果win的启动配置正确,update-grub应该是能够分析到win的引导并加入到grub中,如果不行,那得手动编辑/boot/grub/grub.cfg来手动添加入口。由于grub配置和ESP分区无关,因此不需要grub-install,重启,应该能在grub选择菜单中看到win7了。
关于SecureBoot,安全启动,是说在整个启动过程中,所调用的文件都是经过签名的。比如启动用的shimx64.efi,还有系统启动时一些驱动等。ubuntu官方的文件是有签名的,因此支持安全启动,但是有一些驱动是私有的,比如AMD、NVIDIA的显卡驱动,是没有经过签名的,如果有用这类的驱动,就得关闭安全启动。
关于UEFI CSM(Compatibility Support Module),UEFI的兼容模块,允许操作系统以旧的BIOS-MBR模式启动。win7必须得开启CSM才能正常启动,部分人以为是win7需要MBR模式引导,这个是错误的。关闭CSM,用UEFI + GPT的方式win7一样能引导,只是卡在启动中,一般是在windows那个图标的位置就花屏了。UEFI不仅仅是从NVRAM读取引导项,去ESP分区加载引导程序这么简单的,这只是它一小部分的功能。它的另一个功能,是定义了UEFI下的一些显示规则,所以UEFI的主板,启动过程可以做得很炫酷。UEFI引导win7是没问题的,但是win7的驱动不支持UEFI的显示,因此完成引导后,就跑不下去了。有传闻说,只要愿意启动过程黑屏,win7也是可以纯UEFI启动的(我没试过,尝试的话后果自负)
设置启动过程黑屏 bcdedit.exe /store S:\efi\Microsoft\boot\bcd /set {default} novesa on 然后删掉vga.sys C:\Windows\System32\drivers,把vga.sys
而ubuntu20.04是两者都支持的,但在CSM模式下,明显驱动没写好,OEM logo被拉伸了,正常情况下,hp这个应该是圆的