GRUB 与系统引导
本文是发到内刊上的一篇文章,感谢帮忙找 typo 的肥猫 ~
计算机引导过程
固件
确切的说,固件(Firmware)也是一种软件,但是它比一般的软件(例如操作系统或者运行在操作系统上的应用软件)更接近硬件,一般是由硬件厂商在硬件出厂前直接固化到硬件内部的芯片上。有些固件是可以升级的,例如大部分计算机主板的固件,这里我们讨论的也主要是计算机主板的固件。
现在我们能看到的计算机主板固件主要上分为两种:BIOS(Legacy BIOS)和 UEFI,BIOS 历史悠久,数十年没有太大的变化,已经不太适应计算机的发展,因而催生了更加先进和适应时代需求的 UEFI。
BIOS 是 Basic Input Output System(基本输入输出系统)的缩写,如前文所说,它也是可执行的程序代码,计算机启动时会首先将 BIOS 载入到内存并执行,并由 BIOS 来完成硬件检测和初始化,然后启动磁盘上的操作系统。
UEFI 是 Unified Extensible Firmware Interface(统一可扩展固件接口)的缩写,它是 BIOS 的替代者,并且本着向下兼容的原则,大部分 UEFI 都包含 BIOS 的兼容模块(Compatibility Support Module/CSM),在其设置中也能找到相关的选项。
BIOS 与 MBR
一般来说,BIOS 需要配合 MBR 分区表来引导系统(GPT 分区表也可以通过 PMBR 兼容 BIOS 引导),对于使用 BIOS 的计算机,其系统引导过程如下:
- BIOS 被加载执行,完成加电自检(Power On Self Test,POST) ,并检查和初始化需要的硬件设备
- BIOS 根据预设的顺序查找引导设备(能从中读取数据,且首扇区以 0x55AA 结束)
- BIOS 执行第一个找到的引导设备首扇区前 440 字节代码,即主引导记录(MBR)
- MBR 通常是启动管理器(Boot Loader)的第一阶段代码,由它引导启动管理器的第二阶段
- 启动管理器完成操作系统的引导启动
MBR 是 Master Boot Record 的缩写,又叫做主引导扇区,是计算机开机后访问硬盘时所必须要读取的首个扇区。在深入讨论主引导扇区内部结构的时候,有时也将其开头的446字节内容特指为“主引导记录”(MBR),其后是4个16字节的“磁盘分区表”(DPT),以及2字节的结束标志(0x55AA)。因此,在使用“主引导记录”(MBR)这个术语的时候,需要根据具体情况判断其到底是指整个主引导扇区,还是主引导扇区的前446字节。
UEFI 与 GPT
UEFI 的出现就是为了代替 BIOS,GPT 分区表(GUID Partition Table)是同 UEFI 一起诞生的,它突破了 MBR 分区表4个主分区及最大 2.2T 容量的限制。
UEFI 与 BIOS 相比还有很多特性,例如:
- 支持文件系统,可以直接读取分区上的文件
- 可以存储启动管理器的路径并直接引导之
- 可以加载并运行 EFI 应用
- 提供 EFI Shell
主流的 UEFI 都支持 MBR 和 GPT 分区表,并且支持 FAT12/FAT16/FAT32、IS09660、UDF 等文件系统。
一般来说,UEFI 下系统的引导的过程如下:
- UEFI 被加载执行,完成加电自检(Power-On Self Test,POST) ,并检查和初始化需要的硬件设备
- UEFI 根据预设直接从引导设备上加载 UEFI 应用(有可能是启动管理器,如 GRUB)
- 启动管理器完成操作系统的引导启动
UEFI 的引导依赖于分区表上的一个特殊分区,叫 EFI 系统分区(EFI System Partition),UEFI 标准中规定 EFI 系统分区为 FAT32,同时支持 FAT12/FAT16 作为移动介质的文件系统。
UEFI 的多重引导
每个操作系统或厂商都可以维护自己的 EFI 系统分区中的文件,同时不影响其他系统,一般来说各个操作系统或厂商都会将文件置于 EFI 系统分区中的/EFI/<VENDOR NAME>/
目录,例如/EFI/deepin
或/EFI/Microsoft
,这样各家的文件互不影响。UEFI 的多重启动只是简单的运行不同路径下的 UEFI 程序,避免了依赖链式启动机制(Chain Loading,通过一个启动引导程序加载另一个引导程序),这些程序的路径要添加到 UEFI 设置中才能在计算机开机时自动运行或进行选择。
安全启动
UEFI 提供了安全启动(Secure Boot)的功能,安全启动功能启用时,UEFI 会验证启动管理器的的合法性,一般来说验证是通过数字签名来实现的,但很多计算机出厂时只预装了微软的证书,有的 UEFI 固件也支持基于路径的认证,还有将启动管理器路径写死的。
大多数 UEFI 固件提供了关闭安全启动的选项,还有部分可以在 UEFI 设置界面手动添加受信任的路径。
常见启动引导器
BIOS 或 UEFI 加载并初始化硬件完成后,一般会启动某个启动管理器来接管硬件设备,引导操作系统启动的工作将由启动引导器来完成。
引导程序引导方式及程序视应用机型种类而不同。例如在普通的个人电脑上,引导程序通常分为两部分:第一阶段引导程序位于主引导记录(MBR),用以引导位于某个分区上的第二阶段引导程序,如 NTLDR、BOOTMGR 和 GNU GRUB 等。
NTLDR/BOOTMGR
NTLDR(NT Loader 的缩写)是微软的 Windows NT 系列操作系统(包括 Windows XP 和 Windows Server 2003)的引导程序。
NTLDR 可以从硬盘以及 CD-ROM、U盘等移动存储器运行并引 Windows NT 系统的启动。如果要用 NTLDR 启动其他操作系统,则需要将该操作系统所使用的启动扇区代码保存为一个文件,NTLDR 可以从这个文件加载其它引导程序。
NTLDR 主要由两个文件组成,这两个文件必须放在系统分区(大多数情况下都是C盘):
NTLDR
,这是引导程序本身boot.ini
,这是引导程序的配置文件
当boot.ini
丢失时,NTLDR 会启动第一块硬盘第一个分区上的\Windows
目录中的系统。
bootmgr (Windows Boot Manager) 是从 Windows Vista 开始引进的新一代开机管理程序,用以替换 NTLDR 。
当电脑运行完 POST (Power On Self Test) 后,传统型 BIOS 会根据引导扇区查找开机硬盘中标记"引导"分区下的 bootmgr
文件;若是 UEFI 则是bootmgr.efi
文件,接着管理程序会读取开机配置数据库 BCD
(Boot Configuration Database) 内的引导数据,接着根据其中的数据加载与默认或用户所选择的操作系统。
GNU GRUB 及其使用
GNU GRUB(简称 GRUB)是一个来自 GNU 项目的启动引导程序。GRUB 是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB 可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。
GRUB Legacy/GRUB2
新的GRUB2(GRUB 第二版)为 GRUB 的重写版本,它是 GRUB 的大革新。GRUB2 对 Linux 系统做了更多的优化,支持更多的功能,如动态的载入模块(而在之前的GRUB中,新增或刪除模块要重新编译 GRUB)等。GRUB2 的版本号为 0.98 或更高;旧的 GRUB 的版本号则为 0.97 或更低,也被称为“GRUB Legacy”或“GRUB1”等。GRUB2 的配置、命令等较 GRUB Legacy 有一定的不同,如未指明,本文所说 GRUB 均指 GRUB2。
GRUB 的安装
GRUB 提供一个安装程序grub-install
用以安装 GRUB 到磁盘,下面是grub-install
的一些常用参数及选项:
- --boot-directory=DIR
指定 boot 目录,用于存放 GRUB 的相关文件,包括其镜像、模块及字体等,同时 GRUB 也会从该目录读取配置文件,此参数缺省为
/boot
,则 GRUB 的相关文件都在/boot/grub
下,配置文件路径为/boot/grub/grub.cfg
。 - --target=TARGET
指定要安装的 GRUB 类型(对应不同的 BIOS 启动模式),常用的可选参数有 i386-pc、x86_64-efi、i386-efi 等,对应的文件会被安装到
<boot directory>/grub/<target>/
(<boot directory>
为--boot-directory
参数指定的 boot 目录,默认为/boot
)下 - --force
即使遇到报错仍然强制安装
UEFI 特有参数及选项:
- --efi-directory=DIR
指定 EFI 系统分区的根目录,即 EFI 系统分区的挂载点
- --removable
为移动设备安装,将 GRUB 安装到U盘时必须使用此选项
- --bootloader-id=ID
指定启动项 ID
- --efi-directory=DIR
GRUB 安装实例
将 BIOS 模式的 GRUB 安装到
/dev/sda
sudo grub-install --target=i386-pc --boot-directory=/boot /dev/sda
上面的
--boot-directory=/boot
一般可以省略。注意:要安装 i386-pc 模式的 GRUB 需要安装软件包
grub-pc-bin
sudo apt-get install grub-pc-bin
将 BIOS 模式的 GRUB 安装到U盘(
/dev/sdb
)假设
/dev/sdb
只有一个分区,文件系统为 FAT32,如果U盘已经挂载,先卸载之:sudo umount /dev/sdb1
安装 GRUB:
mkdir /tmp/sdb1 sudo mount /dev/sdb1 /tmp/sdb1 sudo grub-install --target=i386-pc --boot-directory=/tmp/sdb1/boot /dev/sdb sudo umount /dev/sdb1
上面的
--boot-directory=/tmp/sdb1/boot
不可省略。将 x64 EFI 模式的 GRUB 安装到计算机 UEFI(EFI 系统分区为
/dev/sda1
)假设
/dev/sda1
已经被挂载到/boot/efi
,如果没有先手动挂载之:sudo mount /dev/sda1 /boot/efi
安装 GRUB:
sudo grub-install --target=x86_64-efi --boot-directory=/boot --efi-directory=/boot/efi
上面的
--boot-directory=/boot --efi-directory=/boot/efi
一般可以省略。将 x64 EFI 模式的 GRUB 安装到U盘(
/dev/sdb
)同样假设
/dev/sdb
只有一个分区,文件系统为 FAT32,如果U盘已经挂载,先卸载之:sudo umount /dev/sdb1
安装 GRUB:
mkdir /tmp/sdb1 sudo mount /dev/sdb1 /tmp/sdb1 sudo grub-install --target=x86_64-efi --boot-directory=/tmp/sdb1/boot --efi-directory=/tmp/sdb1 --removable sudo umount /dev/sdb1
上面的
--boot-directory=/tmp/sdb1/boot --efi-directory=/tmp/sdb1 --removable
不可省略。
GRUB 的配置文件
GRUB 配置文件的文件名和位置随系统的不同而不同;常见为/boot/grub/grub.cfg。
修改 GRUB 的配置文件后,不必把 GRUB 重新安装到 MBR 或者某个分区中。在 Linux 中,grub-install
命令是用来把 GRUB 的步骤1安装到 MBR 或者分区中的。GRUB 的配置文件、步骤2以及其它文件必须安装到某个可用的分区中。如果这些文件或者分区不可用,步骤1将把用户留在命令行界面。
GRUB Shell 常用命令
在 GRUB 界面下按 C
可进入 GRUB Shell 界面,它提供了一个简单的类 Bash 的命令行环境,下面介绍一些常用的命令:
- ls:
不加参数使用时,列出当前的存储设备及识别出来的分区
可以接目录路径为参数,列出目录内的内容 - cat:查看文件内容
- echo:显示字符串或环境变量
- set:设置环境变量,例如
set root=hd0,gpt1
- insmod:载入模块
- loopback:映射回环设备
- search:搜索分区
- linux:载入 Linux 内核
- initrd: 载入初始化内存盘
- boot:启动系统
- chainloader:链式启动其他文件
- source:载入 GRUB 配置文件
GRUB Shell 操作实例
手动启动硬盘上的 deepin 系统
假设硬盘分区表为 GPT,第一个分区为 FAT32 格式的 EFI 系统分区,第二个分区为 deepin 的根分区,使用安装了 GRUB 的U盘启动电脑,进入 GRUB Shell (在 GRUB 菜单界面按C
),可按如下操作:
- 载入 GPT 分区表支持模块:
insmod part_gpt
- 查看存储设备及分区:
ls
- 假设计算机硬盘被识别成 hd1,设置 hd1,gpt2 为根分区:
set root=hd1,gpt2
- 查看根分区内容:
ls /
查看
/boot
目录内容:ls /boot
查看
/boot/grub
目录内容ls /boot/grub
- 载入 Linux 内核:
linux /boot/vmlinuz-4.9.0-deepin2-amd64 root=/dev/sda2
(示例,也可以用linux /vmlinuz root=/dev/sda2
) - 载入初始化内存盘:
initrd /boot/initrd.img-4.9.0-deepin2-amd64
(或initrd /initrd.img
) - 启动系统:
boot
如果一切正常,系统会正常启动。此外,在上面第4步的时候,也可以用source /boot/grub/grub.cfg
命令载入硬盘上的 GRUB 配置文件,然后按Esc
返回 GRUB 菜单界面,会看到原本电脑上 GRUB 菜单,直接选择 deepin 系统启动即可。
在 LIVE 环境修复 GRUB 引导
进入 LIVE 环境
使用系统修复光盘或U盘启动计算机即可进入 Live 桌面环境。
进入 CHROOT 环境
在 Live 桌面环境中打开终端
确定硬盘上系统的各个挂载点的分区,以下表所示情况举例:
挂载点 | 分区 | 备注 |
---|---|---|
/boot/efi | /dev/sda1 | UEFI 下特有 |
/ | /dev/sda2 | |
/home | /dev/sda3 | 如未单独分区则忽略 |
/var | /dev/sda4 | 如未单独分区则忽略 |
挂载文件系统
mkdir /tmp/mnt #建立临时挂载目录
cd /tmp/mnt #进入目录
sudo mount /dev/sda2 ./ #挂载根分区
sudo mount /dev/sda1 boot/efi #仅在UEFI模式下挂载EFI分区
sudo mount /dev/sda3 home #如果仅修复引导此分区可不挂载
sudo mount /dev/sda4 var #如果/var单独分区,必须挂载
sudo mount --bind /sys sys
sudo mount --bind /proc proc
sudo mount --bind /dev dev
sudo mount --bind /dev/pts dev/pts
进入 chroot 环境
sudo chroot /tmp/mnt
修复 GRUB 引导
切记,修复本机 GRUB 引导需要在 chroot 环境下操作!
BIOS 下:
grub-install --boot-directory=/boot /dev/sda
update-grub
UEFI 模式下:
grub-install --boot-directory=/boot --efi-directory=/boot/efi
update-grub