2. 基础知识
要理解 TF-A(Trusted Firmware-A)为什么存在、它运行在什么位置、以及它如何与操作系统和电源管理框架协作,必须先建立四个基础概念:异常等级(Exception Level, EL)、安全状态(Security State)、SMC 调用约定以及 PSCI 与 TF-A 的关系。这四者共同构成了 Armv8-A 平台上“谁在什么权限下、通过什么接口、完成什么服务”的完整图景。
一、异常等级:权限的四个台阶
Armv8-A 用异常等级描述处理器当前的权限层级。等级越高,权限越大;低等级代码必须通过受控入口才能请求高等级服务。
- EL0:用户态,运行普通应用程序,权限最低,不能直接访问系统寄存器。
- EL1:内核态,运行 Linux 内核、Hypervisor 之下的 Guest OS 等,负责进程调度、内存管理和驱动。
- EL2:虚拟化层,运行 Hypervisor,负责虚拟机切换、第二阶段地址翻译和虚拟中断注入。
- EL3:安全监控层,运行 Secure Monitor,是安全世界与非安全世界之间的唯一受控通道。
关键点在于:EL3 是最高特权级,且通常只有 EL3 能配置安全状态切换。TF-A 的 BL31 阶段正是运行在 EL3 的 Secure Monitor,它负责处理来自 EL1/EL2 的 SMC 调用,并决定是否切换到安全世界(如 OP-TEE)或执行电源管理操作。
二、安全状态:两个世界的隔离
Armv8-A 的安全扩展把系统划分为安全世界(Secure World)和非安全世界(Non-secure World)。两者拥有独立的地址空间、外设访问权限和中断路由。非安全世界包括普通 Linux、Android 等;安全世界包括可信操作系统(如 OP-TEE)、安全监控程序等。
安全状态由 SCR_EL3.NS 位控制:当 NS=0 时处理器处于安全状态,NS=1 时处于非安全状态。EL3 的 Secure Monitor 在异常入口和返回时保存/恢复上下文,并切换 NS 位,从而实现两个世界的隔离与受控通信。
三、SMC 调用约定:低权限请求高权限服务的标准入口
SMC(Secure Monitor Call)是 Armv8-A 提供的同步异常指令,用于从 EL1/EL2 陷入 EL3。它有两种触发方式:SMC 指令和 HVC 指令(后者用于虚拟化场景)。在 TF-A 中,SMC 是普通世界请求安全服务、电源管理服务的主要通道。
SMC 调用约定遵循 SMC Calling Convention(SMCCC),核心规则如下:
- 功能号放在
X0寄存器中,高 32 位表示调用类型(如 PSCI、SiP、OEM),低 32 位表示具体功能。 - 参数依次放在
X1~X6寄存器中。 - 返回值放在
X0~X3中,其中X0通常返回错误码或结果。 - 调用类型由功能号高 32 位区分,例如
0x84000000表示 PSCI,0xC4000000表示 64 位 PSCI。
// 以 PSCI CPU_ON 为例(64 位调用)
// X0 = 0xC4000003 (PSCI_CPU_ON_64)
// X1 = target_cpu (目标 CPU 的 MPIDR)
// X2 = entry_point (非安全世界入口地址)
// X3 = context_id (上下文标识)
// 执行 smc #0 后,X0 返回 0 表示成功
TF-A 在 EL3 的异常向量表中注册 SMC 处理函数,根据 X0 的高 32 位分派到不同服务模块:PSCI 服务、SiP 服务、OEM 服务或标准安全服务。
四、PSCI 与 TF-A 的关系
PSCI(Power State Coordination Interface)是 Arm 定义的一套电源管理接口标准,规定了 CPU 热插拔、空闲状态、系统关机/重启等操作的调用方式。它本身是接口规范,不是实现。
TF-A 则是 PSCI 在 EL3 的参考实现。Linux 内核通过 SMC 指令调用 PSCI 功能号,陷入 EL3 后由 TF-A 的 PSCI 模块处理。TF-A 负责协调多个 CPU 的上下线、保存/恢复上下文、与平台电源控制器交互,最终完成电源状态切换。
| 概念 | 角色 | 运行位置 | 与 TF-A 的关系 |
|---|---|---|---|
| EL3 | 最高异常等级 | 处理器特权级 | TF-A BL31 运行于此 |
| 安全状态 | 安全/非安全隔离 | SCR_EL3.NS 控制 | TF-A 负责切换与上下文保存 |
| SMC | 同步异常指令 | EL1/EL2 发起 | TF-A 在 EL3 处理 SMC 异常 |
| PSCI | 电源管理接口规范 | Linux 内核调用 | TF-A 提供 EL3 实现 |
五、典型场景:Linux 如何通过 PSCI 让一个 CPU 上线
假设 Linux 运行在 CPU0 上,现在要让 CPU1 上线。流程如下:
- Linux 内核准备 CPU1 的入口地址和上下文 ID,填入 X1~X3。
- X0 填入
PSCI_CPU_ON_64功能号0xC4000003。 - 执行
smc #0,处理器从 EL1 陷入 EL3。 - TF-A 的 SMC 处理程序读取 X0,识别为 PSCI 调用,分派到 PSCI 模块。
- PSCI 模块检查 CPU1 状态,配置平台电源控制器,释放 CPU1 复位。
- CPU1 从 TF-A 指定的入口开始执行,最终进入 Linux 内核的 secondary 启动路径。
- TF-A 返回 X0=0 给 Linux,表示 CPU_ON 成功。
六、常见误区与复盘
- 误区一:EL3 就是安全世界。EL3 是异常等级,安全状态是另一个维度。EL3 可以运行在安全状态,也可以配置为非安全状态,但 TF-A 的 Secure Monitor 通常运行在安全状态的 EL3。
- 误区二:SMC 只能用于安全服务。SMC 也用于 PSCI 电源管理、SiP 平台服务等,功能号高 32 位决定服务类型。
- 误区三:PSCI 是 TF-A 的一部分。PSCI 是 Arm 规范,TF-A 只是实现之一;其他固件(如 U-Boot 的 PSCI 实现)也可以提供 PSCI 服务。
- 误区四:EL2 一定存在。如果系统不启用虚拟化,EL2 可能未使用,但 EL3 和 EL1 仍然存在。
理解这四个基础概念后,就能看清 TF-A 的定位:它运行在最高特权级 EL3,作为安全状态切换的守门人,通过 SMC 调用约定接收普通世界的请求,并以 PSCI 等标准接口提供电源管理和安全服务。后续章节中 BL1、BL2、BL31、BL33 的分工,以及安全启动链的建立,都建立在这套异常等级与安全状态模型之上。