4. 启动流程与引导加载
航电计算平台的启动过程不是“一按电源就跑应用”,而是一条由硬件复位逻辑、固化在芯片内部的 BootROM、外部引导加载程序以及操作系统内核共同组成的多阶段信任链。理解这条链路的每一级做了什么、镜像放在哪里、如何校验、参数如何传递,是 BSP 移植与启动排障的基础。本节以典型的 ARM64 航电计算平台为例,梳理从上电复位到内核接管控制权的完整路径。
上电复位序列:从电源稳定到第一条指令
上电瞬间,电源管理芯片(PMIC)按预设时序依次拉高各路供电轨,通常先建立核心电压(如 0.9V),再建立 I/O 电压(如 1.8V/3.3V),最后释放复位信号。复位释放后,CPU 内部的复位控制器将程序计数器(PC)强制指向芯片定义的复位向量地址。对于多数 ARM64 SoC,该地址位于片上 ROM 的固定偏移处,例如 0x0000_0000 或 0xFFFF_0000,具体由芯片手册规定。
此时 CPU 处于最高异常等级 EL3(或 EL2,取决于芯片设计),MMU 关闭、Cache 未使能、内存控制器尚未初始化,因此 BootROM 只能访问片上 SRAM 和极少数已就绪的外设。这一阶段的代码通常由芯片厂商固化,不可修改,其职责是建立最小可运行环境,并从预定义的启动介质中加载下一级引导程序。
BootROM:信任链的起点
BootROM 是芯片内固化的只读代码,也是整个启动信任链的根(Root of Trust)。它按芯片设定的启动顺序探测启动介质,常见顺序为:eMMC/SD → QSPI NOR Flash → UART/USB 下载模式。探测到有效介质后,BootROM 从介质固定偏移处读取引导头(Boot Header),解析镜像大小、加载地址、校验信息,并将引导加载程序的第一级(如 U-Boot SPL)搬移到片上 SRAM 中执行。
BootROM 通常还会执行签名校验:若芯片启用了安全启动,BootROM 会用固化在 OTP 中的公钥哈希验证引导头的数字签名,校验失败则停止启动或进入恢复模式。这一机制保证了后续所有代码的可信来源。在航电场景中,安全启动往往是适航审查关注的重点之一。
多阶段引导:为什么不能一步到位
BootROM 运行在片上 SRAM 中,容量通常只有几十到几百 KB,无法容纳完整的 U-Boot 或内核。因此需要多阶段引导:第一级 SPL(Secondary Program Loader)体积小,负责初始化 DDR 控制器和基本时钟,把完整的 U-Boot 从存储介质搬到 DDR 中;第二级 U-Boot Proper 运行在 DDR 中,具备完整驱动、命令行和文件系统支持,负责加载内核镜像与设备树。
在航电平台中,常见的阶段划分如下:
- BL1(BootROM):固化代码,验证并加载 BL2。
- BL2(SPL / ATF BL2):初始化 DDR、时钟、引脚,加载 BL31(ATF)和 BL33(U-Boot)。
- BL31(ARM Trusted Firmware):建立安全监控环境,处理 PSCI 电源管理调用。
- BL33(U-Boot Proper):加载内核、设备树、根文件系统,传递启动参数。
每一级都需对下一级镜像进行校验,形成逐级信任的链条。若某一级校验失败,启动流程会中止或回退到备份镜像,具体行为由芯片和引导程序配置决定。
镜像加载与校验:从存储到内存
以 eMMC 启动为例,BootROM 从 eMMC 的 Boot Partition 或 User Partition 的固定偏移读取引导头。引导头通常包含以下字段:
| 字段 | 典型值/说明 |
|---|---|
| magic | 0x4D564C31(示例,表示 MV-L1) |
| image_size | 0x0002_0000(128 KB,示例) |
| load_addr | 0x0400_0000(片上 SRAM 基址,示例) |
| entry_point | 0x0400_0200(示例) |
| hash | SHA-256 摘要,用于完整性校验 |
| signature | RSA-2048 签名,用于安全启动校验 |
BootROM 读取引导头后,先计算镜像的 SHA-256 摘要并与头中 hash 字段比对,确认完整性;若启用安全启动,再用 OTP 中的公钥验证 signature。两项均通过后,将镜像搬移到 load_addr 并跳转到 entry_point。U-Boot Proper 加载内核时采用类似机制,但镜像格式通常为 FIT(Flattened Image Tree)或传统 uImage,校验方式包括 CRC32、SHA-256 和签名。
启动参数传递与设备树
U-Boot 完成内核镜像加载后,需要把控制权交给内核,同时传递三类信息:启动参数(bootargs)、设备树二进制(DTB)地址、以及内核入口地址。在 ARM64 上,约定通过寄存器传递:
/* 示例:U-Boot 跳转内核时的寄存器约定 */
x0 = bootargs 字符串地址 /* 如 "console=ttyS0,115200 root=/dev/mmcblk0p2 rw" */
x1 = DTB 在内存中的地址 /* 如 0x4800_0000 */
x2 = 内核入口地址 /* 如 0x4008_0000 */
x3 = 保留(通常为 0)
bootargs 中的参数直接影响内核启动行为。例如 console=ttyS0,115200 指定串口控制台,root=/dev/mmcblk0p2 指定根文件系统分区,rw 表示以读写方式挂载。在航电平台中,还可能传入 isolcpus、nohz_full 等实时性相关参数。
设备树(Device Tree)以二进制形式描述硬件拓扑,包括 CPU 数量、内存基址与大小、中断控制器、串口、SPI、I2C 等外设的寄存器地址和中断号。U-Boot 可以将内嵌的 DTB 传递给内核,也可以从存储介质加载独立的 DTB 文件。内核启动后解析 DTB,据此初始化各驱动。若 DTB 与实际硬件不匹配,会出现外设无法识别、中断号错误等问题,因此 BSP 移植时必须确保 DTB 与板级硬件一致。
整体来看,航电计算平台的启动流程是一条从硬件复位到内核接管的逐级信任链。BootROM 是信任根,SPL 负责建立 DDR 环境,U-Boot 负责加载内核与设备树,最终通过寄存器传递启动参数。理解每一级的职责、镜像格式、校验方式和参数传递约定,才能在 BSP 移植和启动排障中快速定位问题。