1. ATF与UEFI概述:启动链里的两个关键角色
做固件开发这些年,我经常被问到同一个问题:ATF和UEFI到底谁先跑? 说实话,我刚入行时也搞混过。直到有一次联调,板子死活起不来,最后发现是ATF和UEFI对内存视图的理解不一致——嗯,从那以后我才真正把这两者的协作关系摸透了。
这一章,我们先搭个框架。把ATF和UEFI各自是什么、怎么跑、怎么配合,一次性说清楚。
1.1 ATF架构解析:不只是安全启动
ATF(ARM Trusted Firmware),说白了就是ARM生态下的可信固件。它负责从CPU上电到操作系统启动之间,那段最敏感的安全阶段。
我个人习惯把ATF看作一个三层结构:
| 层级 | 异常级别 | 主要职责 | 典型组件 |
|---|---|---|---|
| BL1 | EL3 | 最底层的ROM代码,负责加载BL2 | BootROM |
| BL2 | S-EL1 | 可信启动加载器,验证并加载后续镜像 | Trusted Boot Firmware |
| BL31 | EL3 | 运行时固件,提供安全监控调用(SMC) | Runtime Firmware |
| BL32 | S-EL1 | 可信操作系统(如OP-TEE) | Secure OS |
| BL33 | EL2/EL1 | 非安全世界的启动加载器(通常是UEFI) | UEFI / U-Boot |
关键点:ATF的BL33就是UEFI的入口。ATF把控制权交给UEFI时,CPU已经处于EL2(虚拟化)或EL1(非安全)状态。UEFI不需要再切异常级别。
我在项目中遇到过一个问题:某款SoC的BL2在验证BL33签名时,因为证书链配置错误,导致UEFI永远跑不起来。排查了三天,最后发现是ATF的TRUSTED_BOARD_BOOT宏没开对。所以,ATF的配置项一定要和硬件一一对应,别想当然。
1.2 UEFI启动流程概览:从固件到OS
UEFI的启动流程,我习惯把它拆成七个阶段。你想想看,从按下电源键到看到操作系统Logo,中间经历了多少步?
- SEC(安全验证):CPU上电后的第一条指令,初始化缓存作为临时内存。
- PEI(EFI前初始化):检测内存、CPU、芯片组,建立内存映射。
- DXE(驱动执行环境):加载大部分设备驱动,初始化PCIe、USB、SATA等。
- BDS(启动设备选择):枚举启动设备,按优先级尝试启动。
- TSL(临时系统加载):加载操作系统引导器(如GRUB、Windows Boot Manager)。
- RT(运行时):UEFI进入运行时模式,提供Runtime Services给OS。
- AL(准备离开):UEFI交出控制权,OS接管。
我的经验:联调时最常卡在PEI和DXE阶段。PEI阶段内存还没完全初始化,调试手段极其有限。我建议你在PEI阶段多打一些串口日志,哪怕只输出一个字符,也能帮你判断死在哪一步。
1.3 ATF与UEFI的协作关系:谁先谁后?
这个问题其实很简单:ATF先跑,UEFI后跑。 但协作细节远不止这么简单。
我画了一张图,帮你理清整个启动链:
从图上你能看到:
- 安全世界(左侧):ATF的BL1→BL2→BL31→BL32,全部在EL3或S-EL1运行。
- 非安全世界(右侧):BL33(UEFI)→OS Bootloader→OS,在EL2/EL1运行。
- 协作点:BL31通过SMC(安全监控调用)为UEFI提供安全服务,比如设置安全内存、处理中断。
避坑指南:我曾经在联调时遇到一个诡异问题——UEFI调用SMC请求设置安全内存,结果ATF返回错误。查了两天,发现是UEFI传递的参数中,内存地址没有按4KB对齐。ATF的SMC处理函数对参数有严格的对齐要求,UEFI端一定要检查参数合法性,别指望ATF帮你兜底。
1.4 协作中的关键数据结构
ATF和UEFI之间传递信息,主要靠共享内存和寄存器。我整理了一个常用数据结构的对照表:
| 数据结构 | 定义方 | 消费方 | 传递内容 |
|---|---|---|---|
boot_params |
ATF (BL31) | UEFI (BL33) | 内存布局、CPU信息、DDR大小 |
smc_args |
UEFI | ATF (BL31) | SMC函数ID、参数1-7 |
entry_point_info |
ATF (BL2) | UEFI (BL33) | 入口地址、栈指针、异常级别 |
shared_mem |
双方协商 | 双方 | 日志缓冲区、事件通知 |
我的习惯:联调初期,我会在共享内存里放一个魔数(Magic Number)。ATF写入一个值,UEFI读取并校验。如果魔数不对,说明共享内存的地址映射有问题。这个小技巧帮我快速定位过至少三次联调故障。
1.5 本章小结
这一章我们搭好了ATF和UEFI协作的框架。说白了就是:
- ATF负责安全世界的初始化,跑在EL3。
- UEFI负责非安全世界的启动,跑在EL2/EL1。
- 两者通过SMC和共享内存协作。