使用Qemu模拟vexpress-a9搭建模拟开发板
目录1. 环境介绍:2. 下载Linux内核3. 安装arm的交叉编译工具链4.编译Linux内核5. 下载qemu6. 制作根文件系统1. 根文件系统的内容2. 根文件系统放在哪里3. 下载、编译和安装busybox7.使用qemu测试8.下载、编译u-boot代码9.u-boot使用qemu测试10. 利用网络引导的方式启动Linux内核。具...
目录
10. 利用网络引导的方式启动Linux内核。具体方式如下:
1. 环境介绍:
Win10 64 + Vmware 14 + ubuntu16.04
u-boot 版本:u-boot-2015-04
Linux kernel版本:linux-3.16.y
busybox版本:1_24_stable
交叉编译工具链:arm-linux-gnueabi-
qemu版本:stable-2.4
2. 下载Linux内核
下载内核有两种方法,一种是用git直接下载内核代码树,方便后面的内核开发。另一种是直接到内核社区下载对应版本的源码包。我采用第一种方法。
方法一:使用git
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
方法二:直接下载3.16源代码包
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.16.tar.xz
3. 安装arm的交叉编译工具链
想必做嵌入式开发的朋友,对交叉编译工具链不陌生。如果你订制一个交叉编译工具链,建议你使用crosstool-ng开源软件来构建。但在这里建议直接安装arm的交叉编译工具链:
sudo apt-get install gcc-arm-linux-gnueabi
4.编译Linux内核
生成vexpress开发板子的config文件:
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 vexpress_defconfig
然后执行如下命令:
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 menuconfig
将:
System Type --->
[ ] Enable the L2x0 outer cache controller
# 即, 把 Enable the L2x0 outer cache controller 取消, 否则Qemu会起不来, 暂时还不知道为什么。
Kernel Features -->
[*] Use the ARM EABI to compile the kernel
# 确保该选项被选择
编译:
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 zImage -j2
生成的内核镱像位于./out_vexpress_3_16/arch/arm/boot/zImage, 后续qemu启动时需要使用该镜像。
编译modules
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 modules
设置modules的存放位置
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 modules_install INSTALL_MOD_PATH=../app
错误的提示上面看是重复定义了return_address函数,这里做个笔记!
解决方案
当前要编译的内核文件夹下面:gedit arch/arm/include/asm/ftrace.h(P.S:如果不是ubuntu可以用vim)
源代码:extern inline void *return_address(unsigned int level)
修改为:static inline void *return_address(unsigned int level)
{
return NULL;
}
当前要编译的内核文件夹下面:gedit arch/arm/kernel/return_address.c
源代码:void *return_address(unsigned int level)(这里是第二个return_address,里面只有return NULL一行代码)
{
return NULL;
}
修改为:全部注释掉,或者删除掉
5. 下载qemu
sudo apt-get install qemu-systen-*
查看qemu支持哪些板子
qemu-system-arm -M help
6. 制作根文件系统
到这里是否大功告成了呢? 其实在上面的测试中,你会发现内核报panic,因为内核找不到根文件系统,无法启init进程。
根文件系统要考虑两个方面:
1. 根文件系统的内容
如果你看过《Linux From Scratch》,相信你会对这一步产生恐惧感,但如果一直从事嵌入式开发,就可以放下心来。根文件系统就是简单得不能再简单的几个命令集和态动态而已。为什么Linux From Scratch会有那么复杂,是因为它要制作出一个Linux发生版。但在嵌入式领域,几乎所有的东西,都是mini版本,根文件系统也不例外。
本文制本的根文件系统 = busybox(包含基础的Linux命令) + 运行库 + 几个字符设备
2. 根文件系统放在哪里
其实依赖于每个开发板支持的存储设备,可以放到Flash上,也可以放到SD卡,甚至外部磁盘上。最关键的一点是你要清楚知道开发板有什么存储设备。
3. 下载、编译和安装busybox
我用的busybox版本是1_24,下载地址:
https://busybox.net/downloads/
配置:
在busybox下执行 make menuconfig
做如下配置:
Busybox Settings --->
Build Options --->
[*] Build BusyBox as a static binary (no shared libs)
(arm-linux-gnueabi-) Cross Compiler prefix
然后执行
make
make install
安装完成后,会在busybox目录下生成_install目录,该目录下的程序就是单板运行所需要的命令。
形成根目录结构
先在Ubuntu主机环境下,形成目录结构,里面存放的文件和目录与单板上运行所需要的目录结构完全一样,然后再打包成镜像,这个临时的目录结构称为根目录.
我写了一个脚本来 mkrootfs.sh 完成这个任务:
#!/bin/bash
sudo rm -rf rootfs
sudo rm -rf tmpfs
sudo rm -f a9rootfs.ext3
sudo mkdir rootfs
sudo cp busybox/_install/* rootfs/ -raf
sudo mkdir -p rootfs/proc/
sudo mkdir -p rootfs/sys/
sudo mkdir -p rootfs/tmp/
sudo mkdir -p rootfs/root/
sudo mkdir -p rootfs/var/
sudo mkdir -p rootfs/mnt/
sudo cp etc rootfs/ -arf
sudo cp -arf /usr/arm-linux-gnueabi/lib rootfs/
sudo rm rootfs/lib/*.a
sudo arm-linux-gnueabi-strip rootfs/lib/*
sudo cp lib/* rootfs/lib -arf
sudo mkdir -p rootfs/dev/
sudo mknod rootfs/dev/tty1 c 4 1
sudo mknod rootfs/dev/tty2 c 4 2
sudo mknod rootfs/dev/tty3 c 4 3
sudo mknod rootfs/dev/tty4 c 4 4
sudo mknod rootfs/dev/console c 5 1
sudo mknod rootfs/dev/null c 1 3
sudo dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=32
sudo mkfs.ext3 a9rootfs.ext3
sudo chmod 777 a9rootfs.ext3
sudo cp -r rootfs /opt/nfsboot #/opt/nfsboot 为nfs挂在目录
sudo mkdir -p tmpfs
sudo mount -t ext3 a9rootfs.ext3 tmpfs/ -o loop
sudo cp -r rootfs/* tmpfs/
sudo umount tmpfs
其中,etc下是启动配置文件,可以的到这里下载:
http://files.cnblogs.com/files/pengdonglin137/etc.tar.gz
7.使用qemu测试
#!/bin/bash
qemu-system-arm \
-M vexpress-a9 \
-serial stdio \
-m 512M \
-kernel ../linux-3.16/out_vexpress_3_16/arch/arm/boot/zImage \
-append "init=/linuxrc root=/dev/mmcblk0 rw rootwait earlyprintk console=ttyAMA0 console=tty0" \
-sd ./a9rootfs.ext3
8.下载、编译u-boot代码
u-boot从下面的网址获得:
http://ftp.denx.de/pub/u-boot/
取得是最新的代码。我使用的是u-boot-2015.05, 解压后,配置,编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_ca9x4_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
9.u-boot使用qemu测试
qemu-system-arm -M vexpress-a9 \
-kernel u-boot \
-nographic \
-m 512M
打印出u-boot的启动信息:
复制代码
U-Boot 2015.07-rc3-00092-gf3edfd3-dirty (Dec 05 2015 - 22:00:46 -0800)
DRAM: 512 MiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC: MMC: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: smc911x-0
Warning: smc911x-0 using MAC address from net device
Hit any key to stop autoboot: 0
10. 利用网络引导的方式启动Linux内核。具体方式如下:
开启Qemu的网络支持功能,启动u-boot,设置u-boot的环境变量,u-boot采用tftp的方式将uImage格式的Linux内核下载到内存地址0x60003000处,为什么是0x60000000起始的地址,参考文件u-boot的配置文件 include/configs/vexpress_common.h。如果用Qemu直接启动Kernel,是通过-append parameter 的方式给kernel传参的,现在是通过u-boot,那么需要通过u-boot的环境变量bootargs,可以设置为如下值 setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0 console=tty0'。 然后设置u-boot环境变量bootcmd,如下: setenv bootcmd 'tftp 0x60003000 uImage; bootm 0x60003000'.
具体步骤
1、启动Qemu的网络支持
qemu 支持多种网络链接方式,其中最常用的就是桥接(bridge)。 这需要依赖内核的 tun/tap 模块的支持。
输入如下命令安装必要的工具包:
sudo apt-get install uml-utilities
sudo apt-get install bridge-utils
输入如下命令查看 /dev/net/tun 文件:
ls -l /dev/net/tun
crw-rw-rwT 1 root root 10, 200 Apr 15 02:23 /dev/net/tun
如果该文件存在,这表明内核已经支持开启了 tun 支持,在 ubuntu-16.04 中,这个功能默认已经开启。
如果该文件不存在,则需要加载 tun 模块,并创建 /dev/net/tun 文件。
安装完成后,执行
sudo tunctl -u root -t tap30
#就可以在主机上创建一个网络设备,这是使用 ifconfig -a 命令可以看到名字为tap30的网络设备。
ifconfig tap30 192.168.2.62 promisc up
#配置网卡IP地址,并且以混杂模式启用。
注:此配置主机重启后续重新配置。
主机的网络配置已经完成,接下来开始配置虚拟机,QEMU通过 -net 参数指定网络配置
有三种选项
-net nic 必须有的基本配置,macaddr 设置mac地址,model是网卡的类型,可以model=?查看有哪些类型
-net tap 使用桥接模式的,需要指定启动脚本 script=和关闭脚本 downscript,fd是指向已经有的tap设备,name是在monitor模式使用info network看到的名字,ifname是tap设备在主机中的名字
-net user 用户模式,qemu使用Slirp实现了一整套tcp/ip协议栈
一般nic必须有,tap和user选一个使用
在启动qemu的脚本中添加两行参数:
-net nic,vlan=0 \
-net tap,vlan=0,ifname=tap30,script=no,downscript=no \
进入虚拟系统后,ifconfig eth0 192.168.2.5 up 配置虚拟系统IP。
2、配置u-boot
主要是修改include/configs/vexpress_common.h
复制代码
diff --git a/include/configs/vexpress_common.h b/include/configs/vexpress_common.h
index 0c1da01..9fa7d9e 100644
--- a/include/configs/vexpress_common.h
+++ b/include/configs/vexpress_common.h
@@ -48,6 +48,11 @@
#define CONFIG_SYS_TEXT_BASE 0x80800000
#endif
+/* netmask */
+#define CONFIG_IPADDR 192.168.2.5
+#define CONFIG_NETMASK 255.255.255.0
+#define CONFIG_SERVERIP 192.168.2.62
+
/*
* Physical addresses, offset from V2M_PA_CS0-3
*/
@@ -202,7 +207,9 @@
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_GBL_DATA_OFFSET
/* Basic environment settings */
-#define CONFIG_BOOTCOMMAND "run bootflash;"
+/* #define CONFIG_BOOTCOMMAND "run bootflash;" */
+#define CONFIG_BOOTCOMMAND "run bootflash; setenv ipaddr \
192.168.2.5; setenv serverip 192.168.2.62; tftp 0x60003000 uImage; tftp 0x60500000 dtb; \
setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000 - 0x60500000;"
11. 使用设备树来启动内核
步骤
1、配置u-boot
vexpress-a9的u-boot默认已经支持设备树了。
2、配置内核
vexpress-a9的kernel默认也已经支持了。
3、编译设备树
在内核源码根目录下执行如下命令:
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 dtbs
然后会在out_vexpress_3_16/arch/arm/boot/dts/下生产如下几个文件
vexpress-v2p-ca15_a7.dtb vexpress-v2p-ca15-tc1.dtb vexpress-v2p-ca5s.dtb vexpress-v2p-ca9.dtb
这里我们用vexpress-v2p-ca9.dtb,然后将其拷贝到/tftpboot下面
cp out_vexpress_3_16/arch/arm/boot/dts/vexpress-v2p-ca9.dtb /tftpboot/dtb
12. 实现NFS根文件系统的挂载。
具体步骤如下。
步骤
1、保证Qemu的网络是可以用的。
进入u-boot交互界面,ping 102.168.2.62,出现 is alive 即网络可用
2、配置u-boot的环境变量bootargs
setenv bootargs 'root=/dev/nfs rw nfsroot=192.168.2.62:/rootfs init=/linuxrc console=ttyAMA0 ip=192.168.2.5'
3、配置kernel
配置内核,使其支持nfs挂载根文件系统
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16/ menuconfig
配置:
File systems --->
[*] Network File Systems --->
<*> NFS client support
<*> NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
[*] Root file system on NFS
然后重新编译内核
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 LOADADDR=0x60003000 uImage -j8
将生成的uImage拷贝到/tftpboot下
4、启动
复制代码
qemu-system-arm -M vexpress-a9 \
-kernel u-boot \
-nographic \
-m 512M \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0
注:这里的-sd参数此时可以不用设置。
此时我们由于指定了-sd参数,所以我们还可以访问原来的根文件系统,方法如下:
复制代码
[root@vexpress ]# ls /dev/mmcblk0 -lh
brw-rw---- 1 0 0 179, 0 Dec 6 08:47 /dev/mmcblk0
[root@vexpress ]# df -h
Filesystem Size Used Available Use% Mounted on
192.168.11.20:/nfs_rootfs/rootfs
15.6G 5.1G 9.7G 34% /
tmpfs 250.7M 0 250.7M 0% /tmp
tmpfs 250.7M 0 250.7M 0% /dev
[root@vexpress ]# mount -t ext3 /dev/mmcblk0 /mnt/tmp
random: nonblocking pool is initialized
kjournald starting. Commit interval 5 seconds
EXT3-fs (mmcblk0): using internal journal
EXT3-fs (mmcblk0): mounted filesystem with writeback data mode
[root@vexpress ]# ls /mnt/tmp/
bin etc linuxrc mnt root sys usr
dev lib lost+found proc sbin tmp var
[root@vexpress ]#
附加
1.错误
kernel/Makefile:971: recipe for target 'prepare3' failed
...
ninja.mk:148: recipe for target 'ninja_wrapper' failed
结论:
make mrproper 再进行编译,问题解决,原因是srctree不干净了
2.tftp服务器搭建
tftp是client客户端,tftpd是server服务器端,d应该指的是daemon。如果你要从别人的tftp服务器端上传/下载东西,就要用到tftp;如果你为别人提供tftp服务,供别人上传/下载东西,那就要安装tftpd服务程序。
ubuntu中常用的tftp服务器和客户端是tftpd-hpa和tftp-hpa
tftpd-hpa(服务器)安装:
sudo apt-get install tftpd-hpa
配置:
sudo vim /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot" //指定将来下位机的下载目录为上位机的/tftpboot,此目录随意指定即可
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"
修改完毕,保存退出
sudo mkdir /tftpboot //创建tftpd-hpa网络服务的下载目录
修改下载目录的权限
sudo chmod 777 /tftpboot
使用:
重新启动tftpd-hpa网络服务:sudo service tftpd-hpa restart
tftp-hpa(客户端)安装:
sudo apt-get install tftp-hpa
测试:
随便找个目录,只要不是/tftpboot就行
tftp 127.0.0.1
tftp> get xxx //下载(下载成功后没有提示,并且在当前目录下会出现xxx文件)
3.nfs服务器搭建
1、NFS 介绍
NFS 即网络文件系统(Network File-System),可以通过网络让不同机器、不同系统之间可以实现文件共享。通过 NFS,可以访问远程共享目录,就像访问本地磁盘一样。NFS 只是一种文件系统,本身并没有传输功能,是基于 RPC(远程过程调用)协议实现的,采用 C/S 架构。
2、安装 NFS 软件包
sudo apt-get install nfs-kernel-server # 安装 NFS服务器端
sudo apt-get install nfs-common # 安装 NFS客户端
3、添加 NFS 共享目录
sudo vim /etc/exports
若需要把 “/nfsroot” 目录设置为 NFS 共享目录,请在该文件末尾添加下面的一行:
/nfsroot *(rw,sync,no_root_squash) # * 表示允许任何网段 IP 的系统访问该 NFS 目录
在这里插入图片描述
新建“/nfsroot”目录,并为该目录设置最宽松的权限:
sudo mkdir /nfsroot
sudo chmod -R 777 /nfsroot
sudo chown ipual:ipual /nfsroot/ -R # ipual 为当前用户,-R 表示递归更改该目录下所有文件
4、启动 NFS 服务
sudo /etc/init.d/nfs-kernel-server start 或者
sudo /etc/init.d/nfs-kernel-server restart 或者
sudo service nfs-kernel-server restart
在 NFS 服务已经启动的情况下,如果修改了 “/etc/exports” 文件,需要重启 NFS 服务,以刷新 NFS 的共享目录。
5、测试 NFS 服务器
sudo mount -t nfs 192.168.12.123:/nfsroot /mnt -o nolock
192.168.12.123 为主机 ip,/nfsroot 为主机共享目录,/mnt 为设备挂载目录,如果指令运行没有出错,则 NFS 挂载成功,在主机的 /mnt 目录下应该可以看到 /nfsroot 目录下的内容(可先在 nfsroot 目录下新建测试目录),如需卸载使用
umount /mnt
更多推荐
所有评论(0)