2. 嵌入式启动流程基础
在嵌入式 Linux 系统中,从上电到进入用户空间并不是一步完成的,而是一条由多个阶段接力执行的启动链。理解这条启动链,是进行 U-Boot 网络 OTA 部署的前提:只有明确每个阶段运行在哪里、能做什么、不能做什么,才能判断 OTA 升级应该在哪一级写入、由谁校验、失败后如何回退。典型启动链为:BootROM → SPL → U-Boot → Linux 内核 → 根文件系统。
核心结论:BootROM 负责“把第一段代码搬进片内 RAM”,SPL 负责“把 U-Boot 搬进 DDR”,U-Boot 负责“把内核和根文件系统搬进 DDR 并启动”,内核负责“初始化硬件并挂载根文件系统”,根文件系统负责“提供用户空间与应用程序”。
一、启动链的整体结构与职责划分
下面这张图展示了各阶段的执行位置、加载目标与职责边界。可以看到,越靠前的阶段,运行环境越受限,代码体积越小,但权限越底层;越靠后的阶段,功能越丰富,但依赖的存储与内存资源也越多。
二、各阶段详细职责与运行环境
| 阶段 | 运行位置 | 核心职责 | 典型大小 | OTA 相关性 |
|---|---|---|---|---|
| BootROM | SoC 片内 ROM | 上电复位、时钟初始化、从启动介质读取 SPL 到 SRAM | 固化不可改 | 不可升级,决定启动介质顺序 |
| SPL | 片内 SRAM | 初始化 DDR、时钟、串口,加载 U-Boot 到 DDR | 约 20~64KB | 通常不参与 OTA,但需保证兼容 |
| U-Boot | DDR | 提供命令行、网络、存储驱动,加载内核与设备树 | 约 200~500KB | OTA 核心:环境变量、bootcmd、网络传输 |
| Linux 内核 | DDR | 初始化硬件驱动、挂载根文件系统、启动 init | 约 3~8MB | OTA 升级对象之一,需校验与回退 |
| 根文件系统 | DDR + 存储 | 提供用户空间、库、应用程序与配置 | 约 50~500MB | OTA 升级对象之一,常采用 A/B 分区 |
三、典型启动流程与日志分析
以一块 ARM 开发板为例,上电后串口会依次输出各阶段日志。通过日志可以判断启动卡在哪一级,这对 OTA 失败排障非常关键。
# BootROM 阶段(通常无输出或仅输出芯片信息)
ROM: BootROM V1.2
Boot media: eMMC
# SPL 阶段
U-Boot SPL 2023.07 (Jan 10 2024 - 10:00:00)
Trying to boot from MMC1
DDR init done, loading U-Boot...
# U-Boot 阶段
U-Boot 2023.07 (Jan 10 2024 - 10:00:00 +0800)
CPU: ARM Cortex-A53
DRAM: 512 MiB
MMC: sdhci@fe330000: 0
In: serial
Out: serial
Err: serial
Net: eth0: ethernet@fe300000
Hit any key to stop autoboot: 0
=> boot
# 内核阶段
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.10.160
[ 2.345678] mmc0: SDHCI controller on fe330000
[ 3.456789] EXT4-fs (mmcblk0p3): mounted filesystem
# 根文件系统阶段
[ 5.678901] systemd[1]: Started Journal Service.
Welcome to Buildroot
buildroot login:
排障技巧:如果串口只输出到 “Trying to boot from MMC1” 就停止,说明 SPL 无法读取 U-Boot,通常是分区表或存储介质问题;如果输出到 “Starting kernel ...” 后无反应,说明内核加载地址或设备树不匹配;如果内核启动后卡在挂载根文件系统,说明 bootargs 中 root= 参数或分区内容有误。
四、OTA 部署中的关键关注点与常见误区
在网络 OTA 部署实践中,启动链的每一级都可能成为升级的瓶颈或故障点。以下是最容易出错的几个环节:
- 误区一:直接升级 SPL。SPL 运行在 SRAM 中,且由 BootROM 直接加载,一旦写坏,设备将无法启动,通常只能通过 JTAG 或 USB 烧录恢复。OTA 方案应尽量避开 SPL 和 BootROM 区域。
- 误区二:忽略 U-Boot 环境变量的持久化。OTA 升级后需要更新 bootcmd、bootargs 或分区偏移,如果环境变量未正确保存到存储介质,重启后会回退到旧配置。
- 误区三:内核与根文件系统版本不匹配。内核中的驱动与根文件系统中的模块、库版本必须一致,否则会出现驱动加载失败或应用无法运行。
- 误区四:没有 A/B 分区与回退机制。单分区升级一旦失败,设备变砖。推荐采用 A/B 双分区,由 U-Boot 根据启动标志选择可启动分区。
在 OTA 方案设计时,必须明确:哪些分区允许网络升级、升级后由谁校验、校验失败后如何回退。通常建议只升级内核分区与根文件系统分区,U-Boot 本身如需升级,应保留双备份并配合硬件看门狗。
五、小结:启动链与 OTA 的对应关系
BootROM 和 SPL 是启动的“地基”,通常不参与网络 OTA;U-Boot 是 OTA 的“调度中心”,负责网络传输、分区写入和启动选择;内核与根文件系统是 OTA 的“主要升级对象”,需要配合校验、双分区和回退策略。只有把这条启动链的每一级职责和边界弄清楚,后续设计 U-Boot 网络 OTA 方案时,才能准确决定升级目标、写入位置和失败恢复路径。