1. 课程导入

在RISC-V平台上,从按下复位按钮到操作系统内核获得控制权,中间要经历一段高度规范、层层交接的启动过程。OpenSBI(Open Source Supervisor Binary Interface)正是这段旅程中承上启下的关键固件:它运行在M模式(Machine Mode),向上为S模式(Supervisor Mode)的操作系统提供标准化的SBI接口,向下负责平台初始化、中断委托、内存保护与多核启动管理。理解OpenSBI,本质上就是理解RISC-V特权级架构如何被真正“用起来”。

学习目标

  • 掌握RISC-V三级特权模式(M/S/U)与CSR寄存器在启动过程中的作用。
  • 理解从复位向量到OpenSBI、再到U-Boot与Linux内核的完整启动链交接顺序。
  • 能够独立编译、裁剪并移植OpenSBI到指定RISC-V开发板或QEMU平台。
  • 读懂SBI规范中的扩展调用(如TIME、IPI、HSM、RFENCE),并能编写简单的SBI调用测试。
  • 具备定位启动失败、串口无输出、内核卡死等常见问题的调试能力。

核心概念与整体知识框架

RISC-V启动链的核心在于“特权级切换”与“控制权交接”。复位后CPU处于M模式,最先运行的固件(通常是BootROM或SPL)完成最基础的时钟、DDR初始化,随后加载OpenSBI。OpenSBI完成平台初始化后,将下一阶段引导程序(如U-Boot SPL或U-Boot Proper)置于S模式运行,并通过SBI接口为其提供M模式服务。最终,引导程序加载Linux内核,内核在S模式运行,通过ecall指令请求SBI服务。

整个知识框架可以拆成四条主线:特权级与CSR、启动链交接、SBI接口规范、平台移植与调试。这四条主线贯穿全部30章内容,本节先建立全局地图。

RISC-V 启动链与 OpenSBI 全局视图 BootROM M模式 · 复位入口 OpenSBI M模式 · SBI服务 U-Boot S模式 · 引导加载 Linux Kernel S模式 · 内核启动 用户空间 U模式 · 应用 特权级: M(Machine) M(OpenSBI) S(Supervisor) S(Kernel) U(User) SBI 调用 / 返回 四大知识主线 特权级与CSR mstatus / medeleg mideleg / mtvec mcounteren / mhartid 启动链交接 复位向量 → OpenSBI OpenSBI → U-Boot U-Boot → Linux SBI接口规范 TIME / IPI / RFENCE HSM / SRST / DBCN ecall 调用约定 平台移植与调试 平台配置 / 设备树 串口日志 / JTAG QEMU 仿真验证 实战路线图 ① 环境搭建 工具链 / QEMU ② 编译OpenSBI fw_dynamic / fw_jump ③ 启动链联调 U-Boot + Kernel ④ SBI调用测试 ecall 验证 ⑤ 移植 真实板卡

方法流程:一次完整的启动交接

以QEMU virt平台为例,典型启动流程如下:

# 1. 复位后,CPU从0x1000(BootROM)开始执行
# 2. BootROM加载OpenSBI固件到0x80000000
# 3. OpenSBI入口 _start:
#    - 保存mhartid、设备树地址
#    - 初始化栈、清零BSS
#    - 调用 sbi_init() 完成平台初始化
#    - 配置 medeleg/mideleg,将异常委托给S模式
#    - 设置 mstatus.MPP = S,mepc = 下一阶段入口
#    - 执行 mret,切换到S模式
# 4. U-Boot在S模式运行,通过ecall请求SBI服务
# 5. U-Boot加载Linux内核,跳转至内核入口

这条链路中,任何一步出错都会导致“串口无输出”或“内核卡死”。因此,掌握每一阶段的入口地址、寄存器状态和日志特征,是调试的基础。

案例场景:QEMU上的最小启动验证

在课程初期,我们使用QEMU快速验证启动链是否打通。以下命令构建并运行一个包含OpenSBI与U-Boot的最小系统:

# 编译OpenSBI(以generic平台为例)
make PLATFORM=generic CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)

# 生成固件
# build/platform/generic/firmware/fw_jump.bin

# 使用QEMU启动
qemu-system-riscv64 \
  -M virt -m 512M -nographic \
  -bios build/platform/generic/firmware/fw_jump.bin \
  -kernel u-boot.bin

# 预期串口输出:
# OpenSBI v1.3
# Platform Name : riscv-virtio,qemu
# ...
# U-Boot 2024.01

如果串口只输出OpenSBI版本号后停止,通常说明S模式交接失败,应重点检查mstatus.MPP与mepc的设置,以及下一阶段镜像是否被正确加载到预期地址。

常见误区与复盘

误区一:把OpenSBI当成Bootloader。OpenSBI不是引导加载程序,它不负责加载内核镜像,只负责M模式服务与特权级交接。加载内核是U-Boot的职责。

误区二:忽略设备树传递。OpenSBI启动时接收的a1寄存器保存设备树地址,必须原样传递给下一阶段,否则内核无法识别硬件。

误区三:混淆fw_jump与fw_dynamic。fw_jump固件固定跳转到下一阶段地址,fw_dynamic则通过动态信息结构体传递参数,二者适用场景不同。

核心参数速查清单

参数/寄存器 作用 典型值/说明
mhartid 当前硬件线程ID 0 为主核,其余为从核
mstatus.MPP mret后的特权级 设置为S模式(01)
mepc mret跳转地址 下一阶段入口地址
medeleg 异常委托寄存器 将S模式异常委托给S处理
mideleg 中断委托寄存器 将S模式中断委托给S处理
a0 / a1 启动参数 a0=hartid,a1=设备树地址
ecall SBI调用指令 a7=扩展ID,a6=功能ID

学习建议:每学完一个模块,都在QEMU上实际运行一次,观察串口日志与寄存器状态。OpenSBI的启动日志会打印平台名称、固件版本、支持的SBI扩展列表,这些信息是后续调试的重要基线。

本课程后续将沿着“特权级与CSR → OpenSBI编译与配置 → 启动链交接 → SBI接口编程 → 平台移植与调试”的路径逐步展开。掌握本节建立的全局视图,后续每一章都能找到自己在启动链中的位置。