3. BL1阶段日志解读:ROM代码执行、平台初始化、认证模块加载
BL1阶段,说白了就是芯片上电后跑的第一段代码。这段代码通常固化在ROM里,你改不了它。我刚开始接触ATF时,总觉得BL1没啥好看的——反正都是厂家写死的,出问题也动不了。后来被一个启动失败的问题折腾了两周,才发现BL1日志里藏着关键线索。
嗯,这一章我们就来聊聊BL1阶段的日志到底怎么看。ROM代码执行、平台初始化、认证模块加载,这三个环节一个都不能少。
3.1 ROM代码执行:第一行代码的足迹
芯片复位后,PC指针直接跳到一个固定地址——通常是ROM的起始位置。这时候MMU还没开,DDR还没初始化,代码只能在SRAM或者内部RAM里跑。
BL1启动的核心特征:
- 运行在EL3异常级别,最高权限
- 使用物理地址,没有虚拟内存映射
- 堆栈空间极其有限,通常只有几KB
- 依赖硬件看门狗,防止卡死
日志里怎么判断ROM代码开始执行了?看下面这个典型输出:
NOTICE: BL1: v2.8(release):v2.8-rc0-123-gabcdef
NOTICE: BL1: Built : 14:30:00, Mar 15 2024
INFO: BL1: RAM 0x00000000 - 0x0003FFFF
INFO: BL1:复位原因: 上电复位
我个人习惯先看版本号和构建时间。如果版本号跟你烧录的固件对不上,那说明ROM代码可能被篡改过,或者芯片进入了恢复模式。我在项目中遇到过一回,板子怎么都起不来,日志里BL1版本号显示的是v2.4,但我明明烧的是v2.8。后来发现是芯片的eFuse配置把BL1加载路径指向了备份区。
小技巧:复位原因字段很重要。上电复位、看门狗复位、软件复位,不同原因对应的排查方向完全不同。如果是看门狗复位,那大概率是BL1执行超时了。
3.2 平台初始化:时钟、电源、存储控制器
ROM代码跑完最基本的设置后,会跳转到BL1的入口。这时候才开始真正的平台初始化。说白了,就是让芯片知道自己长什么样——几个核、多少缓存、外设怎么映射。
日志里常见的初始化步骤:
INFO: BL1: 平台初始化开始
INFO: BL1: 配置系统计数器
INFO: BL1: 配置GICv3
INFO: BL1: 配置MMU(EL3页表)
INFO: BL1: 配置UART控制台
INFO: BL1: 平台初始化完成
你想想看,如果日志卡在"配置系统计数器"这一步,那大概率是晶振没起振,或者时钟源选择有问题。我调试过一块板子,日志停在"配置GICv3"就不动了。查了半天,发现是GIC的基地址在datasheet里写错了——我用的芯片是修订版B,但代码里配的还是修订版A的地址。
| 初始化步骤 | 常见失败原因 | 日志特征 |
|---|---|---|
| 系统计数器 | 晶振故障、时钟源配置错误 | 卡死无输出 |
| GIC初始化 | 基地址错误、中断号冲突 | 打印后立即重启 |
| MMU页表 | 内存属性配置错误、地址重叠 | 打印后进入异常 |
| UART控制台 | 波特率不匹配、引脚复用错误 | 输出乱码或无输出 |
| 存储控制器 | 时序参数错误、DDR训练失败 | 反复重试打印 |
注意:UART控制台初始化如果失败,你后面什么都看不到。我建议在硬件设计阶段就把UART引脚固定下来,不要用复用功能。否则调试时连日志都抓不到,那才叫抓瞎。
3.3 认证模块加载:信任链的第一环
BL1的另一个核心任务,就是加载并验证BL2的镜像。这是整个信任链的起点。如果BL1不认BL2的签名,系统直接死给你看。
认证流程大致是这样的:
INFO: BL1: 加载BL2镜像
INFO: BL1: BL2: 加载地址 0x04001000
INFO: BL1: BL2: 镜像大小 0x0001E000
INFO: BL1: 验证BL2证书
INFO: BL1: 使用ROTPK验证
INFO: BL1: 证书验证成功
INFO: BL1: 跳转到BL2
这里有个关键点——ROTPK(一次性可编程密钥)。这个密钥在芯片出厂时烧进去,或者通过eFuse写入。一旦写入,就不能改了。我遇到过一台设备,升级固件后启动失败,日志显示"证书验证失败"。查了半天,发现是客户自己生成了新的密钥对,但没把公钥烧进eFuse。说白了,就是钥匙和锁不匹配。
认证失败的常见原因:
- 证书签名算法不匹配(比如BL1用RSA2048,证书却是RSA4096)
- ROTPK哈希值不一致
- 证书链不完整(缺少中间CA证书)
- 镜像被篡改或损坏
我曾经被一个"间歇性认证失败"的问题折磨了三天。日志有时候能过,有时候过不了。最后发现是eFuse的读取时序有问题——温度一高,读取出来的ROTPK就多了一个bit错误。嗯,硬件问题,软件背锅。
3.4 BL1阶段的核心流程图
下面这张图把BL1阶段的执行流程串起来了。你可以对照着日志,一步步看系统走到哪了。
3.5 实战:从日志定位BL1阶段问题
说了这么多,咱们来点实际的。假设你拿到一份启动日志,只有下面这几行:
NOTICE: BL1: v2.8(release)
INFO: BL1: 平台初始化开始
INFO: BL1: 配置系统计数器
(然后就没有然后了)
怎么分析?
- 看最后一条有效日志——"配置系统计数器"。这说明代码卡在了这一步,或者这一步之后崩溃了。
- 检查硬件——系统计数器依赖外部晶振或者芯片内部的RC振荡器。用示波器量一下晶振引脚,看有没有波形。
- 检查代码——如果硬件没问题,那可能是计数器基地址配置错了。我遇到过一款SoC,它的系统计数器地址在参考手册里写的是0x2A430000,但实际芯片里是0x2A830000。嗯,手册勘误页里有写,但谁没事去看勘误页呢?
我的排查习惯:遇到BL1卡死,先看复位原因,再看卡在哪个初始化步骤。如果复位原因是"看门狗复位",那说明BL1曾经跑完过,但后续代码执行超时了。这时候重点查DDR初始化或者认证模块——这两个环节最容易超时。
BL1阶段的日志虽然短,但信息密度很高。版本号、复位原因、初始化步骤、认证结果,每一行都可能指向问题的根因。说白了,你不需要看懂每一行汇编代码,但你要知道日志里哪些字段是关键的,哪些异常是致命的。