嵌入式根文件系統(tǒng)的移植和制作詳解
一.文件系統(tǒng)簡介
理論上說一個(gè)嵌入式設(shè)備如果內(nèi)核能夠運(yùn)行起來,且不需要運(yùn)行用戶進(jìn)程的話,是不需要文件系統(tǒng)的,文件系統(tǒng)簡單的說就是一種目錄結(jié)構(gòu),由于 linux操作系統(tǒng)的設(shè)備在系統(tǒng)中是以文件的形式存在,將這些文件進(jìn)行分類管理以及提供和內(nèi)核交互的接口,就形成一定的目錄結(jié)構(gòu)也就是文件系統(tǒng),文件系統(tǒng)是為用戶反映系統(tǒng)的一種形式,為用戶提供一個(gè)檢測(cè)控制系統(tǒng)的接口。
根文件系統(tǒng),我認(rèn)為根文件系統(tǒng)就是一種特殊的文件系統(tǒng),那么根文件系統(tǒng)和普通的文件系統(tǒng)有什么區(qū)別呢?由于根文件系統(tǒng)是內(nèi)核啟動(dòng)時(shí)掛在的第一個(gè)文件系統(tǒng),那么根文件系統(tǒng)就要包括Linux啟動(dòng)時(shí)所必須的目錄和關(guān)鍵性的文件,例如Linux啟動(dòng)時(shí)都需要有init目錄下的相關(guān)文件,在 Linux掛載分區(qū)時(shí)Linux一定會(huì)找/etc/fSTab這個(gè)掛載文件等,根文件系統(tǒng)中還包括了許多的應(yīng)用程序bin目錄等,任何包括這些Linux 系統(tǒng)啟動(dòng)所必須的文件都可以成為根文件系統(tǒng)。
Linux支持多種文件系統(tǒng),包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,為了對(duì)各類文件系統(tǒng)進(jìn)行統(tǒng)一管理,Linux引入了虛擬文件系統(tǒng)VFS(Virtual File System),為各類文件系統(tǒng)提供一個(gè)統(tǒng)一的操作界面和應(yīng)用編程接口。
Linux啟動(dòng)時(shí),第一個(gè)必須掛載的是根文件系統(tǒng);若系統(tǒng)不能從指定設(shè)備上掛載根文件系統(tǒng),則系統(tǒng)會(huì)出錯(cuò)而退出啟動(dòng)。之后可以自動(dòng)或手動(dòng)掛載其他的文件系統(tǒng)。因此,一個(gè)系統(tǒng)中可以同時(shí)存在不同的文件系統(tǒng)。
不同的文件系統(tǒng)類型有不同的特點(diǎn),因而根據(jù)存儲(chǔ)設(shè)備的硬件特性、系統(tǒng)需求等有不同的應(yīng)用場(chǎng)合。在嵌入式Linux應(yīng)用中,主要的存儲(chǔ)設(shè)備為 RAM(DRAM, SDRAM)和ROM(常采用FLASH存儲(chǔ)器),常用的基于存儲(chǔ)設(shè)備的文件系統(tǒng)類型包括:jffs2, yaffs, cramfs, romfs, ramdisk, ramfs/tmpfs等。
1. 基于Flash的文件系統(tǒng)
flash(閃存)作為嵌入式系統(tǒng)的主要存儲(chǔ)媒介,有其自身的特性。Flash的寫入操作只能把對(duì)應(yīng)位置的1修改為0,而不能把0修改為1(擦除 Flash就是把對(duì)應(yīng)存儲(chǔ)塊的內(nèi)容恢復(fù)為1),因此,一般情況下,向Flash寫入內(nèi)容時(shí),需要先擦除對(duì)應(yīng)的存儲(chǔ)區(qū)間,這種擦除是以塊(block)為單位進(jìn)行的。
閃存主要有NOR和NAND兩種技術(shù)。Flash存儲(chǔ)器的擦寫次數(shù)是有限的,NAND閃存還有特殊的硬件接口和讀寫時(shí)序。因此,必須針對(duì)Flash的硬件特性設(shè)計(jì)符合應(yīng)用要求的文件系統(tǒng);傳統(tǒng)的文件系統(tǒng)如ext2等,用作Flash的文件系統(tǒng)會(huì)有諸多弊端。
一塊Flash芯片可以被劃分為多個(gè)分區(qū),各分區(qū)可以采用不同的文件系統(tǒng);兩塊Flash芯片也可以合并為一個(gè)分區(qū)使用,采用一個(gè)文件系統(tǒng)。即文件系統(tǒng)是針對(duì)于存儲(chǔ)器分區(qū)而言的,而非存儲(chǔ)芯片。
在嵌入式Linux下,MTD(Memory Technology Device,存儲(chǔ)技術(shù)設(shè)備)為底層硬件(閃存)和上層(文件系統(tǒng))之間提供一個(gè)統(tǒng)一的抽象接口,即Flash的文件系統(tǒng)都是基于MTD驅(qū)動(dòng)層的(參見上面的Linux下的文件系統(tǒng)結(jié)構(gòu)圖)。使用MTD驅(qū)動(dòng)程序的主要優(yōu)點(diǎn)在于,它是專門針對(duì)各種非易失性存儲(chǔ)器(以閃存為主)而設(shè)計(jì)的,因而它對(duì)Flash有更好的支持、管理和基于扇區(qū)的擦除、讀/寫操作接口。
(1) jffs2
JFFS文件系統(tǒng)最早是由瑞典Axis Communications公司基于Linux2.0的內(nèi)核為嵌入式系統(tǒng)開發(fā)的文件系統(tǒng)。JFFS2是RedHat公司基于JFFS開發(fā)的閃存文件系統(tǒng),最初是針對(duì)RedHat公司的嵌入式產(chǎn)品eCos開發(fā)的嵌入式文件系統(tǒng),所以JFFS2也可以用在Linux, uCLinux中。
Jffs2: 日志閃存文件系統(tǒng)版本2 (Journalling Flash Filesystem v2)
主要用于NOR型閃存,基于MTD驅(qū)動(dòng)層,特點(diǎn)是:可讀寫的、支持?jǐn)?shù)據(jù)壓縮的、基于哈希表的日志型文件系統(tǒng),并提供了崩潰/掉電安全保護(hù),提供“寫平衡”支持等。缺點(diǎn)主要是當(dāng)文件系統(tǒng)已滿或接近滿時(shí),因?yàn)槔占年P(guān)系而使jffs2的運(yùn)行速度大大放慢。
jffs不適合用于NAND閃存主要是因?yàn)镹AND閃存的容量一般較大,這樣導(dǎo)致jffs為維護(hù)日志節(jié)點(diǎn)所占用的內(nèi)存空間迅速增大,另外,jffs文件系統(tǒng)在掛載時(shí)需要掃描整個(gè)FLASH的內(nèi)容,以找出所有的日志節(jié)點(diǎn),建立文件結(jié)構(gòu),對(duì)于大容量的NAND閃存會(huì)耗費(fèi)大量時(shí)間。
(2) yaffs:Yet Another Flash File System
yaffs/yaffs2是專為嵌入式系統(tǒng)使用NAND型閃存而設(shè)計(jì)的一種日志型文件系統(tǒng)。與jffs2相比,它減少了一些功能(例如不支持?jǐn)?shù)據(jù)壓縮),所以速度更快,掛載時(shí)間很短,對(duì)內(nèi)存的占用較小。另外,它還是跨平臺(tái)的文件系統(tǒng),除了Linux和eCos,還支持WinCE, pSOS和ThreadX等。
yaffs/yaffs2自帶NAND芯片的驅(qū)動(dòng),并且為嵌入式系統(tǒng)提供了直接訪問文件系統(tǒng)的API,用戶可以不使用Linux中的MTD與VFS,直接對(duì)文件系統(tǒng)操作。當(dāng)然,yaffs也可與MTD驅(qū)動(dòng)程序配合使用。
yaffs與yaffs2的主要區(qū)別在于,前者僅支持小頁(512 Bytes) NAND閃存,后者則可支持大頁(2KB) NAND閃存。同時(shí),yaffs2在內(nèi)存空間占用、垃圾回收速度、讀/寫速度等方面均有大幅提升。
(3) Cramfs:Compressed ROM File System
Cramfs是Linux的創(chuàng)始人 Linus Torvalds參與開發(fā)的一種只讀的壓縮文件系統(tǒng)。它也基于MTD驅(qū)動(dòng)程序。
在cramfs文件系統(tǒng)中,每一頁(4KB)被單獨(dú)壓縮,可以隨機(jī)頁訪問,其壓縮比高達(dá)2:1,為嵌入式系統(tǒng)節(jié)省大量的Flash存儲(chǔ)空間,使系統(tǒng)可通過更低容量的FLASH存儲(chǔ)相同的文件,從而降低系統(tǒng)成本。
Cramfs文件系統(tǒng)以壓縮方式存儲(chǔ),在運(yùn)行時(shí)解壓縮,所以不支持應(yīng)用程序以XIP方式運(yùn)行,所有的應(yīng)用程序要求被拷到RAM里去運(yùn)行,但這并不代表比 Ramfs需求的RAM空間要大一點(diǎn),因?yàn)镃ramfs是采用分頁壓縮的方式存放檔案,在讀取檔案時(shí),不會(huì)一下子就耗用過多的內(nèi)存空間,只針對(duì)目前實(shí)際讀取的部分分配內(nèi)存,尚沒有讀取的部分不分配內(nèi)存空間,當(dāng)我們讀取的檔案不在內(nèi)存時(shí),Cramfs文件系統(tǒng)自動(dòng)計(jì)算壓縮后的資料所存的位置,再即時(shí)解壓縮到 RAM中。
另外,它的速度快,效率高,其只讀的特點(diǎn)有利于保護(hù)文件系統(tǒng)免受破壞,提高了系統(tǒng)的可靠性。
由于以上特性,Cramfs在嵌入式系統(tǒng)中應(yīng)用廣泛。[!--empirenews.page--]
但是它的只讀屬性同時(shí)又是它的一大缺陷,使得用戶無法對(duì)其內(nèi)容對(duì)進(jìn)擴(kuò)充。
Cramfs映像通常是放在Flash中,但是也能放在別的文件系統(tǒng)里,使用loopback 設(shè)備可以把它安裝別的文件系統(tǒng)里。
(4) Romfs
傳統(tǒng)型的Romfs文件系統(tǒng)是一種簡單的、緊湊的、只讀的文件系統(tǒng),不支持動(dòng)態(tài)擦寫保存,按順序存放數(shù)據(jù),因而支持應(yīng)用程序以XIP(eXecute In Place,片內(nèi)運(yùn)行)方式運(yùn)行,在系統(tǒng)運(yùn)行時(shí),節(jié)省RAM空間。uClinux系統(tǒng)通常采用Romfs文件系統(tǒng)。
其他文件系統(tǒng):fat/fat32也可用于實(shí)際嵌入式系統(tǒng)的擴(kuò)展存儲(chǔ)器(例如PDA, Smartphone, 數(shù)碼相機(jī)等的SD卡),這主要是為了更好的與最流行的Windows桌面操作系統(tǒng)相兼容。ext2也可以作為嵌入式Linux的文件系統(tǒng),不過將它用于 FLASH閃存會(huì)有諸多弊端。
2. 基于RAM的文件系統(tǒng)
(1) Ramdisk
Ramdisk是將一部分固定大小的內(nèi)存當(dāng)作分區(qū)來使用。它并非一個(gè)實(shí)際的文件系統(tǒng),而是一種將實(shí)際的文件系統(tǒng)裝入內(nèi)存的機(jī)制,并且可以作為根文件系統(tǒng)。將一些經(jīng)常被訪問而又不會(huì)更改的文件(如只讀的根文件系統(tǒng))通過Ramdisk放在內(nèi)存中,可以明顯地提高系統(tǒng)的性能。
在Linux的啟動(dòng)階段,initrd提供了一套機(jī)制,可以將內(nèi)核映像和根文件系統(tǒng)一起載入內(nèi)存。
(2)ramfs/tmpfs
Ramfs是Linus Torvalds開發(fā)的一種基于內(nèi)存的文件系統(tǒng),工作于虛擬文件系統(tǒng)(VFS)層,不能格式化,可以創(chuàng)建多個(gè),在創(chuàng)建時(shí)可以指定其最大能使用的內(nèi)存大小。(實(shí)際上,VFS本質(zhì)上可看成一種內(nèi)存文件系統(tǒng),它統(tǒng)一了文件在內(nèi)核中的表示方式,并對(duì)磁盤文件系統(tǒng)進(jìn)行緩沖。)
Ramfs/tmpfs文件系統(tǒng)把所有的文件都放在RAM中,所以讀/寫操作發(fā)生在RAM中,可以用ramfs/tmpfs來存儲(chǔ)一些臨時(shí)性或經(jīng)常要修改的數(shù)據(jù),例如/tmp和/var目錄,這樣既避免了對(duì)Flash存儲(chǔ)器的讀寫損耗,也提高了數(shù)據(jù)讀寫速度。
Ramfs/tmpfs相對(duì)于傳統(tǒng)的Ramdisk的不同之處主要在于:不能格式化,文件系統(tǒng)大小可隨所含文件內(nèi)容大小變化。
Tmpfs的一個(gè)缺點(diǎn)是當(dāng)系統(tǒng)重新引導(dǎo)時(shí)會(huì)丟失所有數(shù)據(jù)。
3. 網(wǎng)絡(luò)文件系統(tǒng)NFS (Network File System)
NFS是由Sun開發(fā)并發(fā)展起來的一項(xiàng)在不同機(jī)器、不同操作系統(tǒng)之間通過網(wǎng)絡(luò)共享文件的技術(shù)。在嵌入式Linux系統(tǒng)的開發(fā)調(diào)試階段,可以利用該技術(shù)在主機(jī)上建立基于NFS的根文件系統(tǒng),掛載到嵌入式設(shè)備,可以很方便地修改根文件系統(tǒng)的內(nèi)容。
以上討論的都是基于存儲(chǔ)設(shè)備的文件系統(tǒng)(memory-based file system),它們都可用作Linux的根文件系統(tǒng)。實(shí)際上,Linux還支持邏輯的或偽文件系統(tǒng)(logical or pseudo file system),例如procfs(proc文件系統(tǒng)),用于獲取系統(tǒng)信息,以及devfs(設(shè)備文件系統(tǒng))和sysfs,用于維護(hù)設(shè)備文件。
我們要移植的開發(fā)板的存儲(chǔ)設(shè)備為Nandflash,我們可以用應(yīng)用比較廣泛的cramfs文件系統(tǒng)。
二.移植準(zhǔn)備
1.目標(biāo)板
我們還是使用之前移植過程一直使用的開發(fā)板參數(shù)。
2.軟件準(zhǔn)備
(1)Busybox
Busybox被形象的稱為嵌入式linux系統(tǒng)中的瑞士軍刀,可以從這個(gè)稱呼中看到busybox是一個(gè)集多種功能于一身的東西,它將許多常用的UNIX命令和工具結(jié)合到了一個(gè)單獨(dú)的可執(zhí)行程序中。雖然與相應(yīng)的GNU工具比較起來,busybox所提供的功能和參數(shù)略少,但在比較小的系統(tǒng)(例如啟動(dòng)盤)或者嵌入式系統(tǒng)中,已經(jīng)足夠了。
Busybox在設(shè)計(jì)上就充分考慮了硬件資源受限的特殊工作環(huán)境。它采用一種很巧妙的辦法減少自己的體積:所有的命令都通過“插件”的方式集中到一個(gè)可執(zhí)行文件中,在實(shí)際應(yīng)用過程中通過不同的符號(hào)鏈接來確定到底要執(zhí)行哪個(gè)操作。例如最終生成的可執(zhí)行文件為busybox,當(dāng)為它建立一個(gè)符號(hào)鏈接ls的時(shí)候,就可以通過執(zhí)行這個(gè)新命令實(shí)現(xiàn)列目錄的功能。采用單一執(zhí)行文件的方式最大限度地共享了程序代碼,甚至連文件頭、內(nèi)存中的程序控制塊等其他操作系統(tǒng)資源都共享了,對(duì)于資源比較緊張的系統(tǒng)來說,真是最合適不過了。
在busybox的編譯過程中,可以非常方便地加減它的“插件”,最后的符號(hào)鏈接也可以由編譯系統(tǒng)自動(dòng)生成。
編譯busybox
Busybox的編譯過程與內(nèi)核的編譯過程很接近都是先make menuconfig進(jìn)行配置,然后在make進(jìn)行編譯。
【1】從http://www.busybox.net/downloads/下載busybox工具。這里我們選擇busybox-1.13.4.tar.bz2
【2】解壓busybox-1.13.4.tar.bz2使用命令
tar jxvf busybox-1.13.4.tar.bz2
【3】進(jìn)入busybox目錄,修改Makefile 在164行 CROSS_COMPILE=arm-linux-
【4】Make menuconfig進(jìn)行配置,可以選擇靜態(tài)編譯,如果是動(dòng)態(tài)編譯的話要拷貝相應(yīng)的庫文件,默認(rèn)配置保存即可。
【5】make all install
這是會(huì)在busybox目錄下生成_install文件夾。
(2)文件系統(tǒng)打包工具
【1】從http://prdownloads.sourceforge.net/cramfs/下載cramfs工具。
【2】解壓cramfs-1.1.tar.gz使用命令:tar zxvf cramfs-1.1.tar.gz
【3】進(jìn)入cramfs工具的根目錄執(zhí)行make。
【4】Make后在cramfs工具的根目錄中就會(huì)生成一個(gè)mkcramfs文件,這個(gè)就是我們需要的工具。
三.制作過程
1.建立根文件系統(tǒng)目錄
就是之前busybox生成的_install目錄 cd …/_install
2.創(chuàng)建各種必要的系統(tǒng)文件目錄。
mkdir dev lib tmp proc
3.創(chuàng)建設(shè)備文件。
cd dev
mknod fb0 c 29 0 建立framebuffer設(shè)備文件
mknod ts0 c 13 128 建立觸摸屏設(shè)備文件
mknod console c 5 1
mknod tty0 c 4 0
mknod tty1 c 4 1
mknod tty2 c 4 2
mknod tty3 c 4 3
mknod tty4 c 4 4[!--empirenews.page--]
4.添加必要的庫文件,由于之前沒有選擇靜態(tài)編譯busybox,這里要拷貝相應(yīng)的庫文件
cd lib
cp –arf …/arm-linux/lib/* .
5.根據(jù)自己需要添加應(yīng)用程序
這里我們編寫一個(gè)簡單的應(yīng)用程序打印一句問候語,程序代碼如下:
#include
void main()
{
printf(“Hello Worldn”);
}
注意編譯時(shí)要使用arm-linux-gcc,由于之前我們把編譯器的庫文件全部進(jìn)行拷貝,可以直接動(dòng)態(tài)編譯。生成的可執(zhí)行文件hello放入tmp文件夾。使用的命令:
rm-linux-gcc hello.c –o hello
cp –arf …/_install/tmp/
6.打包
mkcramfs _install rootfs
四.燒寫過程
我們采用的燒寫方法和燒寫內(nèi)核的方法一樣內(nèi)核的燒,我們采用tftp方式,用網(wǎng)線將目標(biāo)板和pc機(jī)連接起來,配置好目標(biāo)板的網(wǎng)絡(luò)參數(shù),主要是serverip、ipaddr。
首先將rootfs下載到內(nèi)存中:#tftp 30008000 rootfs
按照之前內(nèi)核的nandflash分區(qū)進(jìn)行燒寫,將內(nèi)存中的文件系統(tǒng)燒寫到flash中:
#nand erase 500000 3b00000
#nand write 30008000 500000 3b00000
重啟uboot使其加載文件系統(tǒng)。
可以看到內(nèi)核啟動(dòng),不在出現(xiàn)panic,這時(shí)會(huì)提示回車,回車后進(jìn)入命令行,我們可以使用一些linux的常用命令,如:ls、cd、vi等。
如下圖所示:
注意:我們這里使用的是PUTTY串口顯示軟件,如果用之前的DNW查看串口信息,會(huì)出現(xiàn)下面的錯(cuò)誤:
可以看到第一個(gè)目錄 [1;34mbin [0m
會(huì)發(fā)現(xiàn)出現(xiàn)的信息除了bin目錄外還有其他的內(nèi)容,這并不是文件系統(tǒng)的問題只是DNW這款軟件并不支持這些表示色彩的附加信息,換成PUTTY可以正常顯示了。
我們可以運(yùn)行一下我們自己的應(yīng)用程序hello:./hello
可以看到打印信息Hello World如下圖所示: