3. RISC-V启动流程概览
RISC-V 平台的启动并不是“一条指令跳到内核”这么简单。从上电复位到 Linux 内核接管,中间要经历多个职责明确的阶段:硬件固化代码建立最基础的执行环境,BootROM 加载并校验下一级引导程序,SPL/OpenSBI 完成特权级切换与平台初始化,U-Boot 准备内核镜像与设备树,最后内核解压、建立页表并挂载根文件系统。理解这条链路,是后续调试 OpenSBI、裁剪固件和排查“卡在启动早期”问题的前提。
一、核心原理:多级引导与特权级递进
RISC-V 启动链的本质是“多级引导 + 特权级递进”。复位后 CPU 处于 M 模式(Machine Mode),PC 指向复位向量,通常位于芯片内部的 BootROM。BootROM 代码量小、不可修改,负责最基础的时钟、DDR 初始化或从固定介质读取下一级镜像。随后控制权交给 SPL 或直接交给 OpenSBI 固件,OpenSBI 以 M 模式运行,提供 SBI 接口并完成 M 模式下的平台初始化,然后通过 mret 切换到 S 模式(Supervisor Mode)执行 U-Boot。U-Boot 在 S 模式下加载内核镜像、设备树和 initrd,最终跳转到内核入口,内核在 S 模式下完成自身初始化并启动用户空间。
这条链路上每一级都依赖上一级准备好的资源:DDR 可用、串口可输出、存储介质可读、设备树可解析。任何一级缺失或参数错误,都会表现为“无输出”“卡在 OpenSBI”“内核 panic”等不同现象,因此定位问题时必须按阶段缩小范围。
二、方法流程:各阶段职责与关键动作
把启动链拆成五个阶段后,每一阶段的输入、输出和失败特征就清晰了。下面用清单方式列出典型职责,便于对照日志定位问题。
- 阶段① 上电复位:CPU 从复位向量取指,BootROM 设置栈、时钟和基本串口,从固定介质读取 SPL 或 OpenSBI 头部,校验签名后跳转。
- 阶段② SPL/一级引导:初始化 DDR 控制器和关键外设,把 OpenSBI 固件从 Flash 搬运到 DDR 的链接地址,然后跳转到固件入口。
- 阶段③ OpenSBI:在 M 模式完成平台初始化、中断控制器配置、域隔离,注册 SBI 扩展,最后通过
mret进入 S 模式并跳转到 U-Boot。 - 阶段④ U-Boot:在 S 模式初始化网络、存储和串口,加载内核 Image、DTB 和 initrd,设置
bootargs,跳转到内核入口。 - 阶段⑤ Linux 内核:解压镜像、建立页表、初始化内存管理和驱动模型,解析 DTB,挂载 rootfs,启动 init 进程。
三、案例/场景:一次典型启动日志对照
以 QEMU virt 机器或真实开发板为例,串口日志会按阶段输出。下面是一段简化后的启动日志,可对照上面的阶段划分:
[BootROM] reset vector, loading SPL...
[SPL] DDR init done, loading OpenSBI @0x80000000
[OpenSBI] version 1.4, platform generic
[OpenSBI] domain0 next_addr=0x80200000, next_mode=S
[U-Boot] SPL: loading U-Boot from SPI...
[U-Boot] DRAM: 2 GiB, loading kernel Image...
[Linux] Booting Linux on hart 0, dtb @0x81000000
[Linux] Mounting rootfs... done
如果日志停在 [OpenSBI] 之后没有 U-Boot 输出,通常说明 next_addr 配置错误或 U-Boot 镜像未正确加载;如果 U-Boot 能启动但内核无输出,则要检查 bootargs 中的 console= 和 DTB 的 chosen 节点。
四、误区与复盘:常见启动失败原因
误区一:认为 OpenSBI 只是“跳板”。OpenSBI 承担 M 模式下的中断、定时器、IPI 和域隔离,若其初始化不完整,S 模式内核会出现随机挂起或定时器失效。
误区二:忽略镜像加载地址与链接地址一致。OpenSBI 和 U-Boot 都要求“加载地址 = 链接地址”,否则重定位代码会跑飞,表现为无输出或反复复位。
误区三:设备树与内核版本不匹配。DTB 中的 memory、chosen、cpus 节点必须与内核配置一致,否则内核可能在早期内存扫描阶段 panic。
| 阶段 | 运行模式 | 典型镜像 | 关键输出/检查点 |
|---|---|---|---|
| 上电复位 | M | BootROM | 复位向量、串口初始化 |
| 一级引导 | M | SPL | DDR 初始化完成 |
| 固件 | M | OpenSBI | next_addr、SBI 版本 |
| 引导程序 | S | U-Boot | 内核加载地址、bootargs |
| 内核 | S | Image + DTB | 页表、rootfs 挂载 |
调试建议:先确认串口能输出 BootROM 日志,再逐级确认 SPL、OpenSBI、U-Boot 的加载地址与校验值。每级都保留“可回退”的镜像,避免一次烧录失败导致整板无法启动。