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-

启动流程

qemu-system-riscv64 -M virt -bios fw OpenSBI 固件 fw_jump.bin Linux 内核 Image rootfs cpio.gz 内核解压 initramfs → 挂载 rootfs 执行 /init → 启动 /bin/sh 串口 shell / # 提示符

最小可复现:构建 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"

运行与验证

  1. 赋予执行权限并运行:chmod +x build_and_run.sh && ./build_and_run.sh
  2. 观察串口输出:应依次出现 OpenSBI 版本信息、内核启动日志(Linux version ...)、=== RISC-V Linux 已启动 ===,最后停在 / # 提示符。
  3. 在 shell 中执行 uname -m,预期输出 riscv64;执行 cat /proc/cpuinfo 可看到 isa: rv64...。
  4. 退出:输入 poweroff -f,或按 Ctrl-A 再按 x 结束 QEMU。

判定通过条件:出现 / # 提示符且 uname -m 返回 riscv64,即表示 QEMU 已成功加载内核与根文件系统并进入完整 Linux shell。

常见问题

  • 卡在 Starting kernel ...:内核镜像格式不对,需为 RISC-V 的 Image(非 vmlinux ELF)。
  • 内核 panic No working init found:rdinit=/init 与 rootfs 中 init 路径不一致,或 init 未加可执行权限。
  • 无串口输出:确认 -nographic 与 console=ttyS0 同时存在。