QEMU是一种纯软件实现的虚拟化模拟器,几乎能够模拟全部硬件,包括咱们本次要用的ARM A9平台。它的原理是将guest架构代码转换为TCG中间代码,再转换为host架构代码。linux
虚拟机:ubuntu18.04 LTSexpress
sudo apt install gcc-arm-linux-gnueabi
安装完成后,咱们能够看一下该工具链支持的目标架构:ubuntu
arm-linux-gnueabi-gcc --target
翻一下结果能够看到:架构
Known ARM CPUs (for use with the -mcpu= and -mtune= options): arm1020e arm1020t arm1022e arm1026ej-s arm10e arm10tdmi arm1136j-s arm1136jf-s arm1156t2-s arm1156t2f-s arm1176jz-s arm1176jzf-s arm2 arm250 arm3 arm6 arm60 arm600 arm610 arm620 arm7 arm70 arm700 arm700i arm710 arm7100 arm710c arm710t arm720 arm720t arm740t arm7500 arm7500fe arm7d arm7di arm7dm arm7dmi arm7m arm7tdmi arm7tdmi-s arm8 arm810 arm9 arm920 arm920t arm922t arm926ej-s arm940t arm946e-s arm966e-s arm968e-s arm9e arm9tdmi cortex-a12 cortex-a15 cortex-a15.cortex-a7 cortex-a17 cortex-a17.cortex-a7 cortex-a32 cortex-a35 cortex-a5 cortex-a53 cortex-a57 cortex-a57.cortex-a53 cortex-a7 cortex-a72 cortex-a72.cortex-a53 cortex-a73 cortex-a73.cortex-a35 cortex-a73.cortex-a53 cortex-a8 cortex-a9 cortex-m0 cortex-m0.small-multiply cortex-m0plus cortex-m0plus.small-multiply cortex-m1 cortex-m1.small-multiply cortex-m23 cortex-m3 cortex-m33 cortex-m4 cortex-m7 cortex-r4 cortex-r4f cortex-r5 cortex-r7 cortex-r8 ep9312 exynos-m1 fa526 fa606te fa626 fa626te fa726te fmp626 generic-armv7-a iwmmxt iwmmxt2 marvell-pj4 mpcore mpcorenovfp native strongarm strongarm110 strongarm1100 strongarm1110 xgene1 xscale
支持的arch和CPU很是全,也支持咱们此次将要模拟的cortex-a9;甚至也支持cortex-m,也就能够编译无MMU的单片机的内核和应用。app
sudo apt install qemu
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install
至此,在busybox目录下生成了'_intall' 目录,将做为咱们构建根文件系统的目录,在根文件系统目录下补充一些内容。
增长如下目录:dom
a. dev目录下静态建立以下节点:工具
sudo mknod -m 666 tty1 c 4 1 sudo mknod -m 666 tty2 c 4 2 sudo mknod -m 666 tty3 c 4 3 sudo mknod -m 666 tty4 c 4 4 sudo mknod -m 666 console c 5 1 sudo mknod -m 666 null c 1 3
console 和 null 是必须的,若是没有则会报错。
b. etc/inittab 文件内容以下,可参考busyboxdir/examples/inittab编写:oop
::sysinit:/etc/init.d/rcS ::askfirst:/bin/sh ::ctrlaltdel:/sbin/reboot ::shutdown:/sbin/swapoff -a ::shutdown:/bin/umount -a -r ::restart:/sbin/init tty2::askfirst:/bin/sh tty3::askfirst:/bin/sh tty4::askfirst:/bin/sh
c. etc/fstab 文件内容以下,主要目的是指明一些文件系统挂载点:测试
#device mount-point type option dump fsck order proc /proc proc defaults 0 0 temps /tmp rpoc defaults 0 0 none /tmp ramfs defaults 0 0 sysfs /sys sysfs defaults 0 0 mdev /dev ramfs defaults 0 0
d. etc/init.d/rcS 文件内容以下,inittab第一条指明了从rcS中去执行脚本ui
mount -a echo "/sbin/mdev" > /proc/sys/kernel/hotplug /sbin/mdev -s # 根据/etc/mdev.conf中的配置进行生成设备节点 mount -a
顺便修改rcS的权限:
chmod 777 etc/init.d/rcS
e. lib 文件拷贝,由于busybox咱们采用默认的动态连接(建议),这样能够节省根文件系统大小,由于应用也能够连接相应的库。首先经过下边3条命令任意一条查看busybox依赖的库文件。
arm-linux-readelf -d busybox | grep NEEDED arm--linux-objdump -x busybox | grep NEEDED strings busybox | grep ^lib
注意:ld-linux.so.3有时候不会显示,咱们也必须拷贝它,若是之后编译应用程序,咱们也要查看依赖的库,补足根文件系统中缺乏的库文件。
cp /usr/arm-linux-gnueabi/lib/ld-linux.so.3 _install/lib/ cp /usr/arm-linux-gnueabi/lib/libc.so.6 _install/lib/ cp /usr/arm-linux-gnueabi/lib/libm.so.6 _install/lib/ cp /usr/arm-linux-gnueabi/lib/libresolv.so.2 _install/lib/
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig(option) make
将 zImage dtb文件拷贝出来,方便使用。 若是已经咱们已经开发了一些驱动,须要进行测试,除了将ko文件拷贝到根文件系统中,也应该执行模块安装命令,不然modules依赖关系,参数、符号等没法使用。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules_install INSTALL_MOD_PATH=busybox-dir/_install/
执行完成后,将在根文件系统的lib下建立modules目录。
dd if=/dev/zero of=rootfs.ext3 bs=1M count=32
将该空白文件格式化为ext3格式(内核默认支持文件系统,若是使用其余须要配置内核):
mkfs.ext3 rootfs.ext3
将该空白文件,挂载在一个目录下:
mkdir fs sudo mount -o loop rootfs.ext3 ./fs
将busybox构建的根文件系统拷贝到挂载点下,而后再卸载
sudo cp -rf busybox-dir/_install/* ./fs sudo umount ./fs
qemu-system-arm \ -M vexpress-a9 \ -kernel ./zImage \ -nographic \ -m 512M \ -smp 4 \ -sd ./rootfs.ext3 \ -dtb vexpress-v2p-ca9.dtb \ -append "init=/linuxrc root=/dev/mmcblk0 rw rootwait earlyprintk console=ttyAMA0"
上述脚本,-M 指定了目标板, -kernel 指定了linux内核镜像, -nographic 指定无图形显示,-m 512M指定了运行内存大小,-smp 指定4核, -sd 指定了外部有1个sd卡,卡内是rootfs.ext3镜像文件, -dtb 指定了设备树文件, -append 指定了bootargs; bootargs中init=/linuxrc 指定了init进程是根文件系统下的linuxrc(busybox生成), root=/dev/mmcblk0 指定了根文件系统为sd卡, console指定了ttyAMA0,即控制台。
Booting Linux on physical CPU 0x0 Linux version 4.19.86 (yhangzzz@yhangzzz-virtual-machine) (gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1)) #2 SMP Sun Dec 1 13:35:37 CST 2019 CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache OF: fdt: Machine model: V2P-CA9 Memory policy: Data cache writealloc random: get_random_bytes called from start_kernel+0x98/0x474 with crng_init=0 percpu: Embedded 16 pages/cpu s32780 r8192 d24564 u65536 Built 1 zonelists, mobility grouping on. Total pages: 130048 Kernel command line: init=/linuxrc root=/dev/mmcblk0 rw rootwait earlyprintk console=ttyAMA0 log_buf_len individual max cpu contribution: 4096 bytes ... ... ... EXT4-fs (mmcblk0): mounting ext3 file system using the ext4 subsystem random: fast init done EXT4-fs (mmcblk0): recovery complete EXT4-fs (mmcblk0): mounted filesystem with ordered data mode. Opts: (null) VFS: Mounted root (ext3 filesystem) on device 179:0. Freeing unused kernel memory: 1024K Run /linuxrc as init process random: crng init done mount: mounting temps on /tmp failed: No such device Please press Enter to activate this console. /bin/sh: can't access tty; job control turned off / # ls bin etc lib lost+found sbin tmp dev home linuxrc proc sys usr / #
本文中,使用qemu搭建了arm-a9的虚拟化平台,用于linux内核开发、驱动开发、根文件系统构建、应用开发,或者uboot开发。虽然是虚拟的,可是和实际开发中的步骤基本一致。