恢复 UEFI 模式的 GRUB2 启动项

我的系统是 64 位 openSUSE Tumbleweed 与 预装的 Windows 10 双启动。感觉应该是开启了 UEFI 的 Secure Boot 的(结果真是)。今天尝试着在 BIOS 里恢复默认设置,结果玩坏了,丢了 OpenSUSE 启动项。开机只能从硬盘启动直接进入 Windows。只好尝试着使用恢复光盘恢复一下。虽然不算特别顺利,终于还是很快就搞定了。

这种不常见的操作,如果不记下来,下次肯定又要再摸索一遍。下面是详细步骤。参考了三个网页。

一点背景知识

有必要先了解一下 UEFI 与 GRUB 2 的关系,可以参考 openSUSE 上的这篇文档

简单来说就是,EFI 相当于开机后运行的一个小型嵌入式系统,该系统的作用就是检查并启动我们需要的目标操作系统。EFI 的内部引导管理器管理着一个所有引导项的列表。可在开机加电后按 F12 键打开引导设备管理器查看列表。设置了默认启动项之后,开机 EFI 做相应检查后就直接交接给该默认启动项,比如 Windows 启动管理器或者 GRUB 启动菜单。在 Linux 上还可以通过命令行应用 efibootmgr 来访问和有限操作 EFI 内部引导管理器。

安装操作系统的时候系统需要为自己准备加载项,都需要将系统引导工具(或叫「引导加载器(boot loader)」如 Windows 启动管理器和 Grub 2 启动加载器)安装到 EFI 分区(ESP)。默认情况下,Windows 和 openSUSE 分别是 /EFI/Microsoft/Boot/BCD.efi/EFI/opensuse/grubx64.efi (启用 Secure Boot 的话则是 shim.efi)。安装完了之后还需要向 EFI 注册成为内部引导管理器中的一个引导项后才会被 EFI 在用户开机后按 F12 键时展示给用户。如果设为默认,EFI 则会直接将后续的引导权交给该默认启动项而不会展示所有启动项列表。

启动 U 盘

先下载系统对应的 rescue CD:https://en.opensuse.org/openSUSE:Tumbleweed_installation

然后根据「T470s 上安装 Linux 滚动发行版 openSUSE Tumbleweed」里烧录光盘镜像到 U 盘的方法制作启动 U 盘。

从 U 盘启动系统,自动进入 rescue 模式的选择菜单。注意必须是 UEFI 模式(只要 BIOS 设置为 UEFI only 那就只能从 UEFI 模式启动),否则进入的恢复系统看不到 /boot/efi 分区。

恢复光盘的启动菜单第一项是 Live 模式,进入之后是 openSUSE Tumbleweed Xfce 桌面环境;第二项是 Failsafe 模式,进入后只有命令行界面。

恢复过程

登录恢复系统

如果进入 Live 模式,可以从开始菜单 -> 「System」 -> 「XTerm」启动命令行界面,直接在命令行输入 su 就可以切换到 root 身份(无密码)。

如果是 Failsafe 模式,等待系统进入命令行要求登录的时候,输入 root,密码为空,即是 root 身份。

[可选]修改字体大小

**此小节内容在 Failsafe 模式下试过

如果命令行字体太小,可以临时修改命令行终端的字体。

查看所有可用字体,

# ls -al /usr/share/kbd/consolefonts/

我选用了 suse12x22.psfu,这个对我的 2560×1440 的 14″ 显示器算是非常合适,

# setfont /usr/share/kbd/consolefonts/suse12x22.psfu

分区位置

先确认至少以下几个分区的位置,

/boot/efi
/boot
/
/home

以及所在的磁盘路径,比如 /dev/sdaX 或者 /dev/nvme0n1pX 其中 X 代表分区号,X 前面的部分是磁盘设备路径(两块硬盘则一般情况下分别是 /dev/sda/dev/sdb 或类似的 NVMe 磁盘标识)。

如果不记得,可以使用,

# fdisk -l

以及,

# parted -l

查看所有可用磁盘设备来帮助回忆。其中带 loop 的设备是光盘启动造成的;另外可能还包括 U 盘的部分分区(根据不同制作启动 U 盘的方式有所不同)。

作为参考,下面是我的分区及设备路径(不相关的没放上来):

/dev/nvme0n1p1  EFI System
/dev/nvme0n1p7  /
/dev/nvme0n1p8  /home

/boot/ 中。为了避免误导——因为不同安装环境和设备具体情况不同,这些指令不能直接复制粘贴使用——下面用 XYZ 指代分区(p, partition)编号,如这里的 178

开始重建 GRUB2 引导项

根据本文最开头介绍的基本知识,重建/恢复 GRUB 2 引导项要分成两种情况:

A. 在 EFI 中注册 GRUB。/boot/efi 中还保存了原来的 opensuse 文件夹,其中的内容也都还在。那么就不需要重新安装 GRUB2 引导项,只需要将其加入(注册)到 EFI 启动项列表中即可;

B. 重建 GRUB 并将其注册到 EFI 中。/boot/efi 中原来的 opensuse 文件夹里的内容不可用了,那么就需要重新安装了。

可以将 /boot/efi 挂载之后查看其内容来确定。但是个人觉得比较简单的方法是,直接按情况 A 来操作,然后尝试重新启动,可以正确引导就结束,不行再重新从恢复光盘启动然后按照 B 的方法来重建 GRUB2 启动项。

情形 A:在 EFI 中注册 GRUB

仅仅是注册话就很简单了, efibootmgr 可以很方便地完成这个工作,

# efibootmgr -c -d /dev/nvme0n1 -p X -l \\EFI\\opensuse\\shim.efi -L opensuse-secure

其中,

  • -c 表示生成一个新的启动项;
  • -d /dev/nvme0n1 表示该启动项对应的文件在磁盘 /dev/nvme0n1 中,如果有多个磁盘,可能后面结尾的数字就不是 1
  • -p X 表示启动项对应的文件在上述磁盘的第 X 个分区中;
  • -l \\EFI\\opensuse\\shim.efi 表示该启动项对应的启动文件,其中路径是相对于 ESP 分区的根目录(/)的,使用 \\ 这样的分隔符,如果不是 Secure Boot,则需要将上面的 shim.efi 改成 grubx64.efi
  • -L opensuse-secure 表示新建启动项在EFI 内部启动管理器中的标签(名称)为 opensuse-secure

完成后 efibootmgr 会列出内部启动管理器的当前配置,类似于,

$ sudo efibootmgr -v

的结果,如,

BootCurrent: 0001
 Timeout: 2 seconds
 BootOrder: 0001,0000,0010,0011,0012,0013,0017,0018,0019,001A,001B,001C,001D,001E,0023
 Boot0000* Windows Boot Manager  HD(1,GPT,...,0x800,0x82000)/File(\EFI\Microsoft\Boot\bootmgfw.efi)...
 Boot0001* opensuse-secure       HD(1,GPT,...,0x800,0x82000)/File(\EFI\opensuse\shim.efi)
 Boot0010  Setup FvFile...
 ... ... ...

这里(省略了很多内容)显示当前启动的是 0001 号启动项;Timeout 超时等待时间是 2s;启动顺序(BootOrer)是 0001 第 1,0000 第 2。下面还列出了 Boot0000 是 Windows,Boot0001 可以看到是 opensuse-secure。所以默认情况下会直接使用 Secure Boot 扩展启动 openSUSE。

现在重启系统试试看,

# reboot

如果没有出现启动项菜单,那么估计得进行下面的安装了。

情形 B:重新安装 GRUB 2

**以下操作未经测试**

这个稍微麻烦些。

创建 mount 位置,

# mkdir /mounts
# mkdir /mounts/root

挂载原来的分区到新建的挂载点,

# mount /dev/nvme0n1pY /mounts/root
# mount /dev/nvme0n1pX /mounts/root/boot/efi

还有更多需要挂载的,

# mount --bind /dev /mounts/root/dev
# mount --bind /proc /mounts/root/proc
# mount --bind /sys /mounts/root/sys

激活刚挂载的原来的 / 分区,

# chroot /mounts/root

重建 GRUB2,

# grub2-install --target=x86_64-efi

如果是 Secure Boot,还需要下面这行指令,

# shim-install

再然后就是重建 GRUB 菜单项了(也许不需要,但是没有什么坏处,反正每次更新内核都会重建一次的),

# grub2-mkconfig -o /boot/grub2/grub.cfg

**不太确定这里是否需要注册该启动程序到 EFI 内部启动管理器作为启动项的操作(见情形 A 中的 efibootmgr 指令)**

然后按 Ctrl+D 退出挂载的 root 分区(退出 chroot),

# exit

再取消挂载刚才挂载的那些设备,

# umount /sys
# umount /proc
# umount /dev
# umount /mounts/root/boot/efi
# umount /mounts/root

最后重启系统,

# reboot

幸运的话重启之后应该直接会进入 GRUB 启动菜单了,至少按 F12 调出的内部启动项里面应该会有 openSUSE 的启动项。

感觉一般情况下只需要走到情形 A 而不至于到情形 B 的程度。©

本文发表于水景一页。永久链接:<http://cnzhx.net/blog/restore-grub2-boot-menu-with-uefi/>。转载请保留此信息及相应链接。

雁过留声,人过留名

电子邮件地址不会被公开。 必填项已用*标注

特别提示:与当前文章主题无关的讨论相关但需要较多讨论求助信息请发布到水景一页讨论区的相应版块,谢谢您的理解与合作!请参考本站互助指南