1. 课程导入

在嵌入式 Linux 系统开发中,处理器上电到操作系统接管控制权之间,存在一条高度依赖体系结构细节的启动链路。对于 RISC-V 平台而言,这条链路通常由固化在芯片内部的 BootROM、一级引导程序 SPL、通用引导加载程序 U-Boot,以及最终的内核与根文件系统共同组成。本课程围绕“RISC-V U-Boot 与 Linux 启动”展开,目标不是孤立地讲解某个命令,而是帮助学习者建立从复位向量到用户空间进程的完整系统视角。

RISC-V 是一种开放指令集架构,采用模块化设计。其基础整数指令集称为 RV32I 或 RV64I,在此基础上可扩展 M、A、F、D、C 等标准扩展。与许多传统架构不同,RISC-V 将特权级划分为 Machine、Supervisor、User 三个层次,分别对应 M 模式、S 模式和 U 模式。启动过程本质上就是控制权在不同特权级之间逐级交接的过程:BootROM 运行在 M 模式,U-Boot 的 SPL 阶段通常也运行在 M 模式,而完整 U-Boot 和 Linux 内核一般运行在 S 模式,用户程序运行在 U 模式。

理解 RISC-V 启动的关键,不是记住某一块开发板的地址,而是掌握“复位向量 → 特权级切换 → 设备初始化 → 镜像加载 → 内核解压 → 设备树传递 → init 进程”这条主链,以及每一环依赖的寄存器、地址和镜像格式。

一、整体知识框架:从复位到用户空间

下图给出本课程贯穿始终的启动链路关系。它把 RISC-V 特权级、典型镜像和关键交接动作放在同一张图中,便于后续章节逐段展开。

RISC-V 启动链路与特权级交接 M 模式(Machine) S 模式(Supervisor) U 模式(User) BootROM SPL / FSBL DDR 初始化 加载 U-Boot U-Boot proper 加载内核镜像 传递 DTB 跳转内核 Linux 内核启动 挂载根文件系统 init / 用户进程 关键交接点 ① BootROM 读取启动介质,加载 SPL 到 SRAM;② SPL 初始化 DDR,加载 U-Boot proper; ③ U-Boot 加载内核与 DTB,准备启动参数;④ 内核接管后建立页表、初始化驱动; ⑤ 挂载根文件系统并启动 init,最终进入用户空间。

二、核心原理:三个特权级与两次关键跳转

RISC-V 启动过程中最容易被忽视的是特权级切换。复位后,CPU 从 M 模式开始执行,此时可以访问所有 CSR 和物理内存。BootROM 和 SPL 通常运行在 M 模式,负责最底层的时钟、电源、DDR 和存储控制器初始化。当 SPL 准备跳转到 U-Boot proper 时,需要通过 mret 指令从 M 模式切换到 S 模式,并设置 mstatus.MPP、mepc 等寄存器。类似地,U-Boot 跳转 Linux 内核时,内核入口通常也运行在 S 模式,并通过 a0、a1 寄存器传递 hartid 和设备树地址。

因此,学习本课程需要同时关注两条线:一条是“镜像加载线”,即 BootROM → SPL → U-Boot → Kernel → Rootfs;另一条是“特权级交接线”,即 M → S → U。只有两条线对齐,系统才能正常启动。

三、方法流程:建议的学习路径

  1. 建立架构认知:理解 RV64GC 指令集、M/S/U 特权级、CSR 寄存器、中断与异常入口。
  2. 掌握启动介质:了解 SPI Flash、SD/eMMC、UART 下载等启动方式,以及 BootROM 如何选择启动源。
  3. 拆解 U-Boot:区分 SPL 与 U-Boot proper 的职责,掌握 board_init_f、board_init_r、驱动模型和环境变量。
  4. 理解内核交接:掌握 Image、Image.gz、FIT 镜像格式,以及 DTB 的传递方式。
  5. 动手调试:通过串口日志、bdinfo、printenv、bootm、booti 等命令定位启动失败点。

四、典型场景与常见误区

以一块常见的 RISC-V 开发板为例,上电后串口首先输出 BootROM 信息,随后 SPL 打印 DDR 容量,接着 U-Boot proper 显示版本和板级信息。若在 SPL 阶段卡住,通常与 DDR 参数或时钟配置有关;若在 U-Boot 阶段卡住,常见原因是环境变量错误、镜像地址冲突或 DTB 不匹配;若内核启动后 panic,则多与根文件系统、console 参数或设备树节点缺失有关。

常见误区一:把 U-Boot 当成一个整体。实际上 SPL 和 U-Boot proper 运行在不同阶段、不同内存区域,甚至不同特权级。误区二:忽略设备树。RISC-V 平台外设差异大,DTB 不匹配会导致内核无法识别串口、MMC 或网络。误区三:只看内核日志,不关注 SPL 和 U-Boot 的早期输出,导致定位方向错误。

五、关键概念速查清单

概念 作用 典型位置
BootROM 芯片固化代码,选择启动介质并加载 SPL 片内 ROM
SPL 初始化 DDR、时钟,加载 U-Boot proper SRAM
U-Boot proper 加载内核、DTB,准备启动参数 DDR
DTB 描述硬件拓扑,传递给内核 DDR / Flash
init 用户空间第一个进程,启动系统服务 根文件系统

六、实操观察:一次典型启动日志

BootROM: 2024.06
SPL: DDR init done, 512MB
U-Boot 2024.01 (RISC-V 64)
Board: riscv-demo
DRAM:  512 MiB
Loading kernel from mmc 0:1 ...
Loading DTB from mmc 0:1 ...
## Booting kernel from Legacy Image ...
Starting kernel ...
[    0.000000] Linux version 6.6.0
[    0.000000] Kernel command line: console=ttyS0,115200 root=/dev/mmcblk0p2
[    1.234567] Run /sbin/init as init process

这段日志对应了本课程后续要逐层拆解的全部环节。学习者应能从中识别出 BootROM、SPL、U-Boot、内核和 init 五个阶段,并知道每个阶段失败时应该查看哪些信息。掌握这条主线后,再学习具体命令、配置和移植方法,就能做到“知其然,也知其所以然”。