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,中间经历了多少步?

  1. SEC(安全验证):CPU上电后的第一条指令,初始化缓存作为临时内存。
  2. PEI(EFI前初始化):检测内存、CPU、芯片组,建立内存映射。
  3. DXE(驱动执行环境):加载大部分设备驱动,初始化PCIe、USB、SATA等。
  4. BDS(启动设备选择):枚举启动设备,按优先级尝试启动。
  5. TSL(临时系统加载):加载操作系统引导器(如GRUB、Windows Boot Manager)。
  6. RT(运行时):UEFI进入运行时模式,提供Runtime Services给OS。
  7. AL(准备离开):UEFI交出控制权,OS接管。

我的经验:联调时最常卡在PEI和DXE阶段。PEI阶段内存还没完全初始化,调试手段极其有限。我建议你在PEI阶段多打一些串口日志,哪怕只输出一个字符,也能帮你判断死在哪一步。

1.3 ATF与UEFI的协作关系:谁先谁后?

这个问题其实很简单:ATF先跑,UEFI后跑。 但协作细节远不止这么简单。

我画了一张图,帮你理清整个启动链:

ATF与UEFI启动协作流程图 ATF与UEFI启动协作流程图 BL1 (BootROM) BL2 (Trusted Boot) BL31 (Runtime) BL32 (Secure OS) BL33 (UEFI) OS Bootloader Operating System SMC调用 / 上下文切换 协作关键点 ATF在EL3提供安全服务 UEFI通过SMC请求安全操作

从图上你能看到:

  • 安全世界(左侧):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和共享内存协作。