目录
1. 环境介绍:
2. 下载Linux内核
3. 安装arm的交叉编译工具链
4.编译Linux内核
5. 下载qemu
6. 制作根文件系统
1. 根文件系统的内容
2. 根文件系统放在哪里
3. 下载、编译和安装busybox
7.使用qemu测试
8.下载、编译u-boot代码
9.u-boot使用qemu测试
10. 利用网络引导的方式启动Linux内核。具体方式如下:
1、启动Qemu的网络支持
2、配置u-boot
11. 使用设备树来启动内核
1、配置u-boot
2、配置内核
3、编译设备树
12. 实现NFS根文件系统的挂载。
1、保证Qemu的网络是可以用的。
2、配置u-boot的环境变量bootargs
3、配置kernel
4、启动
附加
1.错误
2.tftp服务器搭建
tftpd-hpa(服务器)安装:
配置:
使用:
tftp-hpa(客户端)安装:
测试:
3.nfs服务器搭建
1、NFS 介绍
2、安装 NFS 软件包
3、添加 NFS 共享目录
4、启动 NFS 服务
5、测试 NFS 服务器
1. 环境介绍:
Win10 64 + Vmware 14 + ubuntu16.04
u-boot 版本:u-boot--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:///pub/scm/linux/kernel/git/torvalds/linux.git
方法二:直接下载3.16源代码包
wget /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,下载地址:
/downloads/
配置:
在busybox下执行 make menuconfig
做如下配置:
Busybox Settings --->Build Options --->[*] Build BusyBox as a static binary (no shared libs)(arm-linux-gnueabi-) Cross Compiler prefix
然后执行
makemake install
安装完成后,会在busybox目录下生成_install目录,该目录下的程序就是单板运行所需要的命令。
形成根目录结构
先在Ubuntu主机环境下,形成目录结构,里面存放的文件和目录与单板上运行所需要的目录结构完全一样,然后再打包成镜像,这个临时的目录结构称为根目录.
我写了一个脚本来 mkrootfs.sh 完成这个任务:
#!/bin/bashsudo rm -rf rootfssudo rm -rf tmpfssudo rm -f a9rootfs.ext3sudo mkdir rootfssudo cp busybox/_install/* rootfs/ -rafsudo 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/ -arfsudo cp -arf /usr/arm-linux-gnueabi/lib rootfs/sudo rm rootfs/lib/*.asudo arm-linux-gnueabi-strip rootfs/lib/*sudo cp lib/* rootfs/lib -arfsudo mkdir -p rootfs/dev/sudo mknod rootfs/dev/tty1 c 4 1sudo mknod rootfs/dev/tty2 c 4 2sudo mknod rootfs/dev/tty3 c 4 3sudo mknod rootfs/dev/tty4 c 4 4sudo mknod rootfs/dev/console c 5 1sudo mknod rootfs/dev/null c 1 3sudo dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=32sudo mkfs.ext3 a9rootfs.ext3sudo chmod 777 a9rootfs.ext3sudo cp -r rootfs /opt/nfsboot #/opt/nfsboot 为nfs挂在目录sudo mkdir -p tmpfssudo mount -t ext3 a9rootfs.ext3 tmpfs/ -o loopsudo cp -r rootfs/* tmpfs/sudo umount tmpfs
其中,etc下是启动配置文件,可以的到这里下载:
/files/pengdonglin137/etc.tar.gz
7.使用qemu测试
#!/bin/bashqemu-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-.05, 解压后,配置,编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_ca9x4_defconfigmake 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 .07-rc3-00092-gf3edfd3-dirty (Dec 05 - 22:00:46 -0800)DRAM: 512 MiBWARNING: Caches not enabledFlash: 128 MiBMMC: MMC: 0*** Warning - bad CRC, using default environmentIn: serialOut: serialErr: serialNet: smc911x-0Warning: smc911x-0 using MAC address from net deviceHit 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-utilitiessudo apt-get install bridge-utils
输入如下命令查看 /dev/net/tun 文件:
ls -l /dev/net/tuncrw-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.hindex 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_ADDRCONFIG_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 -lhbrw-rw---- 1 0 0 179, 0 Dec 6 08:47 /dev/mmcblk0[root@vexpress ]# df -hFilesystemSizeUsed Available Use% Mounted on192.168.11.20:/nfs_rootfs/rootfs15.6G5.1G9.7G 34% /tmpfs 250.7M 0 250.7M 0% /tmptmpfs 250.7M 0 250.7M 0% /dev[root@vexpress ]# mount -t ext3 /dev/mmcblk0 /mnt/tmprandom: nonblocking pool is initializedkjournald starting. Commit interval 5 secondsEXT3-fs (mmcblk0): using internal journalEXT3-fs (mmcblk0): mounted filesystem with writeback data mode[root@vexpress ]# ls /mnt/tmp/bin etc linuxrcmnt root sys usrdev 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-hpaTFTP_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.1tftp> 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 /nfsrootsudo chmod -R 777 /nfsrootsudo 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
如果觉得《使用Qemu模拟vexpress-a9搭建模拟开发板》对你有帮助,请点赞、收藏,并留下你的观点哦!