RISC-V: 固件与操作系统引导 | eg OpenSBI | 借助AI注释项目代码

server/2025/3/25 21:55:56/

引入:计算机没有黑魔法

例如我们都可以,通过指令来查看我们计算机的信息

“Everything is a State Machine”

  • 在许多状态之间不断切换程序就运行了起来
  • Makefile 也是程序;它也是状态机
  • 程序不好读的话,我们还可以调试它!
    • 计算机系统公理:你想到的就一定有人做到
    • “总有人会去发明轮子的”
    • 然后 相信编译器一定是对的

risc-v-%E5%9B%BA%E4%BB%B6%E4%B8%8E%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%BC%95%E5%AF%BC">RISC-V: 固件与操作系统引导

灵魂三问

  1. RISC-V 系统是如何复位、执行什么固件、如何加载操作系统的?
  2. OpenSBI 的入口位于什么地方?
  3. _start 开始的 _try_lottery 是做什么的?

一、RISC-V 系统复位与启动流程详解

1. 复位机制与固件执行

RISC-V 系统的复位流程由硬件信号触发,所有核心跳转至复位向量地址(如 FU540 芯片的 0x1004),进入 M-mode 执行固化在 ROM 中的 ZSBL(第零阶段引导程序)

ZSBL 根据 MSEL 引脚配置加载下一阶段固件(如 FSBL),FSBL 负责初始化 DDR 内存、时钟和中断控制器,随后将控制权移交至 OpenSBI

关键步骤

  • ZSBL:从 ROM 中加载 FSBL 到 L2 LIM 缓存(地址 0x0800_0000)。
  • FSBL:配置 DDR 并加载 BBL 或 OpenSBI 到 DDR(地址 0x8000_0000)。
  • OpenSBI:作为 M-mode 运行时服务,通过 SBI 调用为操作系统提供硬件抽象。
2. 操作系统加载

OpenSBI 完成硬件初始化后,将跳转至操作系统的入口地址(如 Linux 内核的 _start,通过设备树(DTB)传递硬件参数。U-Boot 可作为中间加载器,支持从 Flash、网络等介质加载内核镜像。


二、OpenSBI 入口与调试方法

1. 入口地址

OpenSBI 的入口通常位于 0x8000_0000(DDR 起始地址),这是 RISC-V 虚拟化平台(如 QEMU virt)的标准配置。可通过 QEMU 启动参数验证:

qemu-system-riscv64 -machine virt -bios opensbi.bin

启动后 OpenSBI 会输出固件基地址和大小。

2. 调试建议
  • GDB 跟踪:在 QEMU 中启用 GDB 调试,断点设置在 _start 或 OpenSBI 初始化函数。
  • SBI 调用监控:通过修改 OpenSBI 源码添加日志,观察 ecall 指令的参数传递(如 EID 和 FID)。

三、_start_try_lottery 分析

1. 函数作用

_try_lottery 常见于多核启动场景,用于 动态选择主核(Boot HART)。其逻辑通常包括:

  • 检查当前 HART ID 是否为主核。
  • 若非主核,则进入等待循环;主核继续执行后续初始化(如加载设备树、启动调度器)。
2. 优化建议
  • 锁机制使用原子操作或硬件锁避免多核竞争。
  • 性能分析:通过 PMU(性能监控单元)统计各核启动延迟,优化任务分配策略。

四、建议

1. 调试与验证工具
  • QEMU + GDB:模拟 RISC-V 环境,单步跟踪启动流程。
  • RISC-V Trace:使用 SiFive Trace 或 Lauterbach 硬件跟踪器,捕获复位到操作系统的完整指令流。
2. 固件定制
  • OpenSBI 扩展:基于 SBI 规范开发自定义扩展(如安全启动),通过 ecall 提供专属服务。
  • U-Boot 集成:在 S-mode 运行 U-Boot,利用其文件系统和网络协议栈加载复杂内核。
3. 性能优化
  • DDR 初始化加速:预计算 PLL 配置参数,减少 FSBL 阶段的延时。
  • 并行启动:在多核系统中,让从核提前初始化外设,缩短整体启动时间。
4. 安全增强
  • IOPMP 配置:通过内存保护单元限制外设访问权限,防止恶意代码篡改引导链(参考 SpacemiT V100 设计,[1])。
  • 可信执行环境(TEE):集成 OP-TEE,在 OpenSBI 阶段验证内核签名。

五、总结与扩展方向

问题

核心要点

扩展方向

RISC-V 复位与启动

多阶段引导(ZSBL→FSBL→OpenSBI) + SBI 抽象层

安全启动、多核协同

OpenSBI 入口

0x8000_0000(DDR 基址) + SBI 服务网关

自定义 SBI 扩展、性能监控

_try_lottery

主核选择逻辑 + 多核同步机制

锁优化、PMU 分析

推荐实践

  1. 使用 QEMU 模拟不同 MSEL 配置,观察启动路径变化([3])。
  2. 修改 OpenSBI 源码,添加自定义 SBI 调用(如动态频率调节)。
  3. 结合 Lauterbach Trace32 分析 _try_lottery 的执行时序,优化多核启动效率。

OpenSBI

OpenSBI: 一个开源的 RISC-V 引导固件,用于管理 RISC-V 平台的启动过程。

  • 它实现了 SBI(Supervisor Binary Interface)规范,为操作系统提供了硬件抽象层,简化了系统启动和硬件管理。
  • OpenSBI 支持多种 RISC-V 处理器和平台,广泛用于嵌入式系统和开发板。

一、环境准备与依赖安装

1. 安装编译工具链
# 安装基础工具  
sudo apt-get install build-essential git device-tree-compiler  
# 安装 RISC-V 交叉编译器(以 riscv64-unknown-elf 为例)  
sudo apt-get install gcc-riscv64-unknown-elf  

确保交叉编译器路径已添加到环境变量(若未自动添加):

export PATH=$PATH:/usr/local/riscv64-unknown-elf/bin  
2. 获取 OpenSBI 源码
git clone https://github.com/riscv-software-src/opensbi.git  
cd opensbi  
# 切换至稳定版本(例如 v1.2)  
git checkout v1.2  

二、编译流程详解

1. 核心编译命令解析

OpenSBI 的编译通过 Makefile 控制,关键参数如下:

make CROSS_COMPILE=riscv64-unknown-elf- PLATFORM=generic  
  • CROSS_COMPILE:指定交叉编译工具链前缀(如 riscv64-unknown-elf-
  • PLATFORM:目标平台(如 genericqemu/virt,具体平台代码位于 platform/ 目录)
  • FW_JUMP_ADDR:可选参数,指定跳转地址(如 0x80200000 用于 Linux 内核加载)
2. 分步编译操作
# 创建输出目录  
mkdir -p output/opensbi  
# 执行编译(以 QEMU virt 平台为例)  
make CROSS_COMPILE=riscv64-unknown-elf- PLATFORM=qemu/virt  
# 复制生成文件至输出目录  
cp build/platform/qemu/virt/firmware/fw_jump.bin output/opensbi/  

生成文件说明

  • fw_jump.bin:跳转型固件,需手动指定下一阶段地址
  • fw_payload.bin:包含嵌入式内核的固件(如结合 U-Boot)

三、Makefile 关键逻辑解析

1. 平台配置加载

Makefile 会加载 platform/<PLATFORM>/objects.mk,定义平台相关源文件和链接脚本([1])。例如:

# platform/qemu/virt/objects.mk  
platform-objs-y += platform/qemu/virt/sbi_platform.o  
firmware-objs-$(CONFIG_FW_JUMP) += firmware/fw_jump.o  
2. 固件生成流程
  1. 汇编启动代码firmware/fw_base.S 定义入口 _start,处理多核同步和重定位([1])。
  2. C 代码初始化lib/sbi/sbi_init.c 初始化设备树、异常处理、定时器等([1])。
  3. 链接脚本控制firmware/fw_base.lds 指定代码段布局(.text 起始地址为 FW_TEXT_START,默认 0x80000000)。

四、调试与验证

1. QEMU 模拟运行
qemu-system-riscv64 -machine virt -bios output/opensbi/fw_jump.bin -nographic  

输出示例

OpenSBI v1.2  
Platform Name          : QEMU Virt Machine  
Firmware Base          : 0x80000000  
Firmware Size          : 112 KB  
Runtime SBI Version    : 1.0  
2. GDB 调试技巧
# 启动 QEMU 调试模式  
qemu-system-riscv64 -machine virt -bios fw_jump.bin -s -S -nographic  
# 另开终端连接 GDB  
riscv64-unknown-elf-gdb build/platform/qemu/virt/firmware/fw_jump.elf  
(gdb) target remote :1234  
(gdb) b _start       # 在入口点设置断点  
(gdb) c              # 继续执行  

观察点

  • 检查 a0(HART ID)、a1(设备树地址)寄存器初始化值
  • 跟踪 sbi_init 函数调用链([1])

五、常见问题与解决方案

1. 编译错误:未找到交叉编译器
  • 原因CROSS_COMPILE 路径未正确设置
  • 修复:确认编译器可执行文件存在,例如:
ls /usr/local/riscv64-unknown-elf/bin/riscv64-unknown-elf-gcc  
2. 启动时卡在 _wait_for_boot_hart
  • 分析:非主核(Boot HART)未正确释放锁
  • 调试:修改 fw_base.S 添加调试输出(需重新编译):
/* 在 _wait_for_boot_hart 循环前添加 */  
la a0, msg_wait  
call sbi_platform_console_puts  
3. 自定义平台适配
  1. 复制现有平台模板(如 platform/generic/)至新目录
  2. 修改 objects.mk 添加平台特定驱动
  3. 编译时指定 PLATFORM=new_platform

对于分析 Makefile

使用 make -nB > a.log 查看实际执行的命令,

  • grep 过滤干扰项;sed 让输出更易读
  • 然后再 vim 查看可使‘ ' --> /n
  • 逐级分析 Makefile 中的目标依赖关系。

我们也可以借助之前实现的 ag api:通过 output-->program 的想法, 借助 vim -->ai 来让 ai 帮我们实现注释

直接让AI帮你写注释 调格式,读五百多行的makefile文件也不是梦了🙂


http://www.ppmy.cn/server/179070.html

相关文章

Language Models are Few-Shot Learners,GPT-3详细讲解

GPT的训练范式&#xff1a;预训练Fine-Tuning GPT2的训练范式&#xff1a;预训练Prompt predict &#xff08;zero-shot learning&#xff09; GPT3的训练范式&#xff1a;预训练Prompt predict &#xff08;few-shot learning&#xff09; GPT2的性能太差&#xff0c;新意高&…

国产开发板—米尔全志T113-i如何实现ARM+RISC-V+DSP协同计算?

近年来&#xff0c;随着半导体产业的快速发展和技术的不断迭代&#xff0c;物联网设备种类繁多&#xff08;如智能家居、工业传感器&#xff09;&#xff0c;对算力、功耗、实时性要求差异大&#xff0c;单一架构无法满足所有需求。因此米尔推出MYD-YT113i开发板&#xff08;基…

Unity音频混合器如何暴露参数

音频混合器是Unity推荐管理音效混音的工具&#xff0c;那么如何使用代码对它进行管理呢&#xff1f; 首先我在AudioMixer的Master组中创建了BGM和SFX的分组&#xff0c;你也可以直接用Master没有问题。 这里我以BGM为例&#xff0c;如果要在代码中进行使用就需要将参数暴露出去…

linux去掉绝对路径前面部分和最后的/符号

使用basename命令 basename命令用于获取路径中的文件名部分。它会自动去除路径前面的目录部分和最后的/符号。示例如下&#xff1a; path"/a/b/c" filename$(basename "$path") echo "$filename"path"/a/b/c/" filename$(basename &…

【测试工具】如何使用 burp pro 自定义一个拦截器插件

在 Burp Suite 中&#xff0c;你可以使用 Burp Extender 编写自定义拦截器插件&#xff0c;以拦截并修改 HTTP 请求或响应。Burp Suite 支持 Java 和 Python (Jython) 作为扩展开发语言。以下是一个完整的流程&#xff0c;介绍如何创建一个 Burp 插件来拦截请求并进行自定义处理…

Spring-Mybatis框架常见面试题

1、介绍下什么是Spring框架的IOC和DI IOC 控制反转&#xff0c;指将对象的创建权&#xff0c;反转到Spring容器&#xff1b; DI 依赖注入&#xff0c;指Spring创建对象的过程中&#xff0c;将对象依赖属性通过配置进行注入,不能单独存在&#xff0c;需要在IOC的基础上完成操作…

linux更换镜像源[CentOs]

问题&#xff1a;在使用linux的yum命令时常常会遇到由于无法加载到centos官方镜像源的问题&#xff0c;报错信息如图所示 解决方法&#xff1a;更换国内的数据源 1. 备份原有仓库配置 sudo cp -r /etc/yum.repos.d/ /etc/yum.repos.d.backup # 备份整个目录 sudo rm -rf /et…

SciPy常见面试题及解析

文章目录 1. SciPy与NumPy的区别是什么?2. 如何使用SciPy求解方程 x 2 + 2 x + 1 = 0 x^2 + 2x + 1 = 0 x2+2x+1=0 的根?3. SciPy中如何计算定积分 ∫ 0 π sin ⁡ ( x ) d x \int_{0}^{\pi} \sin(x) dx ∫0π​sin(x)dx?4. 如何用SciPy实现最小二乘法拟合数据?5. SciPy的…