3. STM32MP启动流程与安全启动

STM32MP1系列处理器的启动过程是一条严格分级的信任链。理解这条链上每一级固件的位置、职责和验证方式,是配置安全启动和排查启动故障的基础。整个启动链可以概括为:ROM Code → FSBL(TF-A BL2)→ OP-TEE(BL32)与SSBL(U-Boot,BL33)→ Linux内核。每一级在移交控制权之前,都要对下一级镜像进行完整性和真实性验证。

一、启动链的五个阶段

第一阶段:ROM Code。芯片上电或复位后,首先执行固化在芯片内部ROM中的代码。ROM Code不可修改,它负责最基础的硬件初始化(时钟、部分外设),然后根据BOOT引脚配置和OTP(One-Time Programmable)熔丝状态,从指定启动介质(eMMC、SD卡、NOR/NAND Flash、USB、UART)加载FSBL。在安全启动模式下,ROM Code会使用存储在OTP中的公钥哈希(PKH)验证FSBL头部的签名,验证通过才继续执行。

第二阶段:FSBL(First Stage Boot Loader)。在STM32MP1的典型方案中,FSBL由TF-A(Trusted Firmware-A)的BL2阶段承担。BL2运行在SYSRAM中,负责初始化DDR控制器、配置时钟树、加载后续镜像到DDR。BL2需要从启动介质中读取FIP(Firmware Image Package)容器,解析其中的BL32(OP-TEE)和BL33(U-Boot)镜像,并分别验证其签名。

第三阶段:OP-TEE(BL32)。OP-TEE是一个可信执行环境,运行在ARM Cortex-A7的Secure World中。它提供安全服务接口,如安全存储、加解密引擎调用、随机数生成等。在启动链中,BL2将OP-TEE加载到安全内存区域并验证签名后,跳转执行。OP-TEE初始化完成后,会返回BL2或直接由BL2继续加载BL33。

第四阶段:SSBL(U-Boot,BL33)。U-Boot运行在Normal World,负责加载Linux内核、设备树和根文件系统。在安全启动场景下,U-Boot自身已由BL2验证,但U-Boot在加载内核时还可以通过FIT(Flattened Image Tree)镜像格式对内核和设备树进行签名验证,形成从ROM到内核的完整信任链。

第五阶段:Linux内核。内核启动后,可以通过dm-verity等机制对根文件系统进行完整性校验,进一步延伸信任链。

STM32MP1 安全启动信任链 每一级验证下一级签名,形成不可中断的信任传递 ROM Code 芯片固化 · 不可修改 OTP PKH 验证 FSBL 签名验证 FSBL (TF-A BL2) DDR初始化 · FIP解析 加载并验证 BL32/BL33 签名验证 OP-TEE (BL32) Secure World 安全存储 · 加解密服务 返回/移交 SSBL (U-Boot) Normal World · BL33 加载内核 · FIT验证 FIT签名验证 Linux Kernel dm-verity 根文件系统校验 信任链延伸至用户空间 信任链传递关系 ROM Code 用 OTP 中的 PKH 验证 FSBL 头部签名 FSBL 解析 FIP,用公钥验证 BL32 和 BL33 签名 OP-TEE 初始化 Secure World,提供安全服务 U-Boot 用 FIT 镜像签名验证内核与设备树 启动失败恢复策略 ① ROM Code 验证失败 → 尝试备用启动介质(BOOT引脚切换) ② FSBL 加载失败 → 通过 USB/UART 进入 DFU 模式,重新烧录 FIP ③ U-Boot 验证失败 → 回退到备用 FIT 镜像或进入恢复控制台 ④ 内核校验失败 → 挂载只读恢复分区,触发 OTA 回滚

二、签名验证机制

STM32MP1的安全启动依赖非对称加密体系。整个验证过程围绕密钥对展开:私钥用于签名,公钥用于验证。公钥的哈希值(PKH)被烧录到OTP中,作为信任根。

具体流程如下:

  • 密钥生成与烧录:开发者生成ECDSA或RSA密钥对,将公钥哈希写入OTP。此操作不可逆,一旦烧录,后续所有FSBL镜像必须使用对应私钥签名。
  • 镜像签名:使用STM32 Signing Tool对FSBL、FIP包进行签名,生成包含签名值的头部。签名覆盖镜像的哈希值,确保任何字节改动都会导致验证失败。
  • 逐级验证:ROM Code验证FSBL头部签名;FSBL验证FIP中BL32和BL33的签名;U-Boot通过FIT格式验证内核和设备树。每一级验证失败都会中止启动。

注意:OTP烧录不可逆。在量产前务必在开发板上充分验证密钥和签名流程,确认无误后再进行量产烧录。建议保留一份未烧录OTP的样片用于调试。

三、启动失败恢复策略

安全启动开启后,任何一级验证失败都会导致启动中止。如果没有恢复机制,设备可能变砖。STM32MP1提供了多层次的恢复手段:

失败阶段 现象 恢复方式
ROM Code验证FSBL失败 无串口输出,或输出ROM错误码 切换BOOT引脚到备用介质(如SD卡),或进入USB DFU模式重新烧录
FSBL加载/验证BL32/BL33失败 串口输出TF-A错误日志后停止 通过UART/USB DFU重新烧录FIP包;或使用未签名镜像临时启动
U-Boot验证内核失败 U-Boot输出FIT验证错误 回退到备用FIT镜像;或进入U-Boot控制台手动加载恢复镜像
内核dm-verity校验失败 内核panic,提示hash mismatch 挂载只读恢复分区,触发OTA回滚到上一版本

在实际产品设计中,建议采用A/B双分区方案:主分区启动失败时,自动切换到备份分区。同时保留一个可通过物理按键或串口触发的恢复模式,用于强制进入DFU或U-Boot控制台。这样即使签名验证失败,也能通过重新烧录恢复设备。

调试建议:在开发阶段,可以先关闭安全启动(不烧录OTP),验证启动链各阶段是否正常。确认无误后,再逐步开启签名验证。每次修改FSBL或FIP后,务必重新签名并验证,避免因签名不匹配导致启动失败。

四、关键配置与参数

在TF-A和U-Boot的配置中,与安全启动相关的关键参数包括:

# TF-A 编译配置示例
make PLAT=stm32mp1 \
     ARCH=aarch32 \
     ARM_ARCH_MAJOR=7 \
     AARCH32_SP=optee \
     DTB_FILE_NAME=stm32mp157d-dk1.dtb \
     BL33_CFG=u-boot.dtb \
     TRUSTED_BOARD_BOOT=1 \
     GENERATE_COT=1 \
     MBEDTLS_DIR=../mbedtls

# U-Boot 环境变量示例
setenv bootargs 'root=/dev/mmcblk0p5 rootwait rw'
setenv kernel_addr_r 0xC2000000
setenv fdt_addr_r 0xC4000000
setenv bootcmd 'fatload mmc 0:4 ${kernel_addr_r} fit.itb; bootm ${kernel_addr_r}'

其中TRUSTED_BOARD_BOOT=1启用可信启动,GENERATE_COT=1生成信任链证书。U-Boot的bootm命令在加载FIT镜像时会自动验证签名,验证失败则拒绝启动。

总结来说,STM32MP1的安全启动是一条从ROM Code到Linux内核的完整信任链。每一级固件在移交控制权前都要验证下一级的签名,任何环节失败都会中止启动。通过合理的恢复策略(备用介质、DFU模式、A/B分区、恢复控制台),可以在保证安全性的同时避免设备变砖。理解这条链的每个环节,是进行安全升级和量产部署的前提。