2. QEMU 模拟 RISC-V Linux 系统启动
任务说明
本案例使用 QEMU 的 virt 机器加载 RISC-V 内核镜像与根文件系统,启动完整 Linux 并进入 shell。所需产物:内核镜像 Image、根文件系统 rootfs.cpio.gz、QEMU 可执行文件 qemu-system-riscv64。若已有现成内核与 rootfs,可直接跳到“启动命令”一节。
环境与依赖
- Ubuntu/Debian 主机,安装:
sudo apt install qemu-system-misc gcc-riscv64-linux-gnu build-essential bc bison flex libssl-dev cpio - QEMU 版本 ≥ 7.0(
qemu-system-riscv64 --version可查) - 交叉编译器前缀:
riscv64-linux-gnu-
启动流程
最小可复现:构建 rootfs 与启动脚本
下面脚本用 BusyBox 静态二进制构造最小 initramfs,并生成启动命令。内核镜像需自行准备(可用发行版提供的 Image,或先按案例 1 编译)。
#!/bin/bash
# build_and_run.sh —— 构造最小 rootfs 并启动 QEMU
set -e
# 1. 准备 BusyBox(静态编译版,避免依赖动态库)
BB=${BB:-/usr/bin/busybox}
if [ ! -x "$BB" ]; then
echo "缺少静态 busybox,请安装 busybox-static 或指定 BB=路径"
exit 1
fi
# 2. 组装 initramfs 目录树
ROOT=rootfs
rm -rf "$ROOT" && mkdir -p "$ROOT"/{bin,sbin,etc,proc,sys,dev,tmp}
cp "$BB" "$ROOT/bin/busybox"
for c in sh ls cat mount echo poweroff; do
ln -sf busybox "$ROOT/bin/$c"
done
# 3. init 脚本:挂载伪文件系统并进入 shell
cat > "$ROOT/init" <<'EOF'
#!/bin/busybox sh
/bin/busybox --install -s /bin
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev 2>/dev/null || true
echo "=== RISC-V Linux 已启动 ==="
exec /bin/sh
EOF
chmod +x "$ROOT/init"
# 4. 打包为 cpio.gz
( cd "$ROOT" && find . | cpio -o -H newc 2>/dev/null | gzip -9 ) > rootfs.cpio.gz
echo "rootfs.cpio.gz 生成完成: $(du -h rootfs.cpio.gz | cut -f1)"
# 5. 启动 QEMU
KERNEL=${KERNEL:-./Image}
[ -f "$KERNEL" ] || { echo "未找到内核镜像 $KERNEL,请设置 KERNEL=路径"; exit 1; }
exec qemu-system-riscv64 \
-M virt -m 256M -smp 1 -nographic \
-bios default \
-kernel "$KERNEL" \
-initrd rootfs.cpio.gz \
-append "console=ttyS0 rdinit=/init"
运行与验证
- 赋予执行权限并运行:
chmod +x build_and_run.sh && ./build_and_run.sh - 观察串口输出:应依次出现 OpenSBI 版本信息、内核启动日志(
Linux version ...)、=== RISC-V Linux 已启动 ===,最后停在/ #提示符。 - 在 shell 中执行
uname -m,预期输出riscv64;执行cat /proc/cpuinfo可看到isa: rv64...。 - 退出:输入
poweroff -f,或按Ctrl-A再按x结束 QEMU。
判定通过条件:出现 / # 提示符且 uname -m 返回 riscv64,即表示 QEMU 已成功加载内核与根文件系统并进入完整 Linux shell。
常见问题
- 卡在
Starting kernel ...:内核镜像格式不对,需为 RISC-V 的Image(非vmlinuxELF)。 - 内核 panic
No working init found:rdinit=/init与 rootfs 中 init 路径不一致,或 init 未加可执行权限。 - 无串口输出:确认
-nographic与console=ttyS0同时存在。