参考文章
https://www.cnblogs.com/pengdonglin137/p/5023342.html
https://blog.csdn.net/sxw1002/article/details/52841671
https://wiki.ubuntu.com/Kernel/Dev/QemuARMVexpress
https://translatedcode.wordpress.com/2016/11/03/installing-debian-on-qemus-32-bit-arm-virt-board/
https://gmplib.org/~tege/qemu.html
1、编译linux内核
到 https://mirrors.edge.kernel.org/pub/linux/kernel/v3.x/ 下载合适的内核源码。我用的是linux-3.18.24
除了arm-hisiv400-linux的工具链,编译内核还需要安装bc、ncurses-devel(在make menuconfig时用到)
yum install bc ncurses-devel
然后就可以开始编译了
make CROSS_COMPILE=arm-hisiv400-linux- ARCH=arm O=./_out vexpress_defconfig
make CROSS_COMPILE=arm-hisiv400-linux- ARCH=arm O=./_out menuconfig
可以选上,否则对ext4不能支持
[*] Enable the block layer --->
[*] Support for large (2TB+) block devices and files
make CROSS_COMPILE=arm-hisiv400-linux- ARCH=arm O=./_out zImage -j4
2、安装qemu
偷个懒,直接用yum装。CentOS7在epel里面有
yum install qemu-system-arm
列出qemu-system-arm可以支持的机型
qemu-system-arm -machine help
3、试运行内核
cd _out/arch/arm/boot
qemu-system-arm -M virt -m 512M -kernel zImage -nographic
如果能走到
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
这一步,说明内核可以成功运行了
PS:其他参考文章,一般提到qemu-system-arm要模拟vexpress-a9这个型号。但是这个型号只有sd卡一个存储,不太方便进行定制。用virt虚拟型号可定制性更强。用virt型号的时候,不用指定tty
参考文章1提到的找console tty的方法有些不对及不完善。首先,生成的.config文件位于O=指定的输出_out目录下。其次.config文件中相关的配置项是
CONFIG_CMDLINE="console=ttyAMA0"
因此,应该以console=来查找,而不是按CONFIG_CONSOLE来查找。后来我曾经尝试编译内核的时候改成hisi_defconfig来取代vexpress,结果.config中CONFIG_CMDLINE是空的,qemu-system-arm启动后看不到输出了
4、编译busybox
wget http://www.busybox.net/downloads/busybox-1.25.1.tar.bz2
tar xjf busybox-1.25.1.tar.bz2
cd busybox-1.25.1
export ARCH=arm
export CROSS_COMPILE=arm-hisiv400-linux-
make menuconfig
在 Busybox Settings ---> Build Options 中注意选中
[*]Build BusyBox as a static binary (no shared libs)
make -j4
make install
编译后生成的文件在busybox的_install目录下
5、制作根文件系统
mkdir rootfs
cp -r busybox-1.25.1/_install/* rootfs/
busybox只是让这个根文件系统有了最基本的命令。linux中还需要添加一些必要的目录和文件
mkdir -p rootfs/dev/ rootfs/lib/ rootfs/proc/ rootfs/tmp/ rootfs/var/ rootfs/sys/
mknod rootfs/dev/tty1 c 4 1
mknod rootfs/dev/tty2 c 4 2
mknod rootfs/dev/tty3 c 4 3
mknod rootfs/dev/tty4 c 4 4
mknod rootfs/dev/urandom c 1 9
mknod rootfs/dev/null c 1 3
cd rootfs
wget http://files.cnblogs.com/files/pengdonglin137/etc.tar.gz
tar xzf etc.tar.gz
rm etc.tar.gz -rf
cp /opt/hisi-linux/x86-arm/arm-hisiv400-linux/target/lib/*.so* rootfs/lib/ -d
etc目录下需要放一些系统初始化的必要脚本,待会再细讲。这里先用别人现成的
将rootfs目录下的内容,制作成镜像。回退到rootfs的父级目录
yum install qemu-img
qemu-img create -f raw rootfs.img 1G
mkfs.ext3 -F rootfs.img
mkdir tmpfs
mount -t ext3 rootfs.img tmpfs/
cp -r rootfs/* tmpfs/
umount tmpfs/
6、尝试启动
qemu-system-arm -M virt -m 512M -kernel linux-3.18.24/_out/arch/arm/boot/zImage -nographic -drive if=none,file=rootfs.img,format=raw,id=hd -device virtio-blk-device,drive=hd -append "root=/dev/vda rw console=ttyAMA0"
这组参数也是试了很久才试验出来的。加了硬盘之后,需要append console才能有启动日志输出。而且要指定root路径。由于还不能敲命令行,硬盘挂载在/dev/下面的什么也要靠猜。
想退出qemu,先按Ctrl+D退出console,然后再按Ctrl+a,松手再按x,结束qemu
参考网上其他文章,将设备型号模拟成vexpress-a9也是可以的,不过文件系统要挂载在sd卡上面,不是硬盘上面。模拟成vexpress-a15无法启动,不知道为什么。
qemu-system-arm -M vexpress-a9 -m 512M -kernel linux-3.18.24/_out/arch/arm/boot/zImage -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd rootfs.img
7、添加网络支持
网络的各种文章,都没有把qemu网络该怎么设置,说得很清楚。说得比较清楚的是
https://www.linux-kvm.org/page/Networking
qmeu的网络分为user-mode和tap两种。user-mode只能让虚拟机访问外网,但外网不能访问虚拟机。如果要让外面能访问虚拟机,就必须要使用tap。
要使用tap,必须要在宿主机上面创建一个bridge,这点和kvm使用网桥是一样的
https://www.jianshu.com/p/eb7d8bd7e477
然后添加一个/etc/qemu-ifup的文件
#!/bin/sh
set -x
switch=br0
if [ -n "$1" ];then
#tunctl -u `whoami` -t $1
ip tuntap add $1 mode tap user `whoami`
ip link set $1 up
sleep 0.5s
#brctl addif $switch $1
ip link set $1 master $switch
exit 0
else
echo "Error: no interface specified"
exit 1
fi
qemu-ifup文件需要赋予执行权限。注意switch变量要设置为宿主机上面的网桥名字
然后可以往虚拟机中添加网卡了
qemu-system-arm -M virt -m 512M -kernel linux-3.18.24/_out/arch/arm/boot/zImage -nographic -drive if=none,file=rootfs.img,format=raw,id=hd -device virtio-blk-device,drive=hd -append "root=/dev/vda rw console=ttyAMA0" -device virtio-net-device,netdev=network0 -netdev tap,id=network0,ifname=tap0
或者用vexpress-a9也可以
qemu-system-arm -M vexpress-a9 -m 512M -kernel linux-3.18.24/_out/arch/arm/boot/zImage -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd rootfs.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0
在虚拟机中用ip link命令可以看到lo和eth0两个网卡了。不过要等网络通起来,还需要一些配置
ifconfig eth0 192.168.1.33 netmask 255.255.255.0 broadcast 192.168.1.255 up
这样,宿主机和虚拟机之间就可以通信起来了。我们可以把设置ip地址等初始化工作放到/etc/init.d/rcS脚本里面。不过现在的网络功能还是有缺陷的,域名解析的工作还不正常
参考
http://blog.sina.com.cn/s/blog_6de4c6c30100tiw7.html
https://blog.csdn.net/prog_6103/article/details/78569510
首先,即时busybox是静态链接编译的,系统中/lib目录下还是需要有libnss_dns.so.2、libresolv.so.2这些库,否则域名解析无法工作。这些库可以从海思的gcc里面找到、
其次,根文件系统中还没有/etc/resolv.conf,没有配置dns服务器
DNS配置好了之后,在虚拟机上面依然无法解析成功域名。在宿主机上面通过tcpdump抓包,发现dns请求是发出了,但是宿主机会回复一条ICMP命令,Destination Unreachable (Host administratively prohibited)。这里主要是宿主机启用了iptables,复杂的FORWARD规则拦截了。最简单的解决方法是在iptables插入一条
iptables -I FORWARD -i br0 -j ACCEPT
让所有br0进来的数据都允许转发
8、编译dropbear
为了方便往虚拟开发板上面传文件,远程控制,需要在虚拟开发板上面加上dropbear,方便用ssh远程登录及传输文件
mkdir dropbear
cd dropbear
wget http://zlib.net/zlib-1.2.11.tar.gz
tar xzf zlib-1.2.11.tar.gz
cd zlib-1.2.11
./configure --prefix=/home/kernel/dropbear/lib/zlib --static
修改Makefile
CC=gcc 改为 CC=arm-hisiv400-linux-gcc
LDSHARED=gcc 改为 LDSHARED=arm-hisiv400-linux-gcc
CPP=gcc -E 改为 CPP=arm-hisiv400-linux-cpp -E
make -j4
make install
wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2017.75.tar.bz2
tar xjf dropbear-2017.75.tar.bz2
cd dropbear-2017.75
./configure --with-zlib=/home/kernel/dropbear/lib/zlib --host=arm-hisiv400-linux
make -j4
编译出dropbear后,把它拷贝到rootfs的/sbin目录下。然而,直接运行dropbear,会发现进程还是启动不起来。使用dropbear -E启动,可以看到报错信息是因为缺少了秘钥文件。回到宿主机上面,进入把dropbearkey也拷贝到rootfs/sbin目录下,另外根文件系统也要确保有/dev/urandom这个设备,否则dropbearkey无法运行。进入虚拟机
mkdir -p /etc/dropbear
cd /etc/dropbear/
dropbearkey -t rsa -s 4096 -f dropbear_rsa_host_key
记得从虚拟机中把/etc/dropbear/dropbear_rsa_host_key备份
这时候,使用dropbear -E是可以启动的,但是使用dropbear不带任何参数是启动失败的。把syslog打印出来,发现报错信息为Early exit: Failed to daemonize: No such file or directory。这是一个相当奇葩的问题,居然在调用daemon函数的时候出现了ENOENT的errno。谷歌找到的答案是
https://www.linuxquestions.org/questions/linux-networking-3/sshd-fatal-daemon-failed-no-such-device-279664/
mknod /dev/null c 1 3
9、其余优化
虚拟多核心的arm cpu,qemu-system-arm启动时加上-smp 4,虚拟四核。不过CentOS 7 epel带的qemu 2.0.0还不支持虚拟多核心,需要自己编译更新的qemu版本
上面创建的根文件系统镜像rootfs.img,采用的是raw格式,而且容量只有1G。如果希望虚拟更大的硬盘,则建议用qcow2格式
qemu-img create -f qcow2 rootfs.img 300G
附1:虚拟机根文件中的/etc/init.d/rcS文件参考
#!/bin/sh
# Mount fs accroding to /etc/fstab
mount -a
# Network
ipaddr=192.168.1.33
netmask=255.255.255.0
gateway=192.168.1.1
ifconfig lo 127.0.0.1 up
ifconfig eth0 $ipaddr \
netmask $netmask up
route add default gw $gateway
dropbear
/etc/fstab 文件参考
#device mount-point type options dump fsck order
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
#/dev目录在qemu下不能设置为tmpfs,否则会覆盖了mknod已经创建好的tty1-tty4
#dev /dev tmpfs defaults 0 0
var /var tmpfs defaults 0 0
tmp /tmp tmpfs defaults 0 0
附2:交叉编译strace
wget https://strace.io/files/5.7/strace-5.7.tar.xz
tar xJf strace-5.7.tar.xz
cd strace-5.7
./configure --host=arm-hisiv400-linux
make -j4
arm-hisiv400-linux-strip strace
附3:查看syslog的方法
首先要手动启动syslogd
其次要手动创建好/var/log/目录
附4:编译更新版本的qemu
wget https://download.qemu.org/qemu-4.0.1.tar.xz
tar xJf qemu-4.0.1.tar.xz
cd qemu-4.0.1
./configure --target-list=arm-softmmu,aarch64-softmmu --audio-drv-list=
make -j4
make install