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 Components

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

GRUB 安装实例

  1. 将 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
  2. 将 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不可省略。

  3. 将 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一般可以省略。

  4. 将 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),可按如下操作:

  1. 载入 GPT 分区表支持模块:insmod part_gpt
  2. 查看存储设备及分区:ls
  3. 假设计算机硬盘被识别成 hd1,设置 hd1,gpt2 为根分区:set root=hd1,gpt2
  4. 查看根分区内容:ls /

    查看/boot目录内容:ls /boot

    查看/boot/grub目录内容ls /boot/grub

  5. 载入 Linux 内核:linux /boot/vmlinuz-4.9.0-deepin2-amd64 root=/dev/sda2(示例,也可以用linux /vmlinuz root=/dev/sda2
  6. 载入初始化内存盘:initrd /boot/initrd.img-4.9.0-deepin2-amd64(或initrd /initrd.img
  7. 启动系统:boot

如果一切正常,系统会正常启动。此外,在上面第4步的时候,也可以用source /boot/grub/grub.cfg命令载入硬盘上的 GRUB 配置文件,然后按Esc返回 GRUB 菜单界面,会看到原本电脑上 GRUB 菜单,直接选择 deepin 系统启动即可。

在 LIVE 环境修复 GRUB 引导

进入 LIVE 环境

使用系统修复光盘或U盘启动计算机即可进入 Live 桌面环境。

进入 CHROOT 环境

在 Live 桌面环境中打开终端

确定硬盘上系统的各个挂载点的分区,以下表所示情况举例:

挂载点分区备注
/boot/efi/dev/sda1UEFI 下特有
//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

参考资料

  1. ArchWiki:Arch boot process (简体中文)
  2. 维基百科:主引导记录
  3. 维基百科:统一可扩展固件接口
  4. 维基百科:GNU GRUB
  5. ArchWiki:GRUB (简体中文)
  6. GNU GRUB Manual 2.02
  7. 维基百科:Windows Boot Manager
  8. 维基百科:NTLDR

标签: Linux, GRUB

添加新评论