嵌入式 Linux 的启动链

July 30, 2026 · 访客

上次我写了关于 DFU 作为通过 USB 刷写固件的一种方式的文章。那篇文章跳过了一个值得单独回答的问题:从按下电源按钮到出现 shell 提示符之间,到底发生了什么?DFU 只是这条路径上的一个分支,所以有必要把整条路径完整走一遍。

各个阶段

用 Mermaid 流程图画出来,这条链条(以及 DFU 在其中的位置)是这样的:

flowchart TD
    A[Power-on / Reset] --> B[Boot ROM<br/>immutable, on-chip]
    B --> C{Valid image on<br/>boot media?}
    C -->|No / forced| D[ROM recovery mode<br/>UART / USB]
    C -->|Yes| E[SPL<br/>first-stage bootloader]
    E --> F[U-Boot<br/>second-stage bootloader]
    F --> G{Enter DFU?}
    G -->|Yes| H[DFU mode<br/>waiting for firmware over USB]
    G -->|No| I[Load kernel + device tree]
    I --> J[Linux kernel]
    J --> K[Mount root filesystem]
    K --> L[init / systemd]

渲染出来是这样的:

嵌入式 Linux 启动链流程图:开机会复位进入 boot ROM,boot ROM 检查启动介质上是否有有效镜像。如果没有找到(或强制进入恢复模式),就会进入 UART/USB 恢复模式。否则会加载 SPL,再由 SPL 加载正式的 U-Boot。U-Boot 既可以进入 DFU 模式等待通过 USB 传输固件,也可以加载内核和设备树、启动 Linux、挂载根文件系统,并交给 init/systemd。

Boot ROM

在生产制造时就烧录进芯片——之后它的任何内容都无法更改。它唯一的任务是根据启动模式引脚或 eFuse,在少数几种启动介质(eMMC、SD、QSPI flash,有时是 USB)中找到某个可启动的东西,然后跳转过去。如果找不到任何有效的内容,大多数 SoC 在这一阶段会退回到一个最小化的 UART 或 USB 恢复模式——这是你能与芯片进行任何通信的最早的地方。

SPL

Secondary Program Loader 的缩写(这是 U-Boot 的叫法;其他厂商称之为 FSBL 或类似的名字)。它运行在片上一小块 SRAM 中,甚至在 DRAM 初始化之前就已经运行,因此必须非常小巧。它的主要任务正是如此:把 DRAM 初始化起来,然后把下一阶段——完整的 U-Boot——加载进去。

U-Boot 正式阶段

这是大多数人说"引导加载程序"时真正指的那个东西。它拥有驱动程序、一个 shell、环境变量、网络支持以及命令解释器。DFU 实际上也正是驻留在这里——运行 dfu 0 mmc 0(或类似命令)会让 U-Boot 进入 DFU 模式,而不是继续正常的启动流程,这正是 dfu-util 在主机端所对接的那个模式。否则,它会把内核镜像和设备树 blob 加载到内存中,然后跳转到内核。

内核与用户空间

内核会自解压,启动控制台,使用它收到的设备树探测硬件,并挂载根文件系统——通常是引导加载程序启动所用的同一张 eMMC 或 SD 卡,开发阶段有时也会是 NFS。根文件系统挂载完成后,内核会把控制权交给 PID 1——在 Yocto 构建的镜像上通常是 systemd——"用户空间"也正是从这里真正开始的。

这对 DFU 意味着什么

只有看清 DFU 在整个链条中所处的位置,它才真正说得通:它是 U-Boot 可以选择的一条替代加载内核的岔路,而不是额外附加在上面的独立部件。这也是为什么 DFU 无法挽救所有的故障模式——如果 boot ROM 本身找不到有效的 SPL,你就根本到不了 U-Boot 这一步,只能依赖 boot ROM 所支持的任何恢复模式(这在不同厂商之间差异很大,值得另写一篇文章专门讨论)。

延伸阅读

相关阅读

评论