Title: 用qemu模拟arm
Date: 2016-06-23 17:24:06
Category: 技术
Tags: 总结, Linux
Slug: 用qemu模拟arm
Author: Lemon Tree

配置环境

主机Fedora19 x86_64,需要先安装poky和poky工具链,并有内核源码,目标板子是vexpress。
需要一个带有库文件的rootfs-test,用来进行测试。

source /opt/poky-lsb/1.4.2/environment-setup-armv7a-vfp-neon-poky-linux-gnueabi
export CROSS_COMPILE="arm-poky-linux-gnueabi-"

检查环境

  • 环境变量检查

查看环境变量:

echo $PATH
echo $ARCH
echo $CROSS_COMPILE

正确的情况下输出为:

/opt/poky-lsb/1.4.2/sysroots/x86_64-pokysdk-linux/usr/bin:/opt/poky-lsb/1.4.2/sysroots/x86_64-pokysdk-linux/usr/bin/armv7a-vfp-neon-poky-linux-gnueabi:...
arm
arm-poky-linux-gnueabi-
  • 编译工具与文件检查

编写helloWorld.c进行测试:

//helloWorld.c
#include<stdio.h>

int
main(void)
{
    printf("Hello, World!\n");
    return 0;
}

进行编译,-static静态编译,--sysroot指定一个完整的rootfs,保证helloWorld中所需的文件存在(如果不指定rootfs,ld报错cannot find -lc):

arm-poky-linux-gnueabi-gcc -o hello helloWorld.c -static --sysroot=rootfs-test/
qemu-arm ./hello

编译内核

cd linux-yocto-3.10-arm/
make distclean
make vexpress_defconfig
make menuconfig
  • 根据需求定制

进入Device Drivers/Generic Driver Option/,勾选Maintain a devtmpfs filesystem to mount at /dev和Automount devtmpfs at /dev, after the kernel mounted the rootfs。

make zImage

生成的内核zImage在linux-yocto-3.10-arm/arch/arm/boot/下。

测试内核

制作一个简单的initramfs,用来测试内核是否可以正常启动。

//init.c
#include <stdio.h>

void
main(void)
{
    printf("Hello World!\n");
    while(1);
}

进行编译:

arm-poky-linux-gnueabi-gcc -o init init.c -static --sysroot=rootfs-test/

将生成的可执行文件作成启动镜像:

echo init | cpio -o --format=newc > initramfs

用qemu启动内核,其中-M是板子型号(qemu-system-arm -M ?可查看所有支持的板子型号),-kernel是指定内核,-initrd是指定启动镜像,-append是传递给内核的参数,console是信息的输出终端,-display是显示模式(vnc,sld),-serial是串口重定向:

qemu-system-arm -M vexpress-a9 -kernel linux-yocto-3.10-arm/arch/arm/boot/zImage  -initrd ./initramfs -append "console=ttyAMA0" -display none -serial stdio

qemu启动并打印Hello World! 。

制作文件系统

  • 利用poky制作(简单,可选带openssh)

进入已经git下来的poky,载入编译环境脚本:

cd poky
source oe-init-build-env

此时目录变为BUILD,即poky/build/。

修改conf/local.conf,取消MACHINE ?= "qemuarm"的注释。也可以修改BB_NUMBER_THREADS和PARALLEL_MAKE来加快编译速度。
修改poky/recipes-core/images/core-image-minimal.bb,在IMAGE_INSTALL中增加openssh。

在BUILD目录下执行:

bitbake core-image-minimal

执行完之后,生成的镜像在poky/build/tmp/deploy/images/qemuarm中,core-image-minimal-qemuarm-xxxxxxxxxxxxxx.rootfs.tar.bz2就是所生成的rootfs压缩包。

解压后验证sshd服务默认开启(sysvinit):
> mkdir rootfs
> tar -jxvf core-image-minimal-qemuarm-xxxxxxxxxxxxxx.rootfs.tar.bz2 -C ./rootfs/
> find ./rootfs/etc/rc*\.d | grep sshd
> 

正常情况下,在默认的runlevel中会有Sxxsshd文件
默认的runlevel的定义在./rootfs/etc/inittab中会

重新作成启动镜像:

cd ./rootfs/
find . | cpio -o --format newc | gzip > ./vexpress-initramfs
  • 利用busybox制作(繁琐,需移植openssh)
移植openssh失败

测试文件系统

经过上述步骤,已经有了可用的内核zImage和文件系统vexpress-initramfs。下面直接用qemu启动内核,并载入启动镜像,系统已可以正常运行:

qemu-system-arm -m 128M -M vexpress-a9 -kernel zImage  -initrd vexpress-initramfs -append "root=/dev/ram rdinit=/sbin/init console=ttyAMA0" -display none -serial stdio

配置网络

cd rootfs/
vi etc/network/interfaces

增加如下行:

auto eth0
iface eth0 inet static
address 192.168.3.10
netmask 255.255.255.0
gateway 192.168.3.1

这样arm的系统中就对网卡eth0指定了ip192.168.3.10,保存之后需要重新作成启动镜像:

find . | cpio -o --format newc | gzip > ./vexpress-initramfs

在本地主机上需要新增虚拟网卡tap0,用到的命令tunctl在包tunctl(Fedora19)中。

tunctl -t tap0 -u root
ifconfig tap0 192.168.3.1 up
route add -host 192.168.3.1 dev tap0
shell -c 'echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp'
arp -Ds 192.168.3.1 eth0 pub

这样tap0就已经启动,并且指定了ip为192.168.3.1。

测试网络

启动系统,并指定网络。ifname=tap0中的名字需要与主机上的虚拟网卡名称对应:

qemu-system-arm -M vexpress-a9 -kernel zImage -initrd vexpress-initramfs -m 128M -append "root=/dev/ram rdinit=/sbin/init console=ttyAMA0" -net nic,vlan=0 -net tap,vlan=0,ifname=tap0,downscript=no,script=no -display none -serial stdio

登录系统后查看IP并ping主机:

ifconfig
ping 192.168.3.1

正常情况下已经可以通过ssh登录到arm的系统中去了。

\- 完 -