謝逸軒,馬維華
(南京航空航天大學(xué) 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,江蘇 南京 211100)
科技發(fā)展日新月異,32位通用型MCU價(jià)格一次次下探以及5G萬物互聯(lián)的趨勢面前,開源穩(wěn)定帶網(wǎng)絡(luò)功能的Linux操作系統(tǒng)將會(huì)被移植到各個(gè)垂直領(lǐng)域,更新替換掉老舊的嵌入式設(shè)備。為了更好地服務(wù)于社會(huì),系統(tǒng)掌握Linux移植這門技術(shù)需要在硬件資源性能溢出的當(dāng)下搭建起便捷高效的開發(fā)調(diào)試平臺。NFS,全稱Network File System,是Linux系統(tǒng)中常用的一種文件共享服務(wù),有著與Windows中服務(wù)器信息塊(Server Message Block,SMB)網(wǎng)絡(luò)文件共享服務(wù)一樣的便捷和用戶無感知的使用體驗(yàn)[1]。如今,NFS已經(jīng)從1984年的1.0發(fā)展到如今的4.2版本。
平臺由運(yùn)行windows的筆記本、筆記本上虛擬出的Linux宿主機(jī)以及開發(fā)板三者構(gòu)成。路由器接入互聯(lián)網(wǎng),對內(nèi)運(yùn)行NAT和DHCP服務(wù),設(shè)路由器的IP地址為192.168.1.1,子網(wǎng)掩碼24位。開發(fā)板使用網(wǎng)線接入路由器,筆記本既可無線也可有線接入,虛擬機(jī)的網(wǎng)絡(luò)適配器配置為橋接自動(dòng)。配置路由器依據(jù)網(wǎng)卡MAC地址為開發(fā)板、筆記本、虛擬機(jī)各分配靜態(tài)IP地址,如圖1所示。開發(fā)板已經(jīng)燒錄好帶NFS客戶端的U-boot,并與筆記本進(jìn)行串口連接,以便鍵入命令控制和監(jiān)控Linux啟動(dòng)和根文件系統(tǒng)掛載過程。筆記本和虛擬機(jī)上分別架設(shè)NFS服務(wù),以方便數(shù)據(jù)傳輸,且由于其自帶網(wǎng)絡(luò)防火墻,需要注意關(guān)閉防火墻或添加端口白名單。
圖1 開發(fā)調(diào)試平臺網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)
下載并安裝haneWIN NFS Server for Windows[2]軟件服務(wù)包。
打開程序后(免安裝版需用管理員權(quán)限打開),依次進(jìn)入Edit-Preferences-Exports-Edit exports file來設(shè)置需要共享的文件夾,配置文件格式為:共享目錄路徑+-name:共享目錄別名,每一行一個(gè)共享目錄。筆者以桌面上存放bootloader和內(nèi)核的boot目錄,以及存放根文件系統(tǒng)的rootfs目錄為例,在對話框中添加以下內(nèi)容并點(diǎn)擊Save保存配置。
C:UsersyournameDesktopoot-name:boot
C:UsersyournameDesktop ootfs-name:rootfs
此時(shí),注意勾選“Map client root (UID 0) to root for all entries”選項(xiàng),該選項(xiàng)可讓開發(fā)板內(nèi)核以root權(quán)限掛載共享目錄。
在Linux虛擬機(jī)的終端中輸入mount-t nfs-o nolock 192.168.1.6:/boot /mnt,可查看是否掛載成功。若報(bào)錯(cuò)或未成功掛載,檢查Windows防火墻是否將NFS Server程序加入了白名單或者防火墻是否已經(jīng)關(guān)閉,-nolock選項(xiàng)意為當(dāng)文件被寫入時(shí),不使用額外的Network Lock Manager服務(wù)來鎖定該文件,添加此選項(xiàng)有助于增加兼容性。
成功驗(yàn)證后,使用“umount /mnt”命令解除掛載。
2.2.1 CentOS 7用戶(默認(rèn)root登錄,否則下述各命令前加入sudo)
使用以下命令安裝NFS服務(wù)包:
yum install -y nfs-utils rpcbind
編輯/etc/exports文件,配置需共享的目錄,配置格式:
共享目錄路徑+被允許掛載的主機(jī)/IP+(常用共享選項(xiàng)見表1,多選項(xiàng)間逗號分隔)。
現(xiàn)在以共享/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)
注:*表示任意主機(jī);*與(之間不能存在空格。
更改NFS服務(wù)器選項(xiàng)以兼容U-boot上的NFS V2版本,Linux上的NFS服務(wù)器默認(rèn)不兼容V2版本,編輯/etc/nfs.conf文件,分別找到[nfsd]和vers2=y兩行,刪除兩行前各自的#號以取消注釋。如果沒找到可以直接添加這兩行內(nèi)容,保存并退出。
重啟NFS服務(wù)以生效上述配置,在終端中輸入:
systemctl restart nfs
為NFS服務(wù)添加防火墻白名單或者使用以下命令暫時(shí)關(guān)閉防火墻(重啟后失效):
systemctl stop firewalld
使用mount -t nfs -o nolock 192.168.1.8:/root/boot /mnt或者showmount -e 192.168.1.8來驗(yàn)證共享配置的生效。使用cat /proc/fs/nfsd/versions來驗(yàn)證服務(wù)器兼容版本中是否包含+2(NFS Version 2)。
如果需要NFS服務(wù)開機(jī)自啟并禁用防火墻,輸入
systemctl enable nfs
systemctl disable firewalld
2.2.2 Ubuntu 20.04用戶(默認(rèn)普通用戶登錄)
使用以下命令安裝NFS服務(wù)包:
sudo apt install nfs-kernel-server
編輯/etc/exports文件,配置格式與示例與CentOS 7用戶一致,請參照上節(jié)完成共享目錄配置。
編輯/etc/default/nfs-kernel-server文件,以兼容U-boot上的NFS V2的版本,Linux上的NFS服務(wù)器默認(rèn)不兼容V2版本。找到RPCNFSDCOUNT、RPCMOUNTDOPTS兩項(xiàng),分別將其修改為以下內(nèi)容,其余不變:
RPCNFSDCOUNT=”—nfs-version 2 8”
RPCMOUNTDOPTS=”—nfs-version 2—manage-gids”
重啟NFS服務(wù)以生效上述配置,在終端中輸入:
sudo systemctl restart nfs-kernel-server
由于ubuntu系統(tǒng)默認(rèn)關(guān)閉防火墻,故不需要額外操作。確需關(guān)閉的,請運(yùn)行sudo ufw disable。
使用sudo mount -t nfs -o nolock 192.168.1.8:/root/boot /mnt或者sudo showmount -e 192.168.1.8來驗(yàn)證共享配置的生效。使用sudo cat /proc/fs/nfsd/versions來驗(yàn)證服務(wù)器兼容版本中是否包含+2(NFS Version 2)。
Ubuntu系統(tǒng)上的NFS服務(wù)默認(rèn)自啟動(dòng),無需額外配置。
表1 NFS服務(wù)端共享選項(xiàng)[3]
2.2.3 開發(fā)板使用NFS啟動(dòng)Linux內(nèi)核并掛載遠(yuǎn)端根文件系統(tǒng)
為開發(fā)板斷電再上電;在putty(串口終端程序名)中鍵入任意鍵打斷開發(fā)板普通啟動(dòng)過程;鍵入以下命令,以使用NFS啟動(dòng)Linux內(nèi)核并掛載遠(yuǎn)端根文件系統(tǒng)(以Windows為例):
setenv serverip 192.168.1.6→#啟用Windows上的NFS服務(wù)IP地址
setenv ipaddr 192.168.1.4→#為開發(fā)板自身設(shè)定同子網(wǎng)下的IP地址
setenv rootpath /rootfs→#Windows上設(shè)置的根文件系統(tǒng)別名
setenv bootpath /boot→#Windows上設(shè)置的啟動(dòng)文件夾目錄別名
setenv fdtfile am335x.dtb→#指示開發(fā)板自身設(shè)備樹的文件名
setenv fdtaddr 0x88000000→#指示設(shè)備樹在內(nèi)存中的位置
setenv bootfile zImage→#指示Linux內(nèi)核文件名
setenv loadaddr 0x82000000→#指示Linux內(nèi)核在內(nèi)存中的位置
setenv nfsloadimage “nfs ${loadaddr} ${serverip}:${bootpath}/${bootfile}”
#指示U-boot從NFS服務(wù)器上下載Linux內(nèi)核到內(nèi)存指定位置
setenv nfsloadfdt “nfs ${fdtaddr} ${serverip}:${bootpath}/${fdtfile}”
#指示U-boot從NFS服務(wù)器上下載設(shè)備樹文件到指定內(nèi)存位置
setenv nfsargs “setenv bootargs console=ttyO0,115200n8 root=/dev/nfs nfsroot=${serverip}:${rootpath},nolock rw ip=dhcp”
#設(shè)置內(nèi)核啟動(dòng)參數(shù),將內(nèi)核console設(shè)置為串口ttyO0并以波特率115200bps、無奇偶校驗(yàn)、8位數(shù)據(jù)位的規(guī)格通信,通知內(nèi)核通過NFS掛載根文件系統(tǒng)。
setenv nfsboot “setenv autoload no; run nfsloadimage; run nfsloadfdt; run nfsargs; bootz ${loadaddr}-${fdtaddr}”
#自定義NFS命令啟動(dòng)腳本,以便重復(fù)使用
saveenv→#保存上述環(huán)境變量,以便重復(fù)使用
run nfsboot→#使用NFS啟動(dòng)遠(yuǎn)程內(nèi)核并掛載遠(yuǎn)程根文件系統(tǒng),下次重啟開發(fā)板時(shí)可直接運(yùn)行最后這一條命令以快速啟動(dòng)
總結(jié)之前,需注意上述方法的兩種常見誤區(qū):一是不能在Windows下解壓rootfs.tar.gz到根文件系統(tǒng)的共享目錄,但是可通過Linux虛擬機(jī)掛載Windows共享目錄后使用tar-xvf命令解壓導(dǎo)入,否則會(huì)產(chǎn)生此類報(bào)錯(cuò) [5.316458] Starting init: /sbin/init exists but couldn’t execute it (error-13)。二是當(dāng)內(nèi)核滾屏輸出[5.226074]bootserver=192.168.1.1, rootserver=192.168.1.6, rootpath= 時(shí),不要因?yàn)閞ootpath= 后面為空就認(rèn)為內(nèi)核啟動(dòng)參數(shù)傳入有誤,正常啟動(dòng)的話rootpath=后也是空白的。
進(jìn)行嵌入式Linux移植,不可避免使用Linux作為交叉編譯的宿主機(jī),但是由于國人的電腦操作習(xí)慣仍舊是建立在Windows系統(tǒng)上的,那么采取Windows系統(tǒng)為主力查詢各種資料,虛擬機(jī)安裝Linux發(fā)行版為輔助編譯目標(biāo)文件便是最自然的選擇。此時(shí),采用本文所述的NFS文件系統(tǒng)穿插其中,起到橋梁作用,進(jìn)一步為嵌入式Linux移植開發(fā)提供便利。