QEMU + Buildroot 调试环境

一、目标

零硬件搭建一个完整的嵌入式 Linux 开发环境:
- ARM vexpress-a9 / aarch64 virt
- 自定义内核
- 自定义 rootfs
- 远程调试(gdb + gdbserver)
- 文件共享(NFS / 9p)

二、安装依赖

# Ubuntu / Debian
sudo apt install -y \
    build-essential git curl wget \
    libncurses5-dev libncurses-dev \
    flex bison \
    libssl-dev \
    bc \
    rsync cpio \
    device-tree-compiler \
    u-boot-tools mtools dosfstools \
    genisoimage \
    qemu-system-arm qemu-user-static \
    gdb-multiarch

三、Buildroot 方式(推荐)

1. 下载

git clone https://git.buildroot.net/buildroot
cd buildroot
git checkout 2024.02

2. 使用现成 defconfig

make qemu_arm_vexpress_defconfig
make menuconfig
# 主要调整:
# Filesystem images → [*] ext2/3/4 root filesystem
# Filesystem images → [*] cpio the root filesystem (for use as an initial RAM filesystem)

make -j$(nproc)

3. 输出

output/
├── images/
│   ├── rootfs.ext4           # 根文件系统
│   ├── rootfs.cpio           # 初始 RAM disk
│   ├── vmlinux               # 内核 ELF
│   ├── zImage                # ARM 压缩内核
│   └── vexpress-v2p-ca9.dtb  # 设备树
└── host/
    └── bin/
        └── arm-buildroot-linux-uclibc-gcc  # 工具链

四、QEMU 启动

1. 直接内核 + initramfs

qemu-system-arm \
    -M vexpress-a9 \
    -m 512M \
    -kernel output/images/zImage \
    -dtb output/images/vexpress-v2p-ca9.dtb \
    -initrd output/images/rootfs.cpio \
    -append "console=ttyAMA0,115200" \
    -nographic

2. 内核 + 硬盘镜像

qemu-system-arm \
    -M vexpress-a9 \
    -m 512M \
    -kernel output/images/zImage \
    -dtb output/images/vexpress-v2p-ca9.dtb \
    -drive file=output/images/rootfs.ext4,if=sd,format=raw \
    -append "console=ttyAMA0,115200 root=/dev/mmcblk0 rootfstype=ext4 rootwait" \
    -nographic

3. 使用 U-Boot

# 下载
git clone https://source.denx.de/u-boot/u-boot
cd u-boot
make vexpress_ca9x4_defconfig
make CROSS_COMPILE=arm-linux-gnueabihf-
cd ..

qemu-system-arm \
    -M vexpress-a9 \
    -m 512M \
    -kernel u-boot/u-boot \
    -nographic

U-Boot 交互:

=> setenv bootargs "console=ttyAMA0,115200 root=/dev/mmcblk0 rootfstype=ext4 rootwait"
=> setenv bootcmd "load mmc 0:1 ${loadaddr} zImage; load mmc 0:1 ${fdt_addr_r} vexpress-v2p-ca9.dtb; bootz ${loadaddr} - ${fdt_addr_r}"
=> saveenv
=> boot

五、qemu-user 模拟用户态

# 单个程序
qemu-arm ./myapp
qemu-aarch64 ./myapp

# chroot
sudo qemu-arm-static -B /path/to/rootfs /bin/sh

六、网络配置

1. 用户网络(默认)

qemu-system-arm ... -net nic -net user,hostfwd=tcp::2222-:22
# 主机 ssh -p 2222 ...

2. tap 网络(高级)

# 创建 tap
sudo ip tuntap add dev tap0 mode tap user $USER
sudo ip link set tap0 up
sudo ip addr add 192.168.1.1/24 dev tap0

qemu-system-arm ... -net nic -net tap,ifname=tap0,script=no
# QEMU 中配置 eth0: 192.168.1.2

七、远程调试

1. QEMU 启动 + gdb server

qemu-system-arm \
    -M vexpress-a9 \
    -m 512M \
    -kernel zImage \
    -dtb vexpress-v2p-ca9.dtb \
    -initrd rootfs.cpio \
    -append "console=ttyAMA0,115200" \
    -nographic \
    -gdb tcp::1234 \
    -S                        # 启动时暂停

2. 主机 GDB

arm-linux-gnueabihf-gdb vmlinux
(gdb) target remote :1234
(gdb) b start_kernel
(gdb) c

八、9p 文件共享(推荐)

# 主机:创建 rootfs_overlay
mkdir -p rootfs_overlay/root/myapp
arm-linux-gnueabihf-gcc -o rootfs_overlay/root/myapp/main main.c

qemu-system-arm \
    -M vexpress-a9 \
    -m 512M \
    -kernel zImage -dtb vexpress-v2p-ca9.dtb \
    -drive file=rootfs.ext4,if=sd,format=raw \
    -append "..." \
    -virtfs local,path=rootfs_overlay,mount_tag=hostshare,security_model=none \
    -nographic

# 目标机内
mount -t 9p -o trans=virtio hostshare /mnt

九、NFS 根文件系统

1. 主机配置 NFS

sudo apt install nfs-kernel-server
echo "/path/to/rootfs 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
sudo exportfs -a

2. 启动 QEMU

qemu-system-arm \
    -M vexpress-a9 -m 512M \
    -kernel zImage -dtb vexpress-v2p-ca9.dtb \
    -append "root=/dev/nfs ip=dhcp nfsroot=192.168.1.10:/path/to/rootfs,tcp,v3 console=ttyAMA0,115200" \
    -net nic,model=lan9118 \
    -net tap,ifname=tap0 \
    -nographic

十、使用 Buildroot 的 cpio 自动重载

修改 rootfs_overlay 后:

make                  # 重新生成 rootfs.cpio
# 启动
qemu-system-arm ... -initrd output/images/rootfs.cpio

十一、调试技巧

1. 启动快

echo 0 > /proc/sys/kernel/printk   # 减少启动日志

2. 监视 QEMU

3. 串口转发到文件

qemu-system-arm -serial file:serial.log ...

十二、推荐 QEMU 命令模板

保存为 run.sh

#!/bin/bash
set -e
cd $(dirname $0)

qemu-system-arm \
    -M vexpress-a9 \
    -m 512M \
    -kernel output/images/zImage \
    -dtb output/images/vexpress-v2p-ca9.dtb \
    -drive file=output/images/rootfs.ext4,if=sd,format=raw \
    -append "console=ttyAMA0,115200 root=/dev/mmcblk0 rootfstype=ext4 rootwait" \
    -nographic \
    "$@"
chmod +x run.sh
./run.sh