Qemu - 挂载网络根文件系统
使用Qemu仿真开发板,挂在网络内核和根文件系统。
- 平台:ubuntu 16.04
- 对象:Qemu仿真ARM32.
- 文件:linux-4.4.300.tar.xz、busybox-1.27.1.tar.bz2、u-boot-2017.05.tar.bz2
1.安装依赖
$ sudo apt install libc6-dev bison flex bc gawk texinfo git unzip build-essential vim tree curl wget ssh libncurses5-dev diffutils
$ sudo apt install u-boot-tools
$ sudo apt install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
$ sudo apt install qemu-system-arm
我们查看qemu支持的开发板
$ ./qemu-system-arm -M help
2.下载资源
2.1 kernel
或
https://mirrors.ustc.edu.cn/kernel.org/linux/kernel/
2.2 busybox
https://busybox.net/downloads/
2.3 u-boot
https://ftp.denx.de/pub/u-boot/
3.编译内核
3.1 解压文件
$ tar -xvf linux-4.4.300.tar.xz
$ cd linux-4.4.300
3.2 修改Makefile
@@ -254,8 +254,10 @@ SUBARCH := $(shell uname -m | sed -e s/i
# "make" in the configured kernel build directory always uses that.
# Default value for CROSS_COMPILE is not to prefix executables
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
-ARCH ?= $(SUBARCH)
-CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
+# ARCH ?= $(SUBARCH)
+# CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
+ARCH ?= arm
+CROSS_COMPILE ?= arm-linux-gnueabi-
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
3.3 编译
$ make vexpress_defconfig
$ make -j4
$ make LOADADDR=0x60003000 uImage
4.制作根文件系统
4.1 创建rootfs文件夹
$ mkdir rootfs
4.2 解压busybox
$ tar -xvf busybox-1.27.1.tar.bz2
$ cd busybox-1.27.1
4.3 修改Makefile
@@ -161,7 +161,8 @@ export srctree objtree VPATH TOPDIR
# Default value for CROSS_COMPILE is not to prefix executables
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
-CROSS_COMPILE ?=
+# CROSS_COMPILE ?=
+CROSS_COMPILE ?= arm-linux-gnueabi-
# bbox: we may have CONFIG_CROSS_COMPILER_PREFIX in .config,
# and it has not been included yet... thus using an awkward syntax.
ifeq ($(CROSS_COMPILE),)
@@ -187,7 +188,8 @@ SUBARCH := $(shell echo $(SUBARCH) | sed
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
-ARCH ?= $(SUBARCH)
+# ARCH ?= $(SUBARCH)
+ARCH ?= arm
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
4.4 编译busybox
$ make defconfig
$ make menuconfig
做如下修改:
// 勾选编译静态库
Busybox Settings --->
[*] Build static binary (no shared libs)
编译
$ make -j4
$ make install
4.5 创建根文件系统
$ cp -rf busybox-1.27.1/_install/* ./rootfs
$ cd ./rootfs/
$ mkdir lib proc tmp dev home etc sys opt mnt
$ mkdir -p etc/init.d
4.6 安装modules
$ cd linux-4.4.300
$ make modules_install INSTALL_MOD_PATH=../rootfs
4.7 添加rcS
$ cd rootfs/etc/init.d
$ touch rcS
$ sudo chmod a+x rcS
$ vim rcS
添加如下内容:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
# 挂载fstab文件中所有指定的文件系统
/bin/mount -a
echo /sbin/mdev>/proc/sys/kernel/hotplug
# 在/dev目录下建立必须的设备节点
mdev -s
# 设置主机的名字
/bin/hostname -F /etc/sysconfig/HOSTNAME
4.8 添加inittab
rootfs/etc/inittab
添加如下内容:
# 设置内核的热插拔,有mdev接收来自内核的消息并做出响应
::sysinit:/etc/init.d/rcS
# 在串口启动一个登录会话
::askfirst:-/bin/sh
# 作为init重启执行程序
::ctrlaltdel:/sbin/reboot
::restart:/sbin/init
# 告诉init在关机时运行umount命令卸载所有文件系统,如果卸载失败,以只读方式重新挂载
::showdown:/bin/mount
4.9 添加fstab
rootfs/etc/fstab
添加如下内容(注意间隔符为Tab):
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
4.10 添加profile
rootfs/etc/profile
添加如下内容:
#!/bin/sh
USER="id -un"
LOGNAME=$USER
PS1='[root@linux]#'
PATH=$PATH
HOSTNAME='/bin/hostname'
export USER LOGNAME PS1 PATH
4.11 复制动态库
之前有安装gcc-arm-linux-gnueabi,我们把它的库复制到根文件系统。
$ sudo cp -rf /usr/arm-linux-gnueabi/lib/* ./rootfs/lib/
4.12 创建设备节点
$ cd rootfs/dev/
$ sudo mknod -m 664 tty1 c 4 1
$ sudo mknod -m 664 tty2 c 4 2
$ sudo mknod -m 664 tty3 c 4 3
$ sudo mknod -m 664 tty4 c 4 4
$ sudo mknod -m 664 console c 5 1
$ sudo mknod -m 664 null c 1 3
4.13 打包文件系统
$ dd if=/dev/zero of=rootfs.ext4 bs=1M count=32
$ mkfs.ext4 rootfs.ext4
$ sudo mount rootfs.ext4 /mnt/ -o loop
$ sudo cp -rf rootfs/* /mnt/
$ sudo umount /mnt/
5. 测试系统
编写启动脚本:
$ touch boot.sh
$ chmod a+x boot.sh
修改为如下内容:
#!/bin/sh
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel linux-4.4.300/arch/arm/boot/zImage \
-dtb linux-4.4.300/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-nographic \
-append "root=/dev/mmcblk0 rw console=ttyAMA0" \
-sd rootfs.ext4
执行,如果上面步骤顺利,执行此脚本就可以正常进入系统了。
6.编译bootloader
$ tar -xvf u-boot-2017.05.tar.bz2
6.1 修改Makefile
@@ -246,6 +246,8 @@ ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
+CROSS_COMPILE ?= arm-linux-gnueabi-
+
KCONFIG_CONFIG ?= .config
export KCONFIG_CONFIG
6.2 修改config.mk
@@ -22,7 +22,8 @@ OBJCOPYFLAGS :=
VENDOR :=
#########################################################################
-ARCH := $(CONFIG_SYS_ARCH:"%"=%)
+# ARCH := $(CONFIG_SYS_ARCH:"%"=%)
+ARCH := arm
CPU := $(CONFIG_SYS_CPU:"%"=%)
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_TEGRA
6.3 修改vexpress_common.h
u-boot-2017.05/include/configs/vexpress_common.h
做如下修改(注意IP要改为实际值):
@@ -183,9 +183,21 @@
#include <config_distro_defaults.h>
/* Basic environment settings */
+/*
#define CONFIG_BOOTCOMMAND \
"run distro_bootcmd; " \
"run bootflash; "
+*/
+
+#define CONFIG_BOOTCOMMAND \
+ "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; \
+ setenv bootargs 'root=/dev/mmcblk0 rw console=ttyAMA0';\
+ bootm 0x60003000 - 0x60500000; "
+
+#define CONFIG_IPADDR 192.168.103.100
+#define CONFIG_NETMASK 255.255.255.0
+#define CONFIG_SERVERIP 192.168.103.240
+
#define BOOT_TARGET_DEVICES(func) \
func(MMC, mmc, 1) \
6.4 配置defconfig
$ make vexpress_ca9x4_defconfig
6.5 编译
$ make -j4
7. 网络配置
7.1 配置tftp
1.安装工具
$ sudo apt install tftp-hpa tftpd-hpa xinetd
2.修改配置文件(Host)
/etc/default/tftpd-hpa
添加如下内容(注意第二行路径改为实际值):
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/home/qemulinux/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"
3.创建tftp目录
$ cd /home/qemulinux/
$ mkdir tftpboot
$ chmod 777 tftpboot
4.重启tftp服务
$ /etc/init.d/tftpd-hpa restart
5.复制内核和设备树
$ cp linux-4.4.300/arch/arm/boot/uImage ./tftpboot/
$ cp linux-4.4.300/arch/arm/boot/dts/vexpress-v2p-ca9.dtb ./tftpboot/
7.2 配置虚拟桥接网口
- 1.安装工具
# 虚拟网桥工具
$ sudo apt install bridge-utils
# UML(user-mode linux)工具
$ sudo apt install uml-utilities
- 2.修改interfaces
/etc/network/interfaces
添加如下内容(根据实际网卡名自行修改,ifconfig可查看,这里是enp0s3):
auto enp0s3
auto br0
iface br0 inet dhcp
bridge_ports enp0s3
重启计算机,启动后输入:
$ ifconfig
注意:如果产生br0,并且有ip,即可跳过本小结的后面的”3.配置网络”一步。否则,则继续执行。
- 3.配置网络
# 关闭enp0s3, enp0s3是我主机的无线网口,根据你实际网口修改
$ sudo ifconfig enp0s3 down
# 增加一个虚拟网桥br0
$ sudo brctl addbr br0
# 在br0中添加一个接口enp0s3
$ sudo brctl addif br0 enp0s3
# 只有一个网桥,所以关闭生成树协议
$ sudo brctl stp br0 off
# 设置br0的转发延迟
$ sudo brctl setfd br0 1
# 设置br0的hello时间
$ sudo brctl sethello br0 1
# 打开br0接口,promisc混杂模式
$ sudo ifconfig br0 0.0.0.0 promisc up
# 打开enp0s3接口
$ sudo ifconfig enp0s3 0.0.0.0 promisc up
# 从dhcp服务器获得IP地址
$ sudo dhclient br0
# 配置TAP设备
# 创建一个tap0接口,只允许'whoami'(换成实际用户名)访问
$ sudo tunctl -t tap0 -u 'whoami'
# 在虚拟网桥中增加一个tap0接口
$ sudo brctl addif br0 tap0
# 打开tap0接口
$ sudo ifconfig tap0 0.0.0.0 promisc up
7.3 启动测试
$ vim boot.sh
添加如下内容:
#!/bin/sh
qemu-system-arm \
-M vexpress-a9 \
-kernel u-boot-2017.05/u-boot \
-nographic \
-m 512M \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
-sd rootfs.ext4
如果一切顺利,此时运行脚本就可以正常使用了。
效果是通过tftp挂在内核和设备树。
8. 配置nfs
- 1.安装工具
$ sudo apt install portmap nfs-kernel-server nfs-common
- 2.修改exports文件(host)
/etc/exports
添加如下内容(路径改为实际值):
/home/qemulinux/filesystem *(rw,async,no_root_squash,no_subtree_check)
- 3.创建nfs文件夹
$ mkdir filesystem
$ chmod 777 filesystem
- 4.复制根文件系统
$ sudo cp -rf ./rootfs/* ./filesystem/
- 5.重启NFS服务
$ sudo exportfs -a
$ sudo /etc/init.d/nfs-kernel-server restart
- 6.测试nfs服务
# 替换为真实IP
$ showmount -e 192.168.xxx.xxx
9. 修改vexpress_common.h
u-boot-2017.05/include/configs/vexpress_common.h
做如下修改(注意,代码中的IP,路径请改为实际值):
@@ -183,9 +183,20 @@
#include <config_distro_defaults.h>
/* Basic environment settings */
+/*
#define CONFIG_BOOTCOMMAND \
"run distro_bootcmd; " \
"run bootflash; "
+*/
+
+#define CONFIG_BOOTCOMMAND \
+ "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; \
+ setenv bootargs 'root=/dev/nfs nfsroot=192.168.103.240:/home/qemulinux/filesystem rw ip=192.168.103.100 init=/linuxrc console=ttyAMA0';\
+ bootm 0x60003000 - 0x60500000; "
+
+#define CONFIG_IPADDR 192.168.103.100
+#define CONFIG_NETMASK 255.255.255.0
+#define CONFIG_SERVERIP 192.168.103.240
#define BOOT_TARGET_DEVICES(func) \
func(MMC, mmc, 1) \
修改后进行编译:
$ make -j4
10. 编写启动脚本
10.1 编写脚本
$ vim boot.sh
修改为如下内容:
#!/bin/sh
qemu-system-arm \
-M vexpress-a9 \
-kernel u-boot-2017.05/u-boot \
-nographic \
-m 512M \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0
如果一切顺利,此时运行脚本就可以正常使用了。
效果是:启动uboot后,kernel和dtb通过tftp加载,根文件系统通过nfs加载。
10.2 数据文件系统
nfs除了可以挂载根文件系统,还可以挂载数据文件系统:
1.创建文件夹
$ cd /home/qemulinux
$ mkdir test
$ chmod 777 test
$ cd test
$ echo "hello world" > hello.txt
2.添加访问权限
$ sudo vim /etc/exports
添加如下内容:
/home/qemulinux/test *(rw,async,no_root_squash,no_subtree_check)
重启nfs:
$ /etc/init.d/nfs-kernel-server restart
3.挂载数据文件系统
运行10.1中的脚本,启动qemu版linux系统后,进行挂载:
# 替换真实IP
$ mount -o nolock -t nfs 192.168.xxx.xxx:/home/qemulinux/test mnt
此时,我们就可以通过访问开发板linux下的mnt,来访问host主机的test文件夹。