📖 推荐博主书籍:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry
UEFI Bootloader 全方位解读
面向嵌入式与服务器双场景,聚焦工程师实操所需:清晰的概念边界、启动链路、关键配置、常用工具、与 U‑Boot 的差异、以及在 Jetson Orin/通用 ARM64/PC 的落地路径。

1. 什么是 UEFI?
UEFI(Unified Extensible Firmware Interface)是操作系统与平台固件之间的标准化接口与执行环境。与传统 BIOS 相比,UEFI 提供:
- 统一的启动与运行时服务(Boot Services / Runtime Services)
- 标准化的磁盘分区(GPT)与 EFI 系统分区(ESP, FAT32)
- 可扩展的驱动与应用模型(EFI Drivers / EFI Applications)
- 安全启动链(Secure Boot:PK/KEK/db/dbx)
一句话:UEFI 是“标准化的固件层”,在 OS 启动前完成硬件初始化、提供统一接口,最终把控制权交给内核(Linux/Windows/BSD 等)。
2. 启动链路概览(抽象模型)
ROM →(SoC Early Boot: MB1/MB2/BL1…)→ UEFI 固件
→(Boot Services:定位并加载 EFI 应用/引导器)
→ Linux 内核(EFI Stub)/ GRUB / systemd-boot / Shim
→ 传递 ACPI/Device Tree、cmdline、initrd
→ 进入操作系统
-
EFI 应用可以是:
- 直接使用 EFI Stub 的 Linux 内核(把内核当作一个 EFI 程序启动)
- 通用引导器:GRUB、systemd-boot、GRUB+Shim(安全启动)
-
平台描述:x86 多用 ACPI;ARM 服务器与部分嵌入式常用 Device Tree(DTB),也逐步支持 ACPI。
3. 核心概念速览
- EFI System Partition(ESP):FAT32 分区,放置
\EFI\Vendor\*.efi与启动文件(AArch64 设备的默认回退路径:\EFI\BOOT\BOOTAA64.EFI)。 - NVRAM 启动变量:
Boot####、BootOrder、BootNext,由固件持久化保存,efibootmgr可管理。 - EFI Stub:Linux 内核内建的 UEFI 入口,使内核可作为
*.efi直接被 UEFI 加载;可通过内核命令行传入 DTB 与 initrd。 - Secure Boot:固件只运行受信任的已签名 EFI 映像。常见路径:
Shim → GRUB/systemd-boot → Linux,或直接签名后的vmlinuz.efi。
4. 工程师常用:最小可行启动(EFI Stub 直启)
4.1 准备 ESP 分区
# 假设目标磁盘 /dev/sdX
parted /dev/sdX mklabel gpt
parted /dev/sdX mkpart EFI fat32 1MiB 513MiB
parted /dev/sdX set 1 esp on
mkfs.vfat -F32 -n EFI /dev/sdX1
mkdir -p /mnt/esp && mount /dev/sdX1 /mnt/esp
4.2 放置文件与路径约定(AArch64)
/mnt/esp/EFI/BOOT/BOOTAA64.EFI ← 引导入口(回退路径)
/mnt/esp/EFI/Linux/vmlinuz.efi ← EFI Stub 内核(可直接被固件执行)
/mnt/esp/EFI/Linux/initrd.img ← 可选:initramfs
/mnt/esp/EFI/Linux/tegra.dtb ← 可选:DTB(或由固件传入)
4.3 创建/查看启动项
# 创建启动项(示例:NVMe 第 1 分区为 ESP)
efibootmgr -c -d /dev/nvme0n1 -p 1 \
-L "Linux EFI Stub" \
-l '\\EFI\\Linux\\vmlinuz.efi' \
-u 'root=UUID=<rootfs-uuid> rw \
initrd=\\EFI\\Linux\\initrd.img \
devicetree=\\EFI\\Linux\\tegra.dtb \
console=ttyS0,115200n8'
# 查看启动顺序与条目
efibootmgr -v
UEFI 文件路径使用 反斜杠(
\\),注意大小写与分区号。
5. 工程师常用:采用通用引导器(GRUB / systemd-boot)
- GRUB:功能全面、兼容性强,适合多系统/复杂菜单;支持 DTB/ACPI、LUKS、网络等。
- systemd-boot:轻量,基于 simple boot protocol,配合内核 EFI Stub 使用简洁高效。
- Shim(安全启动):由微软签名的最小加载器,固件验证 Shim → Shim 验证 GRUB/内核。Linux 发行版普遍采用。
放置规则(AArch64):
\EFI\BOOT\BOOTAA64.EFI:回退入口,可指向 Shim/GRUB/systemd-boot。- Vendor 路径:
\EFI\<Vendor>\*.efi,引导器与配置文件按其文档组织。
6. 安全启动(Secure Boot)与签名
6.1 概念
- PK/KEK/db/dbx:平台密钥、密钥交换密钥、允许名单、黑名单。
- 目标:只运行受信任的 EFI 映像(引导器、内核、驱动)。
6.2 开发常用签名流程(示意)
# 用 sbsigntool 对内核/引导器签名(示例)
sbsign --key PK.key --cert PK.crt \
--output vmlinuz.signed.efi vmlinuz.efi
- 使用 Shim:由固件验证 Shim,后续验证权交给 Shim/MOK(Machine Owner Key)体系,开发调试更灵活。
7. 设备树 / ACPI 的传递
- ARM/嵌入式常见:通过 EFI Stub 的
devicetree=指定 DTB,或由固件加载 DTB 传递给内核。 - ARM 服务器 / x86:ACPI 更常见;Linux 内核从 UEFI 接收 ACPI 表。
建议:在同一平台内保持一种主路径(DTB 或 ACPI),避免混杂。
8. Jetson Orin 的要点(结合 L4T 经验)
- Orin 使用 UEFI 固件(见出厂包中的
uefi_jetson.bin、BOOTAA64.EFI)。 - 设备端一般使用 EFI Stub 或通用引导器加载 Linux;部分发行包保留
extlinux.conf兼容以方便内核参数与多内核切换(厂商实现差异化)。 - 刷机与签名由 tegraflash、tegrasign 及 BUP 工具链完成;工程师侧重修改的是 ESP 内容、内核/DTB/initrd、引导器配置。
9. 与 U‑Boot 的对比(工程取舍)
| 维度 | UEFI | U‑Boot |
|---|---|---|
| 标准化 | 高:统一接口/变量/分区/服务 | 低:高度可裁剪,接口随移植而异 |
| 生态 | PC/Server/发行版原生支持 | 嵌入式/SoC 广泛,社区强 |
| 启动器 | EFI Stub / GRUB / systemd-boot / Shim | U‑Boot 脚本/菜单,extlinux/grub 兼容亦可移植 |
| 安全启动 | 体系成熟,厂商与发行版齐备 | 可实现,但多为厂商/方案方定制 |
| 调试 | EFI Shell、NVRAM、统一日志接口 | 命令行强大,外设覆盖广,移植灵活 |
| 适用 | 需要与通用 OS 生态无缝衔接 | 需要深度定制、快速移植与硬件 bring‑up |
实务建议:
- 面向产品/通用 OS:优先 UEFI(安全链、生态、量产一致性)。
- 早期 bring‑up/高度定制:U‑Boot 往往更高效,后期再迁移 UEFI。
10. 常见操作清单(Cheat‑Sheet)
创建 ESP(FAT32)
parted /dev/sdX mklabel gpt
parted /dev/sdX mkpart EFI fat32 1MiB 513MiB
parted /dev/sdX set 1 esp on
mkfs.vfat -F32 -n EFI /dev/sdX1
挂载与放置文件
mount /dev/sdX1 /mnt/esp
mkdir -p /mnt/esp/EFI/BOOT /mnt/esp/EFI/Linux
cp BOOTAA64.EFI /mnt/esp/EFI/BOOT/
cp vmlinuz.efi initrd.img tegra.dtb /mnt/esp/EFI/Linux/
创建启动项
efibootmgr -c -d /dev/sdX -p 1 \
-L "Linux" -l '\\EFI\\Linux\\vmlinuz.efi' \
-u 'root=UUID=<uuid> rw initrd=\\EFI\\Linux\\initrd.img \
devicetree=\\EFI\\Linux\\tegra.dtb console=ttyS0,115200n8'
查看/调整启动顺序
efibootmgr -v
# 置顶条目(示例 Boot0007)
efibootmgr -o 0007,0001,0002
签名(示例)
sbsign --key PK.key --cert PK.crt \
--output vmlinuz.signed.efi vmlinuz.efi
11. 调试与排错
- 串口日志:确保 UEFI console 指向板载 UART(例如
ttyS0/ttyAMA0/ttyTHS*),Kernel cmdline 添加console=。 - EFI Shell 工具:
map(查看设备/分区映射)、bcfg(管理启动项)、dmpstore(读写 NVRAM 变量)、memmap(内存分布)。 - NVRAM 丢失:RTC/NVRAM 断电后启动项丢失,依赖
BOOTAA64.EFI回退路径与自动发现;必要时在系统启动后用efibootmgr重建。 - 路径大小写与分隔符:UEFI 使用 FAT 与 反斜杠;Linux 下复制文件要注意大小写与转义。
- DTB/ACPI 冲突:保持单一路径(DTB 或 ACPI),并确保内核配置匹配。
12. 在 Yocto/发行版中的落地提示
- Yocto:在 wic kickstart 使用
bootimg-efi源,自动创建 ESP 并放置引导器/内核;镜像后期可用wic ls/挂载检查路径。 - 发行版:多数提供现成的 Shim/GRUB/systemd-boot 工具链;自定义内核时关注签名与
EFI/Linux目录结构。 - Jetson Orin:固件与刷机链路由 NVIDIA 提供,系统侧关注 ESP 内容与内核/DTB/引导器配置即可。
13. FAQ(工程师高频问题)
Q1:一定要 GRUB 吗?
A:不一定。EFI Stub 可直接启动内核;复杂菜单/多系统/加密场景,GRUB/systemd-boot 更合适。
Q2:Secure Boot 下怎样调试自编译内核?
A:使用 Shim + MOK 导入自签名证书,或在开发版固件中导入测试密钥;将 vmlinuz.efi 与引导器签名后再放入 ESP。
Q3:ARM 平台 DTB 怎么传?
A:常见做法是 devicetree=\\EFI\\Linux\\xxx.dtb 或由固件传入;确保 DTB 与内核版本匹配。
Q4:启动项总是被清空?
A:检查电池/RTC/NVRAM;保留 \EFI\BOOT\BOOTAA64.EFI 作为兜底入口,系统启动后用 efibootmgr 重建。
14. 结语
UEFI 把“平台差异”吸收到固件层,用标准化接口连接到通用 OS 与安全链。对于需要 安全、可维护、生态友好 的产品形态,UEFI 值得作为首选;而在原型阶段或重度定制,U‑Boot 的灵活性依然无可替代。将两者结合在项目生命周期的不同阶段,往往是更务实的工程方案。
1561

被折叠的 条评论
为什么被折叠?



