3. TF-A架构概览
TF-A(Trusted Firmware-A)并不是一个单一固件,而是一组按“启动阶段”拆分的镜像集合。理解 TF-A 的关键,不是记住某个函数名,而是先建立一张“阶段—职责—运行环境—镜像”的对应关系图。只有把 BL1 到 BL33 的接力关系看清楚,后续学习运行时服务、PSCI、SMC 异常处理和安全启动时,才不会把不同阶段的代码混在一起。
一、各阶段职责与运行环境
TF-A 的启动阶段按 ARM 异常等级(Exception Level)划分。BL1 通常运行在 EL3,是芯片上电后最早执行的固件之一;BL2 也运行在 EL3,但它的使命是“一次性”的镜像加载与验证;BL31 同样运行在 EL3,却是常驻的运行时固件,负责处理来自 Secure/Non-secure 世界的 SMC 调用;BL32 运行在 EL1 Secure,提供可信服务;BL33 运行在 EL1 Non-secure,最终把控制权交给操作系统。
| 阶段 | 典型运行等级 | 核心职责 | 是否常驻 |
|---|---|---|---|
| BL1 | EL3 | 上电初始化、建立信任根、加载并验证 BL2 | 否 |
| BL2 | EL3 | 解析 FIP、加载 BL31/BL32/BL33、完成镜像验证 | 否 |
| BL31 | EL3 | 运行时服务、PSCI、SMC 处理、异常向量管理 | 是 |
| BL32 | EL1 Secure | 可信操作系统或 Secure Payload(如 OP-TEE) | 是 |
| BL33 | EL1 Non-secure | Non-secure 引导程序,最终引导 Linux 等系统 | 否 |
二、镜像布局:FIP 与镜像包
BL2 之后的镜像通常被打包进 FIP(Firmware Image Package)。FIP 是一个容器格式,内部按 UUID 标识不同镜像,例如 BL31、BL32、BL33、SCP_BL2、TOS_FW_CONFIG 等。BL1 一般独立烧录在 Boot ROM 或 Flash 固定位置,因为它需要在上电后第一时间被取指执行。BL2 则可能位于 FIP 中,也可能作为独立镜像存在,取决于芯片厂商的启动方案。
在典型布局中,BL1 位于只读启动介质,BL2 紧随其后或位于 FIP 内,BL31/BL32/BL33 由 BL2 从 FIP 中解析并加载到内存。BL31 必须常驻内存,因为后续 OS 运行期间仍会通过 SMC 进入 EL3;BL32 若存在,也需要常驻;BL33 则作为 Non-secure 世界的入口,最终被 OS 替换或覆盖。
典型 FIP 内容示例:
fip.bin
├── bl31.bin (EL3 运行时固件)
├── bl32.bin (可选,Secure Payload)
├── bl33.bin (U-Boot / UEFI)
├── tb_fw_config.dtb
└── tos_fw_config.dtb
三、启动流程:从 BL1 到 BL33 的接力
启动流程可以概括为“验证—加载—跳转”的链式接力。BL1 上电后先完成 CPU 基础初始化、异常向量设置、串口调试初始化,然后从启动介质读取 BL2,验证其签名或哈希,验证通过后跳转到 BL2。BL2 运行后解析 FIP,依次加载 BL31、BL32(可选)、BL33,并完成对应验证。随后 BL2 跳转到 BL31。
BL31 初始化运行时服务框架,设置 EL3 异常向量,处理 PSCI 和 SMC 调用。如果存在 BL32,BL31 会负责进入 Secure Payload;如果没有 BL32,BL31 直接准备进入 BL33。最终,BL31 通过 ERET 或类似机制跳转到 BL33,由 BL33 引导 Non-secure 操作系统。操作系统启动后,BL31 仍驻留在 EL3,持续为系统提供运行时服务。
四、案例场景:一次典型的安全启动
假设某 ARM 平台使用 TF-A + OP-TEE + U-Boot + Linux。上电后,Boot ROM 从 Flash 读取 BL1,BL1 验证 BL2 签名后跳转。BL2 读取 FIP,依次加载 BL31、BL32、BL33,并验证每个镜像的哈希或签名。BL2 跳转到 BL31 后,BL31 初始化 PSCI 和 SMC 处理框架,然后进入 BL32(OP-TEE)完成可信 OS 初始化。最后 BL31 跳转到 BL33(U-Boot),U-Boot 引导 Linux。Linux 运行后,当需要 CPU 热插拔或系统休眠时,内核通过 SMC 指令进入 BL31,由 BL31 完成电源管理操作。
五、常见误区与复盘
- 误区一:把 BL2 当成常驻固件。BL2 只在启动早期运行一次,完成加载和验证后就把控制权交给 BL31,之后不再参与运行时服务。
- 误区二:认为 BL32 一定存在。BL32 是可选的。没有可信 OS 或 Secure Payload 时,BL31 可以直接跳转到 BL33。
- 误区三:混淆 BL31 与 BL33 的异常等级。BL31 运行在 EL3,负责安全监控和运行时服务;BL33 运行在 EL1 Non-secure,是普通世界的引导程序。
- 误区四:忽略 FIP 的 UUID 匹配。BL2 解析 FIP 时按 UUID 查找镜像,如果打包时 UUID 不匹配,会出现“镜像存在但加载失败”的问题。
复盘时可以用一句话串联:BL1 建立信任根并验证 BL2,BL2 解析 FIP 并加载 BL31/BL32/BL33,BL31 常驻 EL3 提供运行时服务,BL32 提供可选的可信执行环境,BL33 最终引导 Non-secure 操作系统。把这条链记住,后续分析 PSCI、SMC、安全启动和镜像签名时,就能快速定位问题所在的阶段。