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

* 原文：[BIOS ブートと UEFI ブートで GPT パーティションの 違 いと 作 り 方](https://qiita.com/nanorkyo/items/429d7382a418b38de4d3)
* 作者：重村法克
* 2020-11-11

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

## 前提条件

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

## 通用操作

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

```sh
gpart create -s GPT ada0
```

为了简化讨论，假设我们分配了以下分区：

| 设备名    | 分区类型               | 用途         |
| ------ | ------------------ | ---------- |
| ada0p1 | freebsd-boot 或 efi | 启动分区       |
| ada0p2 | freebsd-ufs \[3]   | FreeBSD 分区 |
| ada0p3 | freebsd-swap       | 交换分区       |

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

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

## 在 BIOS 启动情况下

```sh
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。
  * 因此，调整分区大小没有必要，也没有更多的空间来增大它。

```sh
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 启动情况下

```sh
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](https://reviews.freebsd.org/D6935) 的讨论中指出，为了支持固件更新工具等 EFI 应用程序，800KiB 的分区大小可能过小。

```sh
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](https://wiki.freebsd.org/UEFI#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` 命令进行覆盖（[后续说明](https://qiita.com/nanorkyo/items/429d7382a418b38de4d3#%E4%BB%98%E9%8C%B2%E3%83%96%E3%83%BC%E3%83%88%E3%83%AD%E3%83%BC%E3%83%80%E3%83%BC%E3%81%AE%E6%9B%B4%E6%96%B0)）。

### 问：如果分区号不是 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 启动情况下

```sh
gpart bootcode -p /boot/gptboot    -i 1 ada0
        或
gpart bootcode -p /boot/gptzfsboot -i 1 ada0
```

### UEFI 启动的情况

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

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

接着，创建 `/boot/efi` 目录。

```sh
mkdir -p /boot/efi
```

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

```sh
mount /boot/efi
```

之后的更新操作如下：

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

### 参考文献

* [gpart(8) 的手册](https://www.freebsd.org/cgi/man.cgi?gpart%288%29)
* [FreeBSD 的启动过程](https://qiita.com/mzaki/items/76acac14c16ac6789e68)
* [UEFI - FreeBSD Wiki](https://wiki.freebsd.org/UEFI)
* [FreeBSD 10.4 版本说明](https://www.freebsd.org/releases/10.4R/relnotes.html)
* [FreeBSD 11.1 版本说明](https://www.freebsd.org/releases/11.1R/relnotes.html)
* [bsdinstall: 增加 EFI 分区大小至 200MB](https://reviews.freebsd.org/D6935)
* [GPT 和 MBR 的区别是什么？](http://syuu1228.hatenablog.com/entry/20130103/1357165915)
* [通过命令行创建 FreeBSD 启动分区等](http://nao550.hateblo.jp/entry/2018/02/12/214146)
* [FreeBSD/UEFI 相关信息](http://zenno.com/pukiwiki/index.php?FreeBSD%2FUEFI%A4%CB%A4%C4%A4%A4%A4%C6)

***

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 分区，但其优先级和控制方式较难解释，因此请参考 [参考文献](https://qiita.com/mzaki/items/76acac14c16ac6789e68#loaderefi)。虽然并不复杂，但因为需要对文件系统级别进行调整，所以需要进一步深入了解。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://translated-articles.bsdcn.org/2024-nian-7-yue/uefi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
