
当你按下开机键,芯片经历的第一件事是什么?不是 Linux 内核,甚至不是我们熟悉的 U-Boot。在这一切之前,还有一个更早、更底层的角色悄然登场——零阶段引导程序(Zero Stage Bootloader,ZSBL)。
它像接力赛的第一棒选手,在资源最匮乏的环境下完成关键的准备工作,然后将“接力棒”稳稳交给下一阶段。
01 / 零阶段引导程序是什么?
首先要从芯片上电的整个启动序列说起。当一块 SoC 芯片通电,它的片内 ROM 会率先运行一段固化代码,这是真正意义上“第一个跑起来的软件”。ROM 代码之后,才是零阶段引导程序登场。

整个启动序列可以用一条简洁的链路来描述:
硬件上电 -> SoC ROM 代码 -> 零阶段引导程序 -> 安全固件 -> 第一阶段引导程序
与大家熟悉的“引导程序”(如 U-Boot、EDK II)相比,零阶段引导程序有几个鲜明特点:
- 零阶段引导程序:运行在最高特权态(如 RISC-V 的 M 态);生命周期最早;可用资源极少(只有 SRAM 或 Cache as RAM);与厂商芯片硬件特性深度耦合。
- 通称“引导程序”:一般运行在较低特权态(如 S 态);功能更丰富;可用资源更多(已有 DDR 或 PSRAM);生态相对成熟,如 U-Boot、EDK II 等。
简而言之,零阶段引导程序的使命是:在最苦的条件下,把舞台搭好,让后来者能尽情发挥。
02 / 为什么需要零阶段引导程序?
有人可能会问:芯片内置的 ROM 代码不够用吗?答案是:对于运行操作系统而言,远远不够。
因为许多 SoC 芯片的片内 ROM 根本不会初始化 PSRAM、DDR 等大容量外部内存。这背后有很现实的成本考量:片内 SRAM 造价高、面积大,而外接 DDR/PSRAM 成本更低,但需要软件驱动来初始化。
此外,ROM 代码流片、固化后无法更改,一旦有 bug 就会导致芯片无法使用;况且 DDR 初始化驱动代码规模通常较大,也不适合全部烧录在 ROM 中。
零阶段引导程序的核心目标
- 初始化大容量内存(DDR、PSRAM),为 OS 和固件提供足够的运行空间;
- 完成处理器核的基本配置;
- 将后续阶段的内核、固件、引导程序从存储介质搬运到内存;
- 向后续引导程序阶段传递硬件信息(如 DTB 设备树);
- 可选:简单调试、固件更新、信任根安全校验等扩展功能。
为什么选择 RISC-V?
RISC-V 架构模块化、完全开源,从 RTOS 到 Linux 都能灵活适配,且尚未形成像 Arm 那样高度封闭、生态壁垒极高的格局。在 Arm 阵营,U-Boot 等生态已经相当成熟,“挤进去”的空间已经很小;而 RISC-V 生态正处于快速发展期,零阶段引导程序恰好可以填补这一空白。
为什么选择 Rust?
C 语言编写的引导程序各有各的生态护城河,代码复用困难。而 Rust 生态的 embedded-hal 库提供了统一的硬件抽象,让同一套驱动代码可以贯穿从零阶段引导程序,到 SBI 固件,再到操作系统内核,真正做到一次开发、处处复用。此外,Rust 的内存安全特性也天然契合安全敏感的引导场景。
03 / RISC-V 下的零阶段引导程序生态
放眼整个 RISC-V 软件栈,零阶段引导程序处于一个承上启下的核心节点位置:

整个启动过程可以分为三个阶段:
- 硬件阶段:芯片上电,SoC 片内 ROM 代码运行;
- "ROM" 阶段:零阶段引导程序从闪存加载到 RAM 中运行,具备固件加载、调试和安全校验三大功能;
- "RAM" 阶段:后续阶段软件加载到 RAM 中运行,可以是 M 态 Linux(nommu Linux)、各类 RTOS、M 态 SBI 固件(如 RustSBI),进而由 RustSBI 切换到 S 态启动标准 Linux、UEFI 等。
零阶段引导程序的核心价值在于:它是连接硬件与软件的桥梁,支持从 RTOS 到完整 Linux 的全部场景,不做取舍,全部兼容。
04 / RustSBI 团队的实践成果
RustSBI 团队目前维护和贡献了两个主要的零阶段引导程序产品:
- Bouffaloader:
适用于博流 BL808 芯片(未来支持 BL616 等)。可初始化 BL808 的 64MiB 片内 PSRAM,支持三核异构启动,向 RustSBI 提供 DTB 和 DynamicInfo。
- SyterKit:
适用于全志 D1 等芯片,同时支持 RISC-V 和 Arm 架构。可初始化 DDR 内存,将系统软件加载到 M 态,支持 RustSBI 和各类 RTOS 的启动。
异构多核:物联网芯片的常态挑战
现代物联网 SoC 具备多个核已不在少数。BL808 就是一个典型例子:它内置三颗架构各不相同的 RISC-V 处理器核:

针对异构多核,零阶段引导程序需要根据情况采用不同策略:
- 相同指令集系列(如 BL808 三核 RISC-V):采用“镜像融合”方案,将三个核的引导镜像合并为一个固件包,ROM 代码同时拉起三颗核,各自加载对应的固件,既节省启动时间,又方便烧录;
- 不同指令集系列(如 Arm + RISC-V 混搭):还需额外遵守各架构各自的安全启动规则,从一个主核出发逐步加载其余核。
配置文件与固件分区
零阶段引导程序不是一个“写死”的黑盒,它通过配置文件决定后续引导阶段的程序路径、特权级等配置,如替换 DTB 中的 bootargs 以调整 Linux 启动命令无需重新编译内核。

固件分区则负责初始化大容量内存并执行分区操作,决定每个内存块用于放置哪个引导阶段代码,以供操作系统和固件本身使用。以 BL808 为例,M 态固件占 32,704 KiB,DTB 信息占 64 KiB,其余空间预留给 S 态引导程序和内核。


还能做什么?更多扩展功能
除了内存初始化和固件加载这两个核心职责,零阶段引导程序还可以承担更多实用功能:
- 固件 OTA 更新与错误恢复:采用 A/B 双分区设计,更新失败时自动回滚到旧版本,极大提升物联网设备的稳定性。支持通过 MMIO 操作直接读写 Flash,预装烧录软件。
- 引导期调试:提供 read32 / write32 等内存访问命令,在不接调试器的情况下完成 DDR 和外设的初步调试,显著缩短驱动和内核的开发周期。
- 更多引导介质:目前许多方案仅支持 SD 卡启动,未来可扩展到板载 NOR/NAND 闪存、eMMC/UFS,乃至 NVMe 固态硬盘。对于 PC 和服务器定制化方案,这意味着不再需要在 U-Boot 和 UEFI 之间二选一,一套零阶段方案就能兼顾全部场景。
05 / 常见问题解答
1. 所有平台都需要零阶段引导程序吗?
不一定。如果芯片片内已有足够大的 SRAM(如 K210),或者是 QEMU 等模拟器平台(内存冷开机即初始化完毕),则无需零阶段引导程序。当然,有了它也可以补充额外的引导功能。
2. Rust 写的引导程序能启动 C 语言写的内核吗?
完全可以。引导程序和内核可以用任何编程语言实现,只要遵守二进制接口(ABI)规范即可。Rust 写的零阶段引导程序可以启动 OpenSBI;C 写的零阶段引导程序同样可以启动 RustSBI。
3. 用 Rust 是不是意味着要重新写一套驱动?
恰恰相反!Rust 生态的 HAL 包可以在内核、固件、引导程序之间共享。复用各厂家现有的 Rust HAL 包生态,即可快速适配新平台,避免重复造轮子。
4. 热重启需要再次执行零阶段引导程序吗?
不需要。冷上电和从 SoC ROM 重新启动(冷重启)需要走完整流程;而从后续引导阶段发起的热重启,内存已经初始化完毕,无需再次执行零阶段引导程序。
06 / 结语
RustSBI 开源社区正在 RISC-V 生态中推动零阶段引导程序领域的标准化与开源化,用 Rust 语言构建兼具安全性与复用性的系统软件基础设施。
无论是物联网开发者、RISC-V 生态贡献者,还是对系统底层充满好奇的同学,都欢迎加入这场从“零”开始的探索。
项目地址: