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 陷入 EL3 请求服务。

三、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 上线。流程如下:

  1. Linux 内核准备 CPU1 的入口地址和上下文 ID,填入 X1~X3。
  2. X0 填入 PSCI_CPU_ON_64 功能号 0xC4000003。
  3. 执行 smc #0,处理器从 EL1 陷入 EL3。
  4. TF-A 的 SMC 处理程序读取 X0,识别为 PSCI 调用,分派到 PSCI 模块。
  5. PSCI 模块检查 CPU1 状态,配置平台电源控制器,释放 CPU1 复位。
  6. CPU1 从 TF-A 指定的入口开始执行,最终进入 Linux 内核的 secondary 启动路径。
  7. TF-A 返回 X0=0 给 Linux,表示 CPU_ON 成功。
这个场景说明:Linux 并不直接操作电源硬件,而是通过 SMC 请求 EL3 的 TF-A 代劳。TF-A 成为普通世界与平台电源硬件之间的“可信中介”。

六、常见误区与复盘

  • 误区一: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 的分工,以及安全启动链的建立,都建立在这套异常等级与安全状态模型之上。

Armv8-A 异常等级与安全状态协作模型 EL3 · Secure Monitor TF-A BL31 运行于此 · 处理 SMC 异常 · 切换安全状态 · 实现 PSCI SCR_EL3.NS 控制 EL2 · Hypervisor 虚拟机管理 · 第二阶段地址翻译 · 虚拟中断注入 EL1 · Guest OS / Linux Kernel 进程调度 · 内存管理 · 驱动 · 发起 SMC 调用 EL0 · 用户应用程序 普通应用 · 无系统寄存器访问权限 SMC #0 → 陷入 EL3 PSCI 功能号 0xC4000003 = CPU_ON 安全状态 非安全状态