根文件系统首先是内核启动时所mount的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。
本节将介绍如何编译和制作Linux最小系统的根文件系统,并通过sd卡或者nfs挂载根文件系统。
编译、安装根文件系统
根文件系统的制作方法有很多,有buildroot、busybox等,本节采用安装过程最为简单的轻量级根文件系统制作工具busybox。
下载并解压busybox源码
cd /home/workspace
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -xvf busybox-1.36.1.tar.bz2
自动编译脚本
制作automake_arm32.sh自动编译脚本
cd busybox-1.36.1
vi automake_arm32.sh
# 在automake_arm32.sh中添加下列代码
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- clean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j12
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- CONFIG_PREFIX=../objects/rootfs-arm32 install
运行automake_arm32.sh编译安装busybox
./automake_arm32.sh
编译过程中会出现menuconfig界面,需要将“Settings->Build Options->Build static binary”选上
补充根文件系统
busybox编译完成后,只是初步具有了维持linux操作系统基本运行所需的可执行文件,还有设备节点、动态链接库、引导启动相关代码、用户相关信息等,需要根据开发板自身的特性做定制和适配,接下来将适配vexpress-a9开发板补充根文件系统相关内容。
进入根文件系统目录
cd /home/workspace/objects/rootfs-arm32
创建设备节点
mkdir dev
sudo mknod -m 666 dev/tty1 c 4 1
sudo mknod -m 666 dev/tty2 c 4 2
sudo mknod -m 666 dev/tty3 c 4 3
sudo mknod -m 666 dev/tty4 c 4 4
sudo mknod -m 666 dev/console c 5 1
sudo mknod -m 666 dev/null c 1 3
安装动态链接库
mkdir lib
sudo cp -d /usr/arm-linux-gnueabi/lib/*.so* ./lib
配置初始化进程rcS
mkdir -p etc/init.d
touch etc/init.d/rcS
chmod 777 etc/init.d/rcS
vim etc/init.d/rcS
# 在rcS中填入以下内容
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LD_LIBRARY_PATH=/lib:/usr/lib
/bin/mount -n -t ramfs ramfs /var
/bin/mount -n -t ramfs ramfs /tmp
/bin/mount -n -t sysfs none /sys
/bin/mount -n -t ramfs none /dev
/bin/mkdir /var/tmp
/bin/mkdir /var/modules
/bin/mkdir /var/run
/bin/mkdir /var/log
/bin/mkdir -p /dev/pts
/bin/mkdir -p /dev/shm
/sbin/mdev -s
/bin/mount -a
echo "-----------------------------------"
echo "*****welcome to vexpress board*****"
echo "-----------------------------------"
配置文件系统fstab
touch etc/fstab
vim etc/fstab
# 在fstab中填入以下内容
proc /proc proc defaults 0 0
none /dev/pts devpts mode=0622 0 0
mdev /dev ramfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev/shm tmpfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
tmpfs /mnt tmpfs defaults 0 0
var /dev tmpfs defaults 0 0
ramfs /dev ramfs defaults 0 0
配置初始化脚本
touch etc/inittab
vim etc/inittab
# 在inittab中输入以下内容
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
配置环境变量
touch etc/profile
vim etc/profile
# 在profile中添加以下内容
#!/bin/sh
USER="root"
LOGNAME=$USER
# export HOSTNAME=vexpress-a9
export HOSTNAME=`cat /etc/sysconfig/HOSTNAME`
export USER=root
export HOME=root
export PS1="[$USER@$HOSTNAME:\w]\#"
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH
增加主机名
mkdir etc/sysconfig
vi etc/sysconfig/HOSTNAME
# 在HOSTNAME中添加以下内容
vexpress-a9
创建其他文件夹
mkdir mnt proc root sys tmp var
到此,根文件系统的内容补充完毕,接下来将介绍两种挂载根文件系统的方法,一种是通过在qemu上添加外设sd卡挂载根文件系统,另一种则是通过nfs共享文件夹挂载根文件系统。
通过SD卡挂载根文件系统
自动打包脚本
编译安装完成后,进入object目录,并制作自动打包脚本makefs-arm32.sh
cd /home/workspace/objects
sudo mkdir /mnt/rootfs
sudo chmod 777 /mnt/rootfs
vi makefs-arm32.sh
# 在makefs-arm32.sh中添加下列代码
dd if=/dev/zero of=rootfs-arm32.ext3 bs=1M count=64
mkfs.ext3 rootfs-arm32.ext3
sudo mount -t ext3 rootfs-arm32.ext3 /mnt/rootfs -o loop
sudo cp -rf rootfs-arm32/* /mnt/rootfs/
sudo umount /mnt/rootfs/
运行自动打包脚本makefs-arm32.sh
./makefs-arm32.sh
运行完成后将在objects目录下生成一个rootfs-arm32.ext3文件,将作为外设sd卡加入到开发板上。
挂载根文件系统
修改qemu-start-vexpress-a9.sh
vi qemu-start-vexpress-a9.sh
# 将qemu-start-vexpress-a9.sh修改为以下内容
#! /bin/sh
qemu-system-arm -M vexpress-a9 \
-m 512M \
-kernel vexpress-v2p-ca9/arch/arm/boot/zImage \
-dtb vexpress-v2p-ca9/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-nographic \
-append "root=/dev/mmcblk0 rw console=ttyAMA0" \
-sd rootfs-arm32.ext3
运行qemu脚本启动linux最小系统
./qemu-start-vexpress-a9.sh
出现以下提示说明最小Linux操作系统已经成功启动
通过NFS挂载根文件系统
在进行软件调试的过程中,我们经常需与开发板交换文件,或者直接修改板子上的配置文件,如果使用SD卡挂载根文件系统,则每次进行文件交换都需要重启操作系统。为了提高开发效率,我们可以通过NFS共享主机上的根文件系统给开发板,实现在主机上修改完善代码并编译后,直接在开发板上运行,无缝对接。
安装NFS服务器
安装:
sudo apt install nfs-kernel-server
配置:
sudo mkdir -p /sync/rootfs
sudo vim /etc/exports
# 在/etc/exports文件中添加以下内容
/sync/rootfs *(rw,sync,no_root_squash,no_subtree_check)
# !!!注意上述内容应严格按照格式输入,不能随意增减空格!!!
重启nfs服务器:
sudo /etc/init.d/rpcbind restart
sudo /etc/init.d/nfs-kernel-server restart
将安装好的根文件系统拷贝到/sync/rootfs内
cd /home/workspace/objects/rootfs-arm32
sudo cp -rf * /sync/rootfs/
sudo chmod 777 -R /sync/rootfs
内核NFS兼容问题
为解决Linux内核与NFS服务器的兼容问题,目前有两种方案供读者参考,实在不行可以把两种都用上。
方案一:
重新编译内核,并在menuconfig下开启NFS4支持。
位置:File System -> Network File Systems->NFS client support for NFS version 4
方案二:
设置Ubuntu20.04的NFS,使之兼容NFS-V2和NFS-V3并增加调试功能。
sudo vim /etc/default/nfs-kernel-server
# 将nfs-kernel-server文件内的RPCSVCGSSDOPTS属性修改如下:
RPCSVCGSSDOPTS="--nfs-version 2,3,4 --debug --syslog"
修改完成后重启nfs服务器:
sudo /etc/init.d/rpcbind restart
sudo /etc/init.d/nfs-kernel-server restart
测试NFS挂载根文件系统
配置主机网桥(其中eth0是Ubuntu系统的主网卡,根据实际情况可能会有不同的命名)
sudo apt install uml-utilities bridge-utils
sudo vim /etc/network/interfaces
# 修改interfaces文件如下
auto lo
iface lo inet loopback
auto eth0
auto br0
iface br0 inet dhcp
bridge_ports eth0
创建tap0网卡,用于连接qemu虚拟开发板
sudo tunctl -u root -t tap0
sudo ifconfig tap0 172.16.16.10 promisc up
创建qemu-start-vexpress-a9-nfs.sh脚本文件
cd /home/workspace/objects
vim qemu-start-vexpress-a9-nfs.sh
# 在qemu-start-vexpress-a9-nfs.sh内添加以下内容
sudo qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel vexpress-v2p-ca9/arch/arm/boot/zImage \
-dtb vexpress-v2p-ca9/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
-net tap,ifname=tap0,script=no,downscript=no \
-net nic,macaddr=00:16:3e:00:00:01 \
-nographic \
-append "root=/dev/nfs rw nfsroot=172.16.16.10:/sync/rootfs,proto=tcp,nfsvers=3,nolock init=/linuxrc console=ttyAMA0 ip=172.16.16.20" \
运行qemu-start-vexpress-a9-nfs.sh脚本文件
./qemu-start-vexpress-a9-nfs.sh
出现以下提示则说明nfs根文件系统挂载成功