使用 BIOS 引导和 UEFI 引导的 GPT 分区的区别和制作方法

在当前的 FreeBSD 中,不论磁盘大小,几乎都建议使用 GPT(GUID 分区表)来进行分区配置。然而,在传统的 BIOS 启动和 UEFI 启动的情况下,分区配置会有所不同 [1]。以下将介绍两者的区别,并提供可用的启动分区配置示例。

前提条件

在这里,我们假设操作的是 SATA 磁盘,设备名称表示为 /dev/ada0。如果是 SAS/USB 磁盘,设备名为 dan,NVMe 磁盘为 nvdn,eMMC 磁盘为 mmcsdn(其中 n 是大于等于 0 的整数)。

通用操作

由于使用的是 GPT 分区,在所有操作步骤中,都必须执行以下命令 [2]:

gpart create -s GPT ada0

为了简化讨论,假设我们分配了以下分区:

设备名
分区类型
用途

ada0p1

freebsd-boot 或 efi

启动分区

ada0p2

freebsd-ufs [3]

FreeBSD 分区

ada0p3

freebsd-swap

交换分区

在本讨论中,ada0p2ada0p3 使用相同的通用步骤。即执行以下命令,虽然这些命令在当前场景中可能并不立即有用 [4][5] [6]:

gpart add -t freebsd-ufs  ada0
gpart add -t freebsd-swap ada0

在 BIOS 启动情况下

gpart add -t freebsd-boot -b 40 -s 984  ada0
  • 我们为启动分区定义了 freebsd-boot 类型。如果不是 freebsd-boot,引导加载器将无法发现该分区。

  • 起始位置(-b)指定为从第 40 扇区(LBA 40)开始。

    • GPT 分区表头大小为 34 扇区,但在支持 4KiB 扇区的磁盘上,起始位置可能会被四舍五入为 8 的倍数。

    • 近期版本中,GPT 分区表头的大小已经增加为 40 扇区(具体从哪个版本开始的尚未确认)。

  • 分区大小(-s)推荐为 984 扇区。

    • 这样可以确保下一分区(freebsd-ufs)从 512KiB 边界开始 [8]。

    • 由于引导加载器的限制,分区大小不得小于 545KiB,所以下面的大小为 492KiB。

    • 因此,调整分区大小没有必要,也没有更多的空间来增大它。

gpart bootcode -b /boot/pmbr -p /boot/gptboot    -i 1 ada0
        或者
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0

以上步骤完成后,引导加载器安装完毕了。引导加载器会查找 FreeBSD 分区 [9][10],然后将控制权交给 /boot/loader/boot/zfsloader

在 UEFI 启动情况下

gpart add -t efi -b 40 -s 409560 ada0
  • 我们为启动分区定义了 efi 类型。如果不是 efi,UEFI 将无法发现该分区。

  • 起始位置(-b)指定为从第 40 扇区(LBA 40)开始。

    • GPT 分区表头的大小为 34 扇区 [7],但在支持 4KiB 扇区的磁盘上,起始位置可能会被四舍五入为 8 的倍数。

    • 近期版本中,GPT 分区表头的大小已调整为 40 扇区(具体从哪个版本开始尚未确认)。

  • 分区大小(-s)建议设置为 409560 扇区。

    • 这个设置确保下一个分区(freebsd-ufs)从 200MiB 边界开始。

    • 该分区的实际大小略小于 200MiB(少 40 扇区,即 20KB),但可以忽略不计。

    • 目前,11.2-R 的启动分区(/boot/boot1.efifat)的大小为 800KiB。

    • 在 10.4-R 或 11.1-R 版本中,推荐为该分区分配 200MiB,以考虑与其他操作系统(如 macOS)的兼容性。如果仅启动 FreeBSD,800KiB 的大小应无问题。

    • bsdinstall: 增加 EFI 分区大小至 200MB 的讨论中指出,为了支持固件更新工具等 EFI 应用程序,800KiB 的分区大小可能过小。

newfs_msdos -F 32 -c 1 -L EFISYS /dev/ada0p1
mount -t msdosfs /dev/ada0p1 /mnt
mkdir -p /mnt/EFI/BOOT
cp /boot/loader.efi /mnt/EFI/BOOT/BOOTX64.efi
umount /mnt
        或者
gpart bootcode -p /boot/boot1.efifat -i 1 ada0

完成上述步骤后,启动加载器将安装完毕。启动加载器会查找 FreeBSD 分区,并继续启动过程。

常见问题与解答

问:为什么与 Bootable UEFI memory stick or Hard Disk 上的步骤不同?

答:没问题,完全没问题。时代已经跟上了。

问:通过各种资料查看,似乎有很多方法来写入 /boot/boot1.efifat 分区,该采用哪种方式才正确?

答:没问题,任何方法都可以。但我不推荐任何方法。

/boot/boot1.efifat 实际上是分区镜像本身。极端地说,可以认为是 dd if=/dev/ada0p1 of=/boot/boot1.efifat 的结果。实际构建时也会做类似的操作。

因此,无论是使用 dd(8) 还是 gpart(8) 写入都没问题,但显然,gpart(8) 是更聪明的选择。

不过,最好避免使用 /boot/boot1.efifat。正如前面提到的,扩展到 200MiB 后,这个分区只能访问 800KiB 的空间。

尽管分配了 200MiB 的空间,但 EFI 应用程序无法在这 200MiB 中运行。

新安装不会有问题,但更新时,使用这种方式可能会不必要地删除一些内容。

问:在操作系统更新时,是否需要更新启动分区?

答:并非每次都需要,但有时需要,具体情况如下:

  1. 从 UFS 启动 时,由于 UFS 的格式稳定性,启动加载器代码通常不会发生变化,所以几乎不会出现问题。即使没有更新启动分区,通常也不会发现问题,除非从 UFS1 升级到 UFS2。

  2. 从 ZFS 启动 时,由于 ZFS 格式的不稳定性,启动加载器代码会发生变化。因此,必须定期维护启动分区,否则可能无法启动。有关这一点,/usr/src/UPDATING 中的 ZFS notes 提到:“如果更新启动的 ZFS 池的版本,请确保更新启动加载器。”

因此,除了更新步骤外,更新启动加载器的步骤也应纳入操作流程。

对于 freebsd-boot 分区,可以通过 gpart bootcode -p 命令覆盖,但对于 EFI 分区,需要先挂载,再通过 cp 命令进行覆盖(后续说明)。

问:如果分区号不是 1,那么是否可以随意设置?

答:不行,最好不要这样做。

由于 MBR 存在 2TiB 的限制,如果使用超过 2TiB 的空间,BIOS 可能无法找到启动加载器(freebsd-boot)。

另外,如果分区号和分区顺序不一致,管理起来会很麻烦。

问:我们使用的是 GPT 分区,为什么还要管 MBR?

答:遗憾的是,GPT 是 MBR 的上位兼容,所以不能完全忽略它。

对于 UEFI 启动,GPT 被视为 GPT,不用担心 MBR 的问题。

然而对于 BIOS 启动,GPT 会表现得像 MBR,因此需要在前 2TiB 内有启动加载器(freebsd-boot)。不过,是否使用分区号 1 并不重要。

问:我不确定系统是 UEFI 启动还是 BIOS 启动,怎么确定?

答:很简单!在安装 CD 上启动为 LiveCD 后,执行命令 sysctl machdep.bootmethod。如果是 UEFI 启动,显示的是 UEFI;如果是 BIOS 启动,则显示的是 BIOS。

【附录】启动加载器更新

BIOS 启动情况下

gpart bootcode -p /boot/gptboot    -i 1 ada0

gpart bootcode -p /boot/gptzfsboot -i 1 ada0

UEFI 启动的情况

首先,在 /etc/fstab 中添加以下设置。

# Device    Mountpoint FStype  Options Dump Pass #
/dev/ada0p1 /boot/efi  msdosfs rw      0    0

接着,创建 /boot/efi 目录。

mkdir -p /boot/efi

首次可以手动执行挂载。当然,也可以重启后无需特别关注。

mount /boot/efi

之后的更新操作如下:

cp /boot/loader.efi /boot/efi/EFI/BOOT/BOOTX64.efi

参考文献


  1. 在 BIOS 中,通常使用“MBR(主引导记录)引导”,但是由于 2 TiB 限制的严格性以及几乎没有多重引导需求,因此已经统一采用了 GPT 引导(?)

  2. 执行此命令没有过多或不足之处。从兼容性的角度来看,根本没有修改默认值的余地。

  3. 虽然有时可能希望将 freebsd-ufs 改为 freebsd-zfs,但在本次讨论中暂且省略这一点。

  4. 实际上,需要使用 -s 尺寸 选项来指定大小。如果没有指定,意味着使用剩余的所有空间。也就是说,如果直接执行,将无法为交换空间分配空间。

  5. 执行顺序需要注意。如果按此顺序执行,将无法分配启动分区(分区号会错位)。

  6. 可以使用 -i 分区号-b 起始位置 -i 分区号 选项来进行控制,但作为基本说明,建议不使用这些选项。

  7. LBA 0 到 LBA 33 是 GPT 头区域。

  8. 在现代各种介质(例如 4 KiB 扇区的 HDD 或 NAND 闪存等)中,边界 的最小公倍数(如果有 512 KiB 则适用于任何介质)是一个相当合理的数字(应该如此)。

  9. gptboot 会查找 freebsd-ufs 分区中的 /boot/loader,gptzfsboot 会查找 freebsd-zfs 分区中的 /boot/zfsloader。

  10. 由于“/boot/(zfs)loader”绑定到存储该文件的分区的文件系统,因此在引导时会解释为 UFS,而根文件系统使用 ZFS 的混合环境会解释为“UFS”。

  11. 会查找 freebsd-ufs 或 freebsd-zfs 分区,但其优先级和控制方式较难解释,因此请参考 参考文献。虽然并不复杂,但因为需要对文件系统级别进行调整,所以需要进一步深入了解。

最后更新于