使用 QEMU 模拟嵌入式 Linux 系统
1. 简介
嵌入式软件开发依赖于嵌入式硬件设备,如开发板、外部模块设备等,但如果调试工作与外设无关,则无需购买硬件即可使用QEMU模拟内核调试。
它可用于 Linux 和 Windows 主机以及模拟的 PowerPC、ARM、MIPS 和 SPARC 目标。 QEMU 采用在主机和目标处理器之间提供最小转换层的方法。 主机处理器是运行仿真器的处理器,目标处理器是被仿真的处理器。
下面详细介绍搭建QEMU开发环境的过程。
2。 环境
2.1 使用环境
* Ubuntu-18.04.1
或者:
* 电脑:Windows10
* 虚拟机:VirtualBox-5.18
* 虚拟操作系统:Ubuntu-18.04.1
* 模拟开发板:vexpres
2.2 搭建环境时用到的工具
* qemu-4.2.0
* linux-4.14.172 (Linux 内核)
* u-boot-2017.05
*busybox-1.31.1
*arm-linux-gnueabi-gcc
将所有相关文件放在 /home/joe/qemu
3.安装交叉编译工具
# sudo apt 安装 gcc-arm-linux-gnueabi
检查是否安装成功
$arm-linux-gnueabi-gcc -v
使用内置规格。 COLLECT_GCC=arm-linux-gnueabi-gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/arm-linux-gnueabi/7/lto-wrapper 目标:arm-linux-gnueabi 配置:../src/configure -v –with-pkgversion='Ubuntu/Linaro 7.5.0-3ubuntu1~18.04′--with-bugurl=file:///usr 线程模型:posix gcc 版本 7.5.0(Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) |
4.配置和编译Linux内核
4.1 下载Linux内核
从 www.kernel.org 下载所需的内核版本。
这里我下载了相对最新的长期支持的内核版本linux-4.4.157
wget的 https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.4.157.tar.xz 到 /qemu 目录
4.2 解压Linux内核
# tar xvJf linux-4.4.157.tar.xz
4.3 编译Linux内核
// 进入内核源文件目录
# cd linux-4.4.157
使 CROSS_COMPILE=arm-linux-gnueabi-ARCH=arm vexpress_defconfig
make CROSS_COMPILE=arm-linux-gnueabi-ARCH=arm menuconfig
如果运行 menuconfig 显示缺少 ncurses 包,只需运行以下命令安装即可)
$ sudo apt-get 安装 libncurses5-dev
进入菜单配置,进行如下设置
使用交叉工具链编译
编译成功后,在目录下生成内核镜像文件
arch/arm/boot, zImage 和 dtb 可以复制到单独的文件夹中,方便使用
5. 安装 QEMU 工具
5.1 安装 QEMU
* wget https://download.qemu.org/qemu-4.2.0.tar.xz
* tar xvJf qemu-4.2.0.tar.xz
* cd qemu-4.2.0
5.2 配置QEMU前安装依赖包
# apt 安装 zlib1g-dev
# apt 安装 libglib2.0-0 libglib2.0-dev
# apt 安装 libsdl1.2-dev
# apt 安装 libpixman-1-dev libfdt-dev
为了防止编译后文件杂乱,创建builder目录作为编译的中间目标路径。
配置、编译和安装 QEMU。
5.3 配置QEMU支持arm架构下的所有板卡
# ../configure --target-list=arm-softmmu --audio-drv-list=
如果出现以下提示时缺少pixman,
使用 sudo apt-get install libpixman-1-dev 安装它。
5.4 查看QEMU版本
5.5 查看QEMU支持的开发板
5.6 运行 QEMU
# qemu-system-arm -M vexpress-a9 -m 512M -kernel ./zImage -dtb ./vexpress-v2p-ca9.dtb -ngraphic -append “console=ttyAMA0”
要么:
$密码
/家/乔/qemu
# qemu-system-arm -M vexpress-a9 -m 512M -kernel linux-.4.157/arch/arm/boot/zImage -dtb linux-4.4.157/arch/arm/boot/dts/vexpress-v2p-ca9. dtb -nographic -append “console=ttyAMA0”
为了更好的测试和启动qemu,可以创建启动脚本start.sh,并赋予脚本运行权限chmod +x start.sh
#!/斌/庆典
qemu 系统臂 \
-M vexpress-a9 \
-m 512M \
-内核/home/joe/jemu/linux-4.4.157/arch/arm/boot/zImage \
-dtb /home/joe/jemu/linux-4.4.157/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-地理\
-附加“控制台= ttyAMA0”
6.制作根文件系统
使用busybox制作一个简单的根文件系统。
6.1 下载busybox工具
从 https://busybox.net/downloads/ 下载busybox
# wget https://busybox.net/downloads/busybox-1.31.1.tar.bz2
# tar xjvf busybox-1.31.1.tar.bz2
# cd busybox-1.31.1
# 进行定义
# 使 CROSS_COMPILE=arm-linux-gnueabi-
# 安装 CROSS_COMPILE=arm-linux-gnueabi-
提示如下信息,说明安装成功。
安装完成后,生成的目标文件默认在./_install目录下。
6.2 生成根文件系统
6.2.1 编译安装busybox
# mkdir 根文件系统
# sudo cp -r _install/* rootfs/
6.2.2 添加glibc库,在根文件系统中添加loader和动态库
# sudo cp -r _install/* rootfs/
# sudo cp -p /usr/arm-linux-gnueabi/lib/* rootfs/lib/
6.2.3 创建4个tty终端设备(c代表字符设备,4是主设备号,1~4分别是次设备号)
6.3 制作SD卡文件系统镜像
6.3.1 生成空的SD卡镜像
# dd if=/dev/zero of=rootfs.ext3 bs=1M count=32
6.3.2 将 SD 卡格式化为 exts 文件系统
# mkfs.ext3 根文件系统.ext3
6.3.3 烧录rootfs到SD卡
# sudo mount -t ext3 rootfs.ext3 /mnt -o 循环
# sudo cp -rf rootfs/* /mnt/
# sudo 卸载 /mnt
7. 验证
7.1 启动 Qemu
运行以下命令进行测试,检查编译后的内核是否可以成功运行
# sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel ~/qemu/zImage –dtb ~/qemu/vexpress-v2p-ca9.dtb -ngraphic -append “console=ttyAMA0”
或者使用脚本:
在上面的测试中,内核会报panic,提示我们缺少根文件系统。
以上问题是由于x86环境下busybox工具生成的。
我们在安装busybox时使用了make install,所以你应该使用
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-安装 |
编译工具生成arm平台使用的busybox工具
# 文件 rootfs/bin/busybox
rootfs/bin/busybox:ELF 32 位 LSB 可执行文件,ARM,EABI5 版本 1 (SYSV),动态链接,解释器 /lib/ld-,适用于 GNU/Linux 3.2.0,BuildID[sha1]=cbcd33b8d6c946cb19408a5e8e714f554
7.2 再次验证
现在Qemu已经启动Linux内核并成功挂载文件系统,可以通过串口终端与系统进行简单的功能交互。 打印过程中无法运行/etc/init.d/rcS的问题,只需要添加/etc/init.d/rcS文件即可。 文件的内容可以是提示语句。
7.3 退出 QEMU
退出qemu的两种方式
* 在另一个终端输入中:kill all qemu-system-arm
* 在Qemu中输入:Ctrl+A; X
QEMU:终止
8.通过u-boot启动Linux内核
嵌入式系统通常包括:u-boot、kernel、rootfs、appfs。 这些部件在ARM开发板上的位置关系如下图所示
引导加载程序 | 引导参数 | 核心 | 根文件 | 应用程序 |
Rootfs 可以在板载或 PC 上运行
8.1 准备U-boot
8.1.1 下载u-boot
http://ftp.denx.de/pub/u-boot/,我们使用:u-boot-2021.01.tar.bz2
# tar -jxvf u-boot-2018.09.tar.bz2
8.1.2 编译u-boot
# vim 生成文件
CROSS_COMPILE = arm-linux-gnueabi-
# vim 配置.mk
ARCH = 手臂
# 制作 vexpress_ca9x4_defconfig,错误
需要:sudo apt install bison
sudo apt 安装 flex
然后:#make -j4 错误
需要:导出 CROSS_COMPILE=arm-linux-gnueabi-
出口 ARCH=臂
再次:# make vexpress_ca9x4_defconfig
#make -j4
8.1.3 测试,启动u-boot
$ sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel u-boot-2021.01/u-boot –ngraphic
8.2 内核配置编译
使用 u-boot 启动内核镜像:
需要将内核编译成uImage格式,
需要指定uImage在内存中的加载地址
编译内核时指定:make LOADADDR=? uImage -j4
# cd /home/joe/qemu/linux-4.4.157
# 使 LOADADDR=0x60003000 uImage -j4
u-boot编译完成后,在tool文件夹下会生成一个mkimage文件,把这个文件拷贝到交叉编译目录下的bin文件夹下。
$ cd qemu/linux-4.4.157
错误:
$ sudo apt 安装 u-boot-tools
获取 uImage
9.QEMU网络功能设置
当Qemu虚拟机在u-boot上启动时,需要将uImage加载到内存中,通过TFTP服务器可以将uImage下载到内存中的指定地址。
9.1 检查主机内核是否支持tun/tap模块
// 安装桥接网络依赖的两个工具
# sudo apt 安装 uml-utilities bridge-utils
创建tun设备文件:/dev/net/tun(一般是自动创建的)
修改/etc/network/interfaces(配置网络,重启生效)
# sudo vim /etc/网络/接口
auto loiface lo inet loopbackauto enp0s3 // 虚拟网卡名称auto br0iface br0 inet dhcpbridge_ports enp0s3 |
永不重启
# 重启
然后查看Qemu的网络环境
虚拟网口br0是Qemu虚拟机与Linux主机通信的网口。
10.安装TFTP服务器
Qemu仿真开发板启动uImage时创建TFTP服务器将uImage下载到内存
10.1 安装tftp工具
$ apt-get 安装 tftp-hpa tftpd-hpa xinetd
10.2 修改配置文件,设置TFTP服务器目录
# sudo vim /etc/default/tftpd-hpa
...... TFTP_DIRECTORY="/home/joe/tftpboot" ...... |
10.3 在Linux主机上创建tftp目录
# mkdir /home/joe/tftpboot
# chmod 777 /home/joe/tftpboot
10.4 重启tftp服务
# sudo /etc/init.d/tftpd-hpa 重启
10.5 在u-boot中设置内核启动参数
将 uImage 和 cexpress-v2p-ca9.dtb 复制到 tftpboot
启动Qemu进行验证
$ sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel u-boot-2021.01/u-boot –nographic -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 -sd rootfs.分机3
现在rootfs目录就是一个简单的根文件系统,可以做成镜像文件,可以把镜像文件烧录到开发板上,也可以用Qemu中的u-boot启动Linux内核挂载到开发板上镜像文件。 它也可以设置为通过 NFS 网络文件系统启动。
11.挂载NFS文件系统
11.1 安装配置NFS服务
11.1.1安装
$ sudo apt 安装 nfs-kernel-server
11.1.2 配置
$ sudo mkdir /home/joe/qemu/rootfs
$ sudo chown nobody:nogroup /home/joe/qemu/rootfs
$ sudo chmod 777 /home/joe/qemu/rootfs
$ sudo nano /etc/exports
添加:/home/joe/qemu/rootfs *(rw,sync,no_root_squash)
重启 nfs 服务器:
$ sudo /etc/init.d/nfs-kernel-server restart
或者: $systemctl restart nfs-kernel-server
检查是否创建了NFS共享目录
$ sudo showmount –e
Linux主机在使用NFS网络文件系统时需要关闭系统防火墙,否则系统运行时会出现异常。
总结
希望在这篇博客的帮助下,您对 QEMU 有了更多的了解。 上面展示的所有技术都用于我们程序的各种提交。 没有一种单一的、固定的方式来模拟 QEMU。 探索不同的技术,看看什么适合你。 熟悉这些知识,您会惊讶于它如何以意想不到的方式帮助您。