1. 搭建QEMU RISC-V开发环境
任务说明
本案例目标是在Linux主机上安装QEMU系统模拟器与RISC-V交叉编译工具链,并验证QEMU能够启动一个最小的RISC-V固件镜像。完成本案例后,你将拥有一个可复用的RISC-V固件开发与调试基础环境。
环境准备
本案例以Ubuntu 22.04 LTS为参考环境。需要安装的软件包包括:qemu-system-misc(提供RISC-V 64位系统模拟)、gcc-riscv64-unknown-elf(交叉编译器)、gdb-multiarch(用于后续调试)。执行以下命令安装:
sudo apt update
sudo apt install -y qemu-system-misc gcc-riscv64-unknown-elf gdb-multiarch
安装完成后,验证工具版本:
qemu-system-riscv64 --version
riscv64-unknown-elf-gcc --version
最小固件实现
创建一个最小固件,该固件在启动后向主机串口输出一行字符,然后进入死循环。这是验证QEMU启动流程的最简可执行程序。
新建文件 start.S:
.section .text.init
.globl _start
_start:
# 设置栈指针(使用链接脚本中定义的栈顶)
la sp, _stack_top
# 调用C入口
call main
loop:
wfi
j loop
新建文件 main.c:
#define UART0_BASE 0x10000000L
#define UART0_THR (*(volatile unsigned char *)(UART0_BASE + 0x00))
void uart_putc(char c) {
UART0_THR = c;
}
void uart_puts(const char *s) {
while (*s) {
uart_putc(*s++);
}
}
void main(void) {
uart_puts("Hello RISC-V QEMU!\n");
while (1) {
// 空循环,等待中断或复位
}
}
新建链接脚本 link.ld:
OUTPUT_ARCH(riscv)
ENTRY(_start)
MEMORY
{
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 128M
}
SECTIONS
{
.text : {
*(.text.init)
*(.text)
} > RAM
.rodata : {
*(.rodata)
} > RAM
.data : {
*(.data)
} > RAM
.bss : {
*(.bss)
} > RAM
. = ALIGN(16);
. = . + 0x1000; /* 预留4KB栈空间 */
_stack_top = .;
}
编译与链接
执行以下命令生成固件镜像 firmware.elf:
riscv64-unknown-elf-gcc -march=rv64gc -mabi=lp64d -nostdlib -fno-builtin -nostartfiles \
-T link.ld -o firmware.elf start.S main.c
参数说明:-march=rv64gc 指定64位RISC-V指令集(含乘法除法与原子指令),-mabi=lp64d 使用64位整数与双精度浮点ABI,-nostdlib 与 -nostartfiles 表示不使用标准库与标准启动文件,-T link.ld 指定链接脚本。
QEMU启动验证
使用以下命令启动QEMU并运行固件:
qemu-system-riscv64 -machine virt -nographic -bios none -kernel firmware.elf
参数说明:-machine virt 选择virt虚拟开发板(该板型将UART0映射在0x10000000地址),-nographic 将串口重定向到当前终端,-bios none 表示不加载BIOS,直接使用 -kernel 指定的固件。
验证方法与判定标准
执行上述QEMU命令后,终端应显示以下输出:
Hello RISC-V QEMU!
随后程序进入死循环,QEMU进程保持运行状态(不会自动退出)。判定标准:
- 终端出现上述字符串,说明UART驱动与启动流程正确;
- QEMU进程不退出,说明固件正常进入循环,没有触发异常复位;
- 按
Ctrl+A然后按X可退出QEMU。
常见问题排查
- QEMU提示无法打开设备:确认已安装
qemu-system-misc包,且当前用户有权限访问终端设备。 - 编译报错找不到头文件:本案例未使用任何标准库头文件,若添加了
#include语句,需使用-nostdinc并自行提供头文件,或改用riscv64-unknown-elf-gcc自带的freestanding头文件。 - 无输出且QEMU卡死:检查链接脚本中
_start是否被正确放置在入口地址,可使用riscv64-unknown-elf-objdump -d firmware.elf查看反汇编确认入口代码位置。
至此,QEMU RISC-V开发环境搭建完成,后续案例将在此基础上进行固件开发与调试。