在嵌入式开发和内核调试领域,快速构建可重复的测试环境是提升效率的关键。传统物理开发板调试存在硬件依赖性强、环境配置复杂等问题,而QEMU模拟器配合U-Boot、Linux内核和根文件系统的虚拟化方案,为开发者提供了轻量级、可移植的替代方案。
这个项目的独特价值在于实现了U-Boot环境变量的持久化存储——这是很多QEMU方案中缺失的关键功能。实际开发中,我们经常需要修改bootargs、bootcmd等参数,但默认情况下这些配置在QEMU退出后就会丢失。通过本文介绍的方案,开发者可以像操作真实硬件一样保存U-Boot配置,极大提升了开发调试的连贯性。
选择组件版本时需要考虑兼容性链条。以下是经过实测的稳定组合:
注意:ARM架构用户建议使用
qemu-system-arm,x86用户选择qemu-system-x86_64。交叉编译工具链推荐使用Linaro GCC。
Ubuntu/Debian下的依赖安装:
bash复制sudo apt install qemu-system-arm qemu-utils build-essential \
libncurses5-dev bison flex libssl-dev bc
创建项目目录结构:
code复制qemu_uboot_project/
├── images/ # 存放生成的镜像文件
├── linux/ # 内核源码目录
├── uboot/ # U-Boot源码目录
└── buildroot/ # 根文件系统构建目录
获取源码并切换分支:
bash复制git clone https://github.com/u-boot/u-boot.git
cd u-boot
git checkout v2021.10 -b dev_branch
关键配置选项(以ARM vexpress_ca9x4板为例):
bash复制make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_ca9x4_defconfig
make menuconfig
需要特别关注的配置项:
code复制CONFIG_ENV_IS_IN_FAT=y # 启用FAT环境变量存储
CONFIG_SYS_REDUNDAND_ENVIRONMENT=y # 环境变量冗余备份
CONFIG_CMD_SAVEENV=y # 启用saveenv命令
编译命令:
bash复制make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)
生成的u-boot和u-boot.bin将用于后续QEMU启动。
获取稳定版内核源码:
bash复制wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.68.tar.xz
tar xvf linux-5.15.68.tar.xz
cd linux-5.15.68
基础配置(同样以ARM为例):
bash复制make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig
建议通过menuconfig启用以下模块:
code复制Device Drivers ->
[*] Block devices ->
<*> RAM block device support
(16384) Default RAM disk size (kbytes)
[*] Network device support ->
<*> Virtio network driver
编译内核和设备树:
bash复制make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage dtbs -j$(nproc)
Buildroot配置技巧:
bash复制make menuconfig
关键配置路径:
code复制Target options ->
Target Architecture -> ARM (little endian)
Target Variant -> cortex-A9
System configuration ->
(qemu) System hostname
(root) Root password
Filesystem images ->
[*] ext2/3/4 root filesystem
生成根文件系统镜像:
bash复制make
输出文件位于output/images/rootfs.ext4。
创建用于环境变量存储的FAT分区镜像:
bash复制dd if=/dev/zero of=envstore.img bs=1M count=8
mkfs.vfat envstore.img
创建完整的系统镜像(包含多个分区):
bash复制# 创建空白镜像
dd if=/dev/zero of=system.img bs=1M count=256
# 分区操作
sudo parted system.img --script mklabel msdos
sudo parted system.img --script mkpart primary fat32 1MiB 16MiB
sudo parted system.img --script mkpart primary ext4 17MiB 100%
# 挂载并格式化
sudo kpartx -av system.img
sudo mkfs.vfat /dev/mapper/loop0p1
sudo mkfs.ext4 /dev/mapper/loop0p2
U-Boot环境变量通常存储在Flash的特定区域。在QEMU中,我们通过模拟这个行为来实现持久化:
在QEMU启动参数中添加虚拟存储设备:
bash复制-drive if=none,file=envstore.img,format=raw,id=envstore
-device virtio-blk-device,drive=envstore
U-Boot需要正确配置环境变量存储位置:
code复制#define CONFIG_ENV_SIZE (8 * 1024)
#define CONFIG_ENV_OFFSET 0x100000
#define CONFIG_ENV_SECT_SIZE 0x1000
在U-Boot中设置存储设备:
code复制setenv env_devices 'virtio 0'
setenv env_interface 'virtio'
saveenv
ARM架构的典型启动命令:
bash复制qemu-system-arm -M vexpress-a9 -m 512M \
-kernel u-boot \
-drive file=system.img,format=raw,if=sd \
-append "console=ttyAMA0 root=/dev/mmcblk0p2 rw" \
-dtb vexpress-v2p-ca9.dtb \
-serial stdio -net nic -net user
关键参数说明:
-M vexpress-a9:指定ARM vexpress-a9开发板模型-m 512M:分配512MB内存-drive:添加存储设备(模拟SD卡)-append:传递给内核的启动参数-dtb:指定设备树二进制文件自动化引导脚本:
在U-Boot中创建自动引导命令:
code复制setenv bootcmd 'fatload virtio 0:1 0x8000 zImage; \
fatload virtio 0:1 0x8300 vexpress-v2p-ca9.dtb; \
bootz 0x8000 - 0x8300'
saveenv
网络引导配置(可选):
code复制setenv serverip 10.0.2.2 # QEMU用户模式网络的宿主机IP
setenv ipaddr 10.0.2.15
setenv netboot 'tftp 0x8000 zImage; tftp 0x8300 dtb; bootz 0x8000 - 0x8300'
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| U-Boot无法保存环境变量 | 1. 存储设备未正确配置 2. saveenv命令未启用 |
检查CONFIG_ENV_IS_IN_FAT配置 确认存储设备在U-Boot中可见 |
| 内核panic无法挂载根文件系统 | 1. 根文件系统路径错误 2. 文件系统损坏 |
检查内核参数中的root=值 使用fsck检查文件系统 |
| 网络功能不可用 | 1. 内核未编译网络驱动 2. QEMU网络配置错误 |
确认内核配置包含VIRTIO_NET 检查QEMU的-net参数 |
QEMU监控器使用:
启动时添加-monitor telnet:127.0.0.1:5555,server,nowait参数,然后通过telnet连接:
bash复制telnet 127.0.0.1 5555
常用监控命令:
info registers:查看CPU寄存器pmemsave 0 0x10000 dump.bin:保存内存内容GDB调试内核:
bash复制qemu-system-arm -S -s -M vexpress-a9 ...
在另一个终端:
bash复制arm-linux-gnueabihf-gdb vmlinux
(gdb) target remote :1234
启用KVM加速(x86主机):
bash复制-enable-kvm -cpu host
使用virtio设备:
-device virtio-blk-device,drive=maindisk-device virtio-net-device,netdev=net0调整内存大小:
bash复制-m 1G -mem-prealloc
多系统测试:
通过不同的U-Boot配置和内核参数,可以在同一QEMU环境中测试不同版本的Linux发行版。
嵌入式教学:
该方案完美模拟了真实嵌入式系统的启动流程,适合用于:
CI/CD集成:
将QEMU启动测试加入自动化流程,验证系统镜像的完整性。
在实际使用中,我发现环境变量存储的可靠性至关重要。建议定期备份envstore.img文件,特别是在重要配置变更后。另外,对于团队开发,可以预置标准化的U-Boot环境配置,确保所有成员使用相同的启动参数。