4、BL2阶段日志解读:可信启动流程、FIP镜像解析、SCP_BL2/BL31/BL32镜像加载

BL2阶段,说白了就是ATF的“信任根”落地的地方。我刚开始接触ATF时,总觉得BL1才是起点,后来才发现——BL2才是真正建立信任链的关键环节。它负责验证所有后续镜像的合法性,然后才敢把它们加载到内存里。

这一章,我们重点看三件事:可信启动流程怎么走、FIP镜像怎么解析、以及SCP_BL2/BL31/BL32这三个镜像的加载细节。日志里每一行输出,背后都对应着硬件状态和软件逻辑的交互。

4.1 可信启动流程:信任链是怎么建立的?

ARM平台的可信启动,核心思想是“逐级验证”。BL1验证BL2,BL2验证后续所有镜像。这个链条一旦断了,系统就不敢往下走。

我遇到过一个问题:某款芯片在量产时,BL2日志里突然出现Authentication failed。查了半天,发现是证书签名工具链版本不一致导致的。嗯,这种坑踩过一次就记住了。

典型的可信启动流程如下:

  1. BL1加载BL2:从BootROM读取BL2镜像,验证其数字签名。
  2. BL2初始化平台:设置DDR、时钟、中断控制器等。
  3. BL2解析FIP:从Flash中读取FIP镜像,提取各个组件的证书和镜像。
  4. BL2验证SCP_BL2:使用公钥验证SCP_BL2的签名。
  5. BL2验证BL31:同样走证书链验证。
  6. BL2验证BL32:如果启用了TEE,这一步必须过。
  7. BL2跳转到BL31:所有验证通过后,交出控制权。

关键点:BL2的验证是强制性的。如果任何一个镜像验证失败,系统会直接挂死或进入错误处理流程。日志里如果看到ERROR或PANIC,基本就是这里出了问题。

下面这张图,是我自己画的可信启动流程。你看一眼,应该就能理解整个链条是怎么串起来的。

BL2可信启动流程 BL2可信启动流程 BL1 加载并验证 BL2 BL2 初始化平台 BL2 解析 FIP 镜像 验证 SCP_BL2 验证 BL31 验证 BL32 (可选) 跳转到 BL31 任何一步验证失败 → 系统挂死或进入错误处理流程

4.2 FIP镜像解析:BL2怎么找到各个组件?

FIP(Firmware Image Package)是ATF用来打包多个镜像的文件格式。BL2启动时,会从Flash的固定偏移读取FIP头部,然后根据头部信息找到每个子镜像的位置。

FIP的结构其实不复杂。我拆开看过很多次,核心就三部分:

  • 头部:包含魔数、版本、镜像数量。
  • 目录表:每个条目描述一个子镜像的UUID、偏移、大小。
  • 镜像数据:按目录表顺序排列的二进制数据。

日志里常见的FIP相关输出长这样:

INFO:    Loading image 'scp_bl2' from FIP at 0x1000
INFO:    Image 'scp_bl2': offset 0x2000, size 0x8000
INFO:    Authentication of 'scp_bl2' passed
INFO:    Loading image 'bl31' from FIP at 0x1000
INFO:    Image 'bl31': offset 0xA000, size 0x10000
INFO:    Authentication of 'bl31' passed
INFO:    Loading image 'bl32' from FIP at 0x1000
INFO:    Image 'bl32': offset 0x1A000, size 0x20000
INFO:    Authentication of 'bl32' passed

你看,每一行都告诉你:从FIP的哪个基地址加载、镜像在FIP内的偏移、大小、以及验证结果。如果某个镜像加载失败,日志里会直接报ERROR,比如:

ERROR:   Failed to load image 'bl32' from FIP
ERROR:   Image 'bl32' not found in FIP table

遇到这种错误,我一般先检查FIP镜像是否完整。用fiptool可以查看FIP内容:

fiptool info fip.bin

输出会列出所有子镜像的UUID和大小。如果某个镜像缺失,那就是打包时漏了。

小技巧:FIP的魔数是0xD0B5B0A2(小端序)。如果你在二进制里看到这个值,基本就能确认是FIP头部。我经常用hexdump直接看Flash内容来验证。

4.3 SCP_BL2镜像加载:系统控制处理器的固件

SCP_BL2是给SCP(System Control Processor)用的固件。SCP负责电源管理、时钟控制等底层硬件操作。BL2需要先把它加载到SCP的专用内存里,然后启动SCP。

日志里SCP_BL2的加载过程通常是这样:

INFO:    Loading SCP_BL2 image
INFO:    SCP_BL2: base address 0x04000000, size 0x10000
INFO:    SCP_BL2: loaded to SCP SRAM at 0x20000000
INFO:    SCP_BL2: authentication passed
INFO:    SCP_BL2: releasing SCP out of reset

这里要注意几个关键信息:

  • base address:FIP里SCP_BL2的起始偏移。
  • loaded to:SCP SRAM的物理地址。不同平台不一样,我见过0x20000000、0x2E000000等。
  • releasing SCP out of reset:BL2把SCP从复位状态释放,SCP开始执行自己的固件。

注意:SCP_BL2的加载地址是平台相关的。如果地址配置错了,SCP可能跑不起来。我曾经遇到过SCP_BL2加载后SCP没反应,查了半天发现是SCP SRAM的基地址在设备树里写错了。

4.4 BL31镜像加载:EL3运行时固件

BL31是ATF的核心组件,运行在EL3异常级别。它负责安全监控、中断路由、PSCI等功能。BL2加载BL31时,会把它放到DRAM的特定区域。

日志输出示例:

INFO:    Loading BL31 image
INFO:    BL31: base address 0x04010000, size 0x20000
INFO:    BL31: loaded to DRAM at 0x80000000
INFO:    BL31: authentication passed
INFO:    BL31: entry point 0x80001000

关键点:

  • loaded to DRAM:BL31被加载到DRAM地址0x80000000。这个地址通常在BL2初始化DDR后可用。
  • entry point:BL31的入口地址。BL2最后会跳转到这个地址。

我个人的习惯是,看到entry point后,会记下这个地址。如果后续BL31启动失败,可以用JTAG直接跳到这个地址看代码是否跑飞。

4.5 BL32镜像加载:安全世界的操作系统

BL32是TEE(Trusted Execution Environment)的镜像,比如OP-TEE或Trusty。它运行在S-EL1,提供安全服务。BL2加载BL32是可选的——如果平台不需要TEE,这一步会跳过。

日志输出:

INFO:    Loading BL32 image
INFO:    BL32: base address 0x04030000, size 0x40000
INFO:    BL32: loaded to DRAM at 0x90000000
INFO:    BL32: authentication passed
INFO:    BL32: entry point 0x90001000

如果平台没有BL32,日志里会直接跳过:

INFO:    BL32: not present, skipping

常见问题:BL32加载失败时,日志可能显示Authentication failed或Image corrupt。我遇到过一种情况:BL32镜像大小超过了FIP里声明的size,导致加载时内存越界。后来在打包脚本里加了大小检查才解决。

4.6 三个镜像的对比

为了方便你快速对比,我整理了一张表:

镜像 运行位置 异常级别 主要功能 加载目标
SCP_BL2 SCP内部SRAM SCP自有 电源管理、时钟控制 SCP SRAM
BL31 主CPU EL3 安全监控、PSCI、中断路由 DRAM
BL32 主CPU S-EL1 TEE安全服务 DRAM

你看,SCP_BL2和BL31/BL32的加载目标完全不同。SCP_BL2必须放在SCP能直接访问的SRAM里,而BL31/BL32则放在主CPU的DRAM里。这个区别在日志里一眼就能看出来。

4.7 实战:从日志定位BL2阶段的问题

最后,我分享几个实战中常见的日志异常模式:

  • FIP解析失败:日志显示Invalid FIP header。原因通常是FIP镜像损坏或Flash读取错误。我建议先检查Flash的读写时序。
  • 镜像验证失败:日志显示Authentication failed。可能是证书过期、公钥不匹配、或者签名算法不一致。我曾经因为证书链里多了一个中间证书导致验证失败,折腾了两天。
  • 镜像加载地址冲突:日志显示Overlapping memory regions。这说明两个镜像的加载地址有重叠。检查平台内存布局文件platform_def.h里的地址定义。
  • SCP_BL2启动超时:日志显示SCP did not respond。SCP固件可能卡住了,或者SCP SRAM的时钟没配好。

嗯,BL2阶段的日志解读,说白了就是盯着那几行关键输出:加载地址、大小、验证结果。只要这些信息对得上,信任链就能顺利建立。如果对不上,那就按我上面说的方向去排查,基本不会跑偏。