4. ATF启动流程:从BL1到运行时代理

各位同学,今天我们来聊聊ATF的启动流程。说实话,这块内容我第一次接触时也绕了好一阵子。ATF的启动不像普通bootloader那样一条直线跑到底,它分了好几个阶段,每个阶段各司其职。

ATF的启动流程,说白了就是:BL1加载BL2,BL2再依次加载BL31、BL32、BL33。嗯,这个顺序你得记牢了。

4.1 BL1:第一级启动加载器

BL1是ATF启动的起点。它通常存放在ROM里,芯片上电后CPU直接跳到这里执行。

BL1的任务很简单:

  • 初始化最基本的硬件(比如串口、时钟)
  • 验证BL2的镜像签名
  • 把BL2加载到SRAM中
  • 跳转到BL2执行

我个人习惯把BL1看作是「保安」——它只负责开门,把下一个重要角色请进来。我在项目中遇到过,有些芯片的BL1代码量被限制得很死,ROM就那么几十KB,想多塞点功能都不行。

关键点:BL1不负责加载BL31/BL32/BL33,它只负责加载BL2。后面的工作交给BL2去做。

4.2 BL2:第二级启动加载器

BL2运行在SRAM中,它才是真正的「大管家」。BL2负责加载剩下的所有镜像:

  • BL31 — EL3运行时固件,负责安全监控
  • BL32 — TEE操作系统(如OP-TEE)
  • BL33 — 非安全世界的bootloader(通常是U-Boot或EDK2)

你想想看,BL2就像个快递分拣员,把三个包裹分别放到它们该去的地方。BL31放到安全内存,BL32放到TEE专用的安全区域,BL33放到非安全内存。

小技巧:调试时可以在BL2里加打印,确认每个镜像的加载地址是否正确。我曾经因为地址配错,BL31跑飞了,查了两天才找到原因。

4.3 BL31:EL3运行时固件

BL31是ATF的核心。它运行在EL3,是安全世界和非安全世界之间的「守门员」。

BL31的主要职责:

  • 提供运行时代理(Runtime Service)
  • 处理SMC(安全监控调用)异常
  • 实现PSCI(电源状态协调接口)
  • 管理CPU的休眠、唤醒、开关机

说白了,BL31就是那个「裁判」——非安全世界想干点跟电源、安全相关的事,都得通过SMC指令来请求BL31帮忙。

4.4 运行时代理(Runtime Service)

运行时代理是BL31提供的一组服务接口。非安全世界通过SMC指令调用这些服务。

常见的运行时代理包括:

服务类型 服务ID范围 说明
PSCI 0x84000000 - 0x8400FFFF 电源管理服务
SiP 0x82000000 - 0x8200FFFF 厂商自定义服务
TOS 0x83000000 - 0x8300FFFF TEE操作系统服务

举个例子,当Linux想关闭一个CPU核心时,它会发一个PSCI_CPU_OFF的SMC请求。BL31收到后,会执行对应的电源管理操作。

注意:运行时代理的注册顺序很重要。如果两个服务注册了相同的SMC ID,后注册的会覆盖前面的。我曾经踩过这个坑,调试时发现某个SMC调用总是不对,最后发现是服务ID冲突了。

4.5 PSCI接口详解

PSCI(Power State Coordination Interface)是ARM定义的一套电源管理标准接口。它让操作系统可以统一管理CPU的电源状态。

常用的PSCI接口:

  • PSCI_VERSION — 查询PSCI版本
  • CPU_ON — 启动一个CPU核心
  • CPU_OFF — 关闭一个CPU核心
  • CPU_SUSPEND — 让CPU进入休眠
  • SYSTEM_OFF — 关闭整个系统
  • SYSTEM_RESET — 重启系统

我建议你在调试时先验证PSCI_VERSION这个接口。它能帮你确认BL31是否正常工作,SMC通路是否打通。

// 在非安全世界调用PSCI_VERSION的示例
unsigned int psci_version(void)
{
    unsigned int ret;
    // SMC指令:调用PSCI_VERSION服务
    asm volatile(
        "mov x0, #0x84000000\n"  // PSCI_VERSION的SMC ID
        "smc #0\n"               // 触发安全监控调用
        "mov %0, x0\n"           // 获取返回值
        : "=r" (ret)
        :
        : "x0"
    );
    return ret;
}

这段代码看起来简单,但背后BL31做了不少事。它要解析SMC ID,找到对应的服务处理函数,然后返回结果。

4.6 启动流程图

下面我用一张图来总结ATF的启动流程。这张图我画了好几次才满意,希望能帮你理清思路。

ATF启动流程概览 BL1 ROM代码 加载并验证 BL2 SRAM 加载 BL31 EL3运行时 加载 BL32 TEE OS 加载 BL33 U-Boot/EDK2 运行时代理 SMC服务 PSCI接口 电源管理 包含 非安全世界 安全世界 TEE

从这张图你可以看到,BL2是启动流程的「枢纽」。它把BL31、BL32、BL33分别加载到各自的内存区域。BL31启动后,运行时代理和PSCI接口就绪,等待非安全世界通过SMC来调用。

总结一下:ATF启动流程就是「BL1→BL2→BL31/BL32/BL33」这样一条链。BL31是安全监控的核心,运行时代理是服务接口,PSCI是电源管理的标准。这三者配合,构成了ATF的运行时环境。

嗯,这一章的内容就到这里。下一章我们会深入BL31的初始化过程,看看它到底是怎么把运行时代理和PSCI注册起来的。

可可精品资料库