qemu模拟vexpress开发板
1. 问题背景
最近了解到一个强大的开源虚拟机软件:qemu。利用它可以仿真arm板,正好可以用来巩固一下移植相关的操作。网上关于qemu仿真vexpress开发板的例子较多,我试了几个,感觉还是下面这篇文章比较靠谱:
https://www.cnblogs.com/pengdonglin137/p/5023342.html 。目前我进行到用qemu加载u-boot,或者加载内核并挂载ramdis根文件系统,也可以利用u-boot来引导内核启动,但是无法挂载根文件系统。
2. 环境介绍
虚拟机系统:Ubuntu 14.04
u-boot: u-boot-2015-04
linux kernel: linux-3.4.4
busybox: busybox-1.21.0
toolchain: arm-none-linux-gnueabi- (4.6.4)
qemu: QEMU emulator version 1.7.91
这个qemu是直接通过apt在线安装的,在模拟某个arm板前,先看看qemu支不支持。
1 qemu-system-arm -M ?
3. U-boot配置
3.1 u-boot缺省配置
在u-boot-2015.04目录下,先看看关于vexpress的默认配置有哪些,这里我们选vexpress_ca9x4_defconfig来进行默认的配置,使用make指令,可以在命令行指定架构和交叉编译器,也可以写死在Makefile中。
1 ls configs/ | grep vexpress 2 make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- vexpress_ca9x4_defconfig
3.2 u-boot环境变量
这里主要设置bootargs,bootcmd和bootm。我们可以把这些东西写死到include/configs/vexpress_common.h中,否则就要进入u-boot后手动敲命令设置,而且设置好后也不能save(没有flash)。
bootcmd:对应宏CONFIG_BOOTCOMMAND,是u-boot启动时会自动执行的命令。
bootargs:是u-boot传递内核的参数。
bootm: ${kernel_addr} ${ramdisk_addr} ${dtb_addr} 依次是内核镜像地址,根文件镜像地址,设备树地址
211 /* Basic environment settings */ 212 #if 0 213 #define CONFIG_BOOTCOMMAND "run bootflash;" //将原有的宏注释掉 214 #endif 215 216 #define CONFIG_IPADDR 192.168.222.21 //本机IP 217 #define CONFIG_NETMASK 255.255.255.0 //掩码 218 #define CONFIG_SERVERIP 192.168.222.20 //服务器IP:tftp服务和nfs服务 219 220 #define CONFIG_BOOTCOMMAND \ 221 "tftp 0x60008000 uImage3.4.4; " \ 222 "tftp 0x63000000 ramdisk_zy.img; " \ 223 "setenv bootargs root=/dev/mmcblk0 console=ttyAMA0; " \ 224 "bootm 0x60008000 0x63000000; "
3.3 生成u-boot.bin
同样使用make指令,指定一下ARCH和CROSS_COMPILE。后面的-j2是指定2个核同时编译,增加编译速度。目标文件是一个二进制文件,u-boot.bin,这就是要烧写到flash或者qemu要加载的对象。
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- -j2
生成好u-boot后,先用qemu测试一下能否加载。这里参数的意义就直接抄过来吧。
-M vexpress-a9 模拟vexpress-a9单板,你可以使用-M ?参数来获取该qemu版本支持的所有单板
-m 512M 单板运行物理内存512M
-kernel /root/tq2440_work/kernel/linux-stable/out_vexpress_3_16/arch/arm/boot/zImage 告诉qemu单板运行内核镜像路径
-nographic 不使用图形化界面,只使用串口
-append "console=ttyAMA0" 内核启动参数,这里告诉内核vexpress单板运行,串口设备是哪个tty。
20 qemu-system-arm \ 21 -M vexpress-a9 \ 22 -m 256M \ 23 -kernel /home/linux/qemu_linux/u-boot-2015.04/u-boot \ 24 -serial stdio \ 25 -append "root=/dev/mmcblk0 nolock rw console=tty0" \
启动后使用print指令打印环境变量,可以发现在3.2中设置的环境变量在u-boot中有所体现。
4. Linux内核配置
和u-boot的配置步骤类似。先找找缺省配置文件。
ls arch/arm/configs/ | grep vexpress
make 默认配置。
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- vexpress_defconfig
4.1 内核加载地址和启动选项配置
编译内核我们可以通过menucofig先看一下具体的配置内容。在boot option中我们可以配置一下下图中的内容,这是用来设定内核启动一些参数,可以通过boot loader来传递参数(bootargs),也可以设定默认参数。
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- menuconfig
编译内核。这里要说明一下LOADADDR=0x60008000,在上一篇博客我有简单的搜集一些资料,可以参考(虽然还是似懂非懂。。。),不过按照设置可以在qemu中跑起来。这里的LOADADDR我是参考arch/arm/mach-vexpress/Makefile.boot来设置的,其内容如下图。
这里直接生成了uImage(用于u-boot引导),当然zImage也会同时生成。如果编译过程中提示缺少mkimage工具,可以通过apt在线安装,也可以自己下,这里就不再多说。
make LOADADDR=0x60008000 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage -j2
同样,可以先用qemu加载一下。内核可以起来,但是由于没有指定根文件系统,内核会报错。所以下一步我们要制作根文件系统。
20 qemu-system-arm \ 21 -M vexpress-a9 \ 22 -m 256M \ 23 -kernel uImage \ 24 -serial stdio \ 25 -append "root=/dev/mmcblk0 nolock rw console=tty0" \
5. busybox制作根文件系统
5.1 配置busybox
本文制作的根文件系统 = busybox(包含基础的Linux命令) + 运行库 。那么根文件系统放在哪里?依赖于每个开发板支持的存储设备,可以放到Nor Flash上,也可以放到SD卡,甚至外部磁盘上。最关键的一点是你要清楚知道开发板有什么存储设备。
进入busybox,运行 make menuconfig。配置静态建立busybox。
File systems ---> Pseudo filesystems ---> [*] Virtual memory file system support (former shm fs) [*] Tmpfs POSIX Access Control Lists
然后运行 make install 。完成后,会在busybox目录下生成_install目录,该目录下的程序就是单板运行所需要的命令。将这里面的内容全部复制到一个新建的文件夹,如rootfs下面。
还有很重要的一点就是etc/目录下的内容,这里一般有4个文件,可以手动进行配置,也可以直接从网上下。https://files.cnblogs.com/files/pengdonglin137/etc.tar.gz
简单说一下4个文件的作用:
- /etc/fstab 文件负责配置Linux开机时自动挂载的分区。
- rcS是一个脚本文件,在inittab文件中本解析调用,用于配置Linux系统。这个可以参考https://www.cnblogs.com/lp1129/articles/3148858.html。
- init程序需要读取配置文件/etc/inittab.inittab是一个不可执行的文本文件,它有若干行指令所组成。可以参考https://www.cnblogs.com/jason-lu/articles/3272963.html
- /etc/profile:这个文件是每个用户登录时都会运行的环境变量设置,注意是全局的
到目前为止,一个mini的根文件系统就制作好了,我们可以通过nfs来直接挂载到这个rootfs,也可以把它制作成ramdisk镜像,直接烧录到flash中。
5.2 制作ramdisk镜像
运行以下命令,这里解释一下4-7的作用,先创建一个临时目录,用于挂载制作好的根文件系统,再把rootfs的内容复制到这个根文件系统中,类似于我们平时使用u盘。
1 sudo dd if=/dev/zero of=rootfs.ext3 bs=1M count=32 2 sudo mkfs.ext3 rootfs.ext3 3 4 sudo mkdir -p tmpfs 5 sudo mount -t ext3 rootfs.ext3 tmpfs/ -o loop 6 sudo cp -r rootfs/* tmpfs/ 7 sudo umount tmpfs·
接下来,用qemu加载内核和ramdisk。最后的 -sd 即是模拟一个sd卡,里面存放着跟文件系统。
qemu-system-arm \ -M vexpress-a9 \ -m 256M \ -kernel /home/linux/qemu_linux/linux-3.4.4/arch/arm/boot/zImage \ -nographic \ -append "root=/dev/mmcblk0 rw console=ttyAMA0" \ -sd ~/qemu_linux/rootfs.ext3
6. 结果
理想结果,用qemu加载u-boot,再通过u-boot来引导内核,内核直接加载ramdisk,或者通过nfs来加载rootfs。
实际结果:上面黄字标注的没有实现成功。。。
如下图,u-boot自启动后成功从tftp服务器下载了内核镜像和ramdisk。
但是无法挂载根文件系统: