谢逸轩,马维华
(南京航空航天大学 计算机科学与技术学院,江苏 南京 211100)
科技发展日新月异,32位通用型MCU价格一次次下探以及5G万物互联的趋势面前,开源稳定带网络功能的Linux操作系统将会被移植到各个垂直领域,更新替换掉老旧的嵌入式设备。为了更好地服务于社会,系统掌握Linux移植这门技术需要在硬件资源性能溢出的当下搭建起便捷高效的开发调试平台。NFS,全称Network File System,是Linux系统中常用的一种文件共享服务,有着与Windows中服务器信息块(Server Message Block,SMB)网络文件共享服务一样的便捷和用户无感知的使用体验[1]。如今,NFS已经从1984年的1.0发展到如今的4.2版本。
平台由运行windows的笔记本、笔记本上虚拟出的Linux宿主机以及开发板三者构成。路由器接入互联网,对内运行NAT和DHCP服务,设路由器的IP地址为192.168.1.1,子网掩码24位。开发板使用网线接入路由器,笔记本既可无线也可有线接入,虚拟机的网络适配器配置为桥接自动。配置路由器依据网卡MAC地址为开发板、笔记本、虚拟机各分配静态IP地址,如图1所示。开发板已经烧录好带NFS客户端的U-boot,并与笔记本进行串口连接,以便键入命令控制和监控Linux启动和根文件系统挂载过程。笔记本和虚拟机上分别架设NFS服务,以方便数据传输,且由于其自带网络防火墙,需要注意关闭防火墙或添加端口白名单。
图1 开发调试平台网络拓扑结构
下载并安装haneWIN NFS Server for Windows[2]软件服务包。
打开程序后(免安装版需用管理员权限打开),依次进入Edit-Preferences-Exports-Edit exports file来设置需要共享的文件夹,配置文件格式为:共享目录路径+-name:共享目录别名,每一行一个共享目录。笔者以桌面上存放bootloader和内核的boot目录,以及存放根文件系统的rootfs目录为例,在对话框中添加以下内容并点击Save保存配置。
C:UsersyournameDesktopoot-name:boot
C:UsersyournameDesktop ootfs-name:rootfs
此时,注意勾选“Map client root (UID 0) to root for all entries”选项,该选项可让开发板内核以root权限挂载共享目录。
在Linux虚拟机的终端中输入mount-t nfs-o nolock 192.168.1.6:/boot /mnt,可查看是否挂载成功。若报错或未成功挂载,检查Windows防火墙是否将NFS Server程序加入了白名单或者防火墙是否已经关闭,-nolock选项意为当文件被写入时,不使用额外的Network Lock Manager服务来锁定该文件,添加此选项有助于增加兼容性。
成功验证后,使用“umount /mnt”命令解除挂载。
2.2.1 CentOS 7用户(默认root登录,否则下述各命令前加入sudo)
使用以下命令安装NFS服务包:
yum install -y nfs-utils rpcbind
编辑/etc/exports文件,配置需共享的目录,配置格式:
共享目录路径+被允许挂载的主机/IP+(常用共享选项见表1,多选项间逗号分隔)。
现在以共享/root/boot和/root/rootfs为例,添加以下两行到/etc/exports文件尾部:
/root/boot *(rw,insecure,async,no_root_squash,no_subtree_check)
/root/rootfs *(rw,insecure,sync,no_root_squash,no_subtree_check)
注:*表示任意主机;*与(之间不能存在空格。
更改NFS服务器选项以兼容U-boot上的NFS V2版本,Linux上的NFS服务器默认不兼容V2版本,编辑/etc/nfs.conf文件,分别找到[nfsd]和vers2=y两行,删除两行前各自的#号以取消注释。如果没找到可以直接添加这两行内容,保存并退出。
重启NFS服务以生效上述配置,在终端中输入:
systemctl restart nfs
为NFS服务添加防火墙白名单或者使用以下命令暂时关闭防火墙(重启后失效):
systemctl stop firewalld
使用mount -t nfs -o nolock 192.168.1.8:/root/boot /mnt或者showmount -e 192.168.1.8来验证共享配置的生效。使用cat /proc/fs/nfsd/versions来验证服务器兼容版本中是否包含+2(NFS Version 2)。
如果需要NFS服务开机自启并禁用防火墙,输入
systemctl enable nfs
systemctl disable firewalld
2.2.2 Ubuntu 20.04用户(默认普通用户登录)
使用以下命令安装NFS服务包:
sudo apt install nfs-kernel-server
编辑/etc/exports文件,配置格式与示例与CentOS 7用户一致,请参照上节完成共享目录配置。
编辑/etc/default/nfs-kernel-server文件,以兼容U-boot上的NFS V2的版本,Linux上的NFS服务器默认不兼容V2版本。找到RPCNFSDCOUNT、RPCMOUNTDOPTS两项,分别将其修改为以下内容,其余不变:
RPCNFSDCOUNT=”—nfs-version 2 8”
RPCMOUNTDOPTS=”—nfs-version 2—manage-gids”
重启NFS服务以生效上述配置,在终端中输入:
sudo systemctl restart nfs-kernel-server
由于ubuntu系统默认关闭防火墙,故不需要额外操作。确需关闭的,请运行sudo ufw disable。
使用sudo mount -t nfs -o nolock 192.168.1.8:/root/boot /mnt或者sudo showmount -e 192.168.1.8来验证共享配置的生效。使用sudo cat /proc/fs/nfsd/versions来验证服务器兼容版本中是否包含+2(NFS Version 2)。
Ubuntu系统上的NFS服务默认自启动,无需额外配置。
表1 NFS服务端共享选项[3]
2.2.3 开发板使用NFS启动Linux内核并挂载远端根文件系统
为开发板断电再上电;在putty(串口终端程序名)中键入任意键打断开发板普通启动过程;键入以下命令,以使用NFS启动Linux内核并挂载远端根文件系统(以Windows为例):
setenv serverip 192.168.1.6→#启用Windows上的NFS服务IP地址
setenv ipaddr 192.168.1.4→#为开发板自身设定同子网下的IP地址
setenv rootpath /rootfs→#Windows上设置的根文件系统别名
setenv bootpath /boot→#Windows上设置的启动文件夹目录别名
setenv fdtfile am335x.dtb→#指示开发板自身设备树的文件名
setenv fdtaddr 0x88000000→#指示设备树在内存中的位置
setenv bootfile zImage→#指示Linux内核文件名
setenv loadaddr 0x82000000→#指示Linux内核在内存中的位置
setenv nfsloadimage “nfs ${loadaddr} ${serverip}:${bootpath}/${bootfile}”
#指示U-boot从NFS服务器上下载Linux内核到内存指定位置
setenv nfsloadfdt “nfs ${fdtaddr} ${serverip}:${bootpath}/${fdtfile}”
#指示U-boot从NFS服务器上下载设备树文件到指定内存位置
setenv nfsargs “setenv bootargs console=ttyO0,115200n8 root=/dev/nfs nfsroot=${serverip}:${rootpath},nolock rw ip=dhcp”
#设置内核启动参数,将内核console设置为串口ttyO0并以波特率115200bps、无奇偶校验、8位数据位的规格通信,通知内核通过NFS挂载根文件系统。
setenv nfsboot “setenv autoload no; run nfsloadimage; run nfsloadfdt; run nfsargs; bootz ${loadaddr}-${fdtaddr}”
#自定义NFS命令启动脚本,以便重复使用
saveenv→#保存上述环境变量,以便重复使用
run nfsboot→#使用NFS启动远程内核并挂载远程根文件系统,下次重启开发板时可直接运行最后这一条命令以快速启动
总结之前,需注意上述方法的两种常见误区:一是不能在Windows下解压rootfs.tar.gz到根文件系统的共享目录,但是可通过Linux虚拟机挂载Windows共享目录后使用tar-xvf命令解压导入,否则会产生此类报错 [5.316458] Starting init: /sbin/init exists but couldn’t execute it (error-13)。二是当内核滚屏输出[5.226074]bootserver=192.168.1.1, rootserver=192.168.1.6, rootpath= 时,不要因为rootpath= 后面为空就认为内核启动参数传入有误,正常启动的话rootpath=后也是空白的。
进行嵌入式Linux移植,不可避免使用Linux作为交叉编译的宿主机,但是由于国人的电脑操作习惯仍旧是建立在Windows系统上的,那么采取Windows系统为主力查询各种资料,虚拟机安装Linux发行版为辅助编译目标文件便是最自然的选择。此时,采用本文所述的NFS文件系统穿插其中,起到桥梁作用,进一步为嵌入式Linux移植开发提供便利。