1. QEMU RISC-V 环境搭建
做嵌入式开发这么多年,我越来越觉得,一个好的调试环境能省下一半的排错时间。QEMU 配合 RISC-V,说白了就是让你在没拿到真实芯片之前,先把软件跑起来、把问题揪出来。这一章,咱们先把地基打牢。
1.1 QEMU 是什么?
QEMU 是一个开源的机器模拟器。它能模拟整个硬件平台——CPU、内存、外设,甚至网络。你可以在你的 PC 上跑一个完整的嵌入式系统,就像操作真实开发板一样。
我个人习惯把 QEMU 分成两类用法:
- 系统级模拟(System Mode):模拟整机,可以启动操作系统。我们这门课主要用这种。
- 用户态模拟(User Mode):只模拟 CPU,直接运行单个二进制文件。适合快速测试算法。
核心观点:QEMU 不是玩具。我在一个物联网项目中,芯片样片还没回来,就用 QEMU 把整个协议栈调通了。等板子到手,基本一次点亮。
1.2 RISC-V 架构速览
RISC-V 是个精简指令集架构。它最大的特点是——开放、模块化。你不需要给任何人交授权费,想怎么用就怎么用。
它的指令集分几个层级:
| 指令集 | 全称 | 说明 |
|---|---|---|
| RV32I / RV64I | 基础整数指令集 | 必须实现,包含加减、跳转、访存等 |
| M 扩展 | 乘除法扩展 | 硬件乘除法指令 |
| A 扩展 | 原子操作扩展 | 多核同步必备 |
| F / D 扩展 | 单/双精度浮点 | 浮点运算 |
| C 扩展 | 压缩指令扩展 | 16位指令,减小代码体积 |
嗯,这里要注意:QEMU 默认支持 RV64GC,也就是基础 64 位 + 整数乘除 + 原子 + 浮点 + 压缩。大部分场景够用了。
1.3 从源码编译 QEMU
我建议你从源码编译。为什么?因为发行版自带的 QEMU 版本往往偏旧,而且可能没开启 RISC-V 支持。自己编译,心里有底。
步骤如下:
- 下载源码:从
https://download.qemu.org/获取最新稳定版。 - 安装依赖:
sudo apt-get install build-essential pkg-config
sudo apt-get install libglib2.0-dev libpixman-1-dev
sudo apt-get install ninja-build
- 配置编译:
./configure --target-list=riscv64-softmmu --enable-debug
make -j$(nproc)
sudo make install
我的经验:--enable-debug 这个选项一定要加。它会让 QEMU 输出更多调试信息,后面分析日志时你会感谢这个决定的。
编译大概需要 10-20 分钟,取决于你的机器。趁这个时间,你可以泡杯茶,想想你的项目架构。
1.4 配置 RISC-V 系统级模拟器
编译完成后,验证一下:
qemu-system-riscv64 --version
能看到版本号,说明安装成功。接下来,我们需要一个启动用的固件和内核。我推荐用 OpenSBI + Linux 内核的组合。
快速启动命令示例:
qemu-system-riscv64 \
-machine virt \
-m 2G \
-smp 4 \
-kernel fw_jump.bin \
-device loader,file=Image,addr=0x80200000 \
-append "root=/dev/vda ro" \
-drive file=rootfs.ext4,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-nographic
我来解释一下关键参数:
-machine virt:使用 QEMU 自带的 RISC-V 虚拟平台。这个平台模拟了中断控制器、UART、PCIe 等常用外设。-m 2G:分配 2GB 内存。调试时够用了。-smp 4:模拟 4 个 CPU 核心。多核调试时很有用。-nographic:不使用图形界面,所有输出走串口。我习惯这样,方便复制日志。
避坑指南:我曾经在 -device loader 的地址上栽过跟头。RISC-V Linux 内核的加载地址通常是 0x80200000,但不同固件可能有差异。如果你发现内核没启动,先检查这个地址对不对。
1.5 本章知识结构
下面这张图,把本章的核心脉络串起来了。你可以把它当作一个快速索引。
1.6 验证环境
环境搭好之后,跑一个简单的 Hello World 来验证。你可以在 QEMU 里启动 Linux,然后执行:
echo "Hello from QEMU RISC-V!" > /dev/console
如果串口输出了这行字,恭喜你,环境搭建成功。你想想看,从源码编译到系统启动,每一步都是你自己控制的。这种感觉,比用现成的二进制包踏实多了。
小技巧:把 QEMU 的启动命令写成一个 shell 脚本,比如 run_qemu.sh。后面调试时,你只需要改参数,不用每次都敲一长串命令。
嗯,环境搭好了,后面的事情就好办了。调试、日志分析、故障定位,都建立在这个基础上。咱们一步一步来。