程 偉
(安徽理工大學 電氣與信息工程學院,安徽 淮南232001)
在嵌入式產品中,隨著系統功能復雜度的增加和對數據操作靈活性的提高,小容量的Flash設備已經不能滿足需求,大容量Flash設備使用的越來越廣泛。嵌入式文件系統可以對Flash存儲器上龐大的數據進行存儲和管理,而Yaffs2文件系統就是專門針對大容量NAND Flash存儲器設計的嵌入式文件系統,在NAND Flash上運行性能穩定優異。由于Yaffs2文件系統自身的特點,在寫入到NAND Flash存儲器中時不能使用一般的工具和方法。U-Boot作為目前被廣泛使用的一種嵌入式系統中的啟動引導程序,可以在開發過程中實現對文件的燒寫和調試[1]。目前UBoot自身還不支持燒寫Yaffs2文件系統,由于Yaffs2文件系統的特殊結構,需要對U-Boot做一定的改進。本文給出了U-Boot的修改過程并進行了詳細分析,改進后的U-Boot可直接把Yaffs2文件系統寫入NAND Flash存儲器中,方便了構建Yaffs2文件系統+大容量NAND Flash形式的嵌入式系統結構[2],使得嵌入式系統的設計開發更加便利。
目前Flash存儲器以其速度快、容量大、成本低等優點,正被廣泛的應用于嵌入式系統中。常用的Flash存儲設備類型有 NOR Flash和 NAND Flash兩種。其中 NOR Flash采用或非結構柵格存儲矩陣實現,可片內運行程序,常用于系統啟動代碼和內核映像等存儲[3],但是工藝復雜,容量小、價格較貴,具有很低的寫入和擦除速度。NAND Flash在嵌入式系統中的地位與PC上的硬盤類似,用于保存系統運行所必須的操作系統、應用程序、用戶數據等,容量大可達1GB以上且價格也相對便宜,其可擦除次數是NOR Flash的10倍,其壽命也遠遠超過 NOR Flash。NAND Flash也不是完全可靠的,每塊芯片出廠時都有一定比例的壞塊存在,在使用前需要將壞塊掃描出來,確保不再使用它們,否則會使產品有嚴重的故障隱患;而且發生位反轉的概率要高于NOR Flash,當位反轉發生在關鍵代碼、數據上時,有可能導致系統崩潰,一般在讀寫時需要使用ECC (error correction code)進行錯誤檢驗和恢復。
為了方便管理,NAND Flash的存儲空間使用了塊(block)和頁 (page)兩級存儲體系。一般128MB以下容量的NAND Flash芯片,一頁大小為 (512+16)字節,其中的512字節就是一般的存儲數據的區域,16字節為空閑區 (spare data)又稱為 OOB (out of band)區;通常在OOB區存放壞塊標記、前面512字節的ECC校驗碼等[4]。128MB以上大容量的NAND Flash芯片,一頁大小通常為2 KB,每頁包含一個2048字節的數據區和64字節的OOB區[5]。目前大容量的NAND Flash作為嵌入式產品中的存儲介質,其應用日益廣泛,NAND Flash在Compact Flash、Secure Digital、PC Cards和MMC存儲卡市場上所占份額很大。
嵌入式文件系統是嵌入式操作系統的一部分,它的任務是對邏輯文件進行管理,提供對邏輯文件操作的接口,如檢索、修改、刪除、復制等,以方便用戶的使用[6]。嵌入式文件系統還具有兼容性好、支持自定義的實時文件系統、可裁剪可配置、支持多種存儲設備等特點,一個適合嵌入式設備的文件系統,將使嵌入式設備上的文件管理更加方便快捷,大大提高嵌入式設備的性能[7]。支持在Flash上運行的常用嵌入式文件系統有Cramfs、Jffs、Jffs2、Yaffs、Yaffs2等,Cramfs文件系統是只讀文件系統。通常在NOR Flash上多選用Jffs及Jffs2文件系統,在NAND Flash上選用Yaffs或Yaffs2文件系統。
Yaffs文件系統是一種類似于Jffs/Jffs2、專門為NAND Flash設計的嵌入式文件系統,目前有Yaffs和Yaffs2兩個版本,它是日志結構的文件系統[8],開源具有很好的移植性,能夠在Linux、ucLinux和 WinCE下面運行。提供了損耗平衡和掉電保護,可以有效地避免意外掉電對文件系統一致性和完整性的影響[9]。
2.2.1 Yaffs2文件系統簡介
Yaffs是效果很理想的NAND Flash上的文件系統,但它不支持數據壓縮,而且它僅針對每頁512字節 (小頁)大小的NAND Flash存儲器;而很多大容量的NAND Flash使用大小為2KB的頁 (大頁),Yaffs并不能支持這種大頁NAND Flash。Yaffs2正是為了支持2KB每頁的大容量NAND Flash和嚴格的連續頁寫命令而開發出來的,Yaffs2作為Yaffs的升級版,不但支持這兩種頁大小的NAND Flash,而且還支持一些新型的和具有嚴格寫入時序的NAND Flash。NAND Flash的基本擦除單位是Block(塊),而基本寫入單位是page(頁);Yaffs2在分配存儲空間的時候也是以頁為單位的,不過在Yaffs2中通常被稱為塊(chunk),其實和大頁NAND Flash的頁 (page)是一樣的大小,在大多數情況下和頁是一個意思。
Yaffs2充分考慮了大頁NAND Flash的結構特點,文件系統本身就包含了OOB區的數據 (里面有壞塊標記、ECC校驗碼以及其它和Yaffs2相關的信息)。根據大頁NAND Flash以頁面為單位存取的特點,將文件組織成固定大小的數據段;利用大頁NAND Flash提供的每個頁面64字節的OOB空間來存放ECC和文件系統的組織信息,實現了錯誤檢測和壞塊處理[10]。寫入Yaffs2時,不需要再計算ECC值,首先檢查是否壞塊 (是則跳過),然后寫入2048字節的數據,最后寫入64字節的OOB數據,如此循環。
2.2.2 Yaffs2文件系統數據存儲結構
Yaffs2文件系統中的文件、目錄、鏈接、設備文件(以下統稱文件)統一用文件頭 (Yaffs2_objectHeader結構)描述,每個文件頭存放在NAND Flash某頁的數據區內,其中包括了這個文件的模式、類型、所有者ID、創建時問、Parent Object ID等信息,Yaffs2文件系統分區內的所有文件用object ID來惟一標識。一些文件系統組織信息(YAFFS TAG)即元數據 (如文件ID、頁ID、有效字節數等)存放在NAND Flash每頁的OOB區中,由于文件系統的基本組織信息保存在頁面的空閑空間中,因此在文件系統加載時只需要掃描各個頁面的空閑空間,即可建立起整個文件系統的結構,提高了文件系統的加載速度。同時由于支持的頁變大,Yaffs2的OOB區的數據結構與Yaffs的略有不同,比如Yaffs2的OOB區中增加了塊分配序列號[11]。
2.2.3 Yaffs2文件系統的優勢
與Yaffs相比,Yaffs2除了可以支持2KB每頁的NAND Flash外,還做了一些改進[12],可存儲信息更多,也更靈活。如文件頭的部分元數據,免去讀文件頭獲取這些數據的時間;Yaffs在更新文件chunk數據時,將標志位復制下來且寫入序列號加1和新數據一起寫入空白頁,然后將原chunk的標志位字節寫為0,標記chunk無效;而Yaffs2在更新時不再重寫其標志位,來標記chunk無效,加快了寫入速度[13]。塊分配序列號的采用使加載時還可區別chunk有效和無效,在垃圾收集的時候也會以此作為參考之一,判斷該塊是否適合回收,同時垃圾回收策略也有改進。Yaffs2在內存空間占用、垃圾回收速度、讀/寫速度等方面相對于Yaffs也有較大改進,如表1所示。

表1 Yaffs2與Yaffs的性能比較
表1中Yaffs2的最差性能表現在每頁512字節的NAND Flash上,與Yaffs相似;較佳性能則表現在每頁2KB的NAND Flash上。Yaffs2還可以支持東芝和SanDisk公司的多層單元閃存 (multi-level cell,MLC)部件[14]。
在嵌入式系統中,Bootloader是系統上電后執行的一小段程序,它主要完成了初始化硬件設備、準備好軟件環境,最后調用操作系統內核,真正起到了引導和加載內核的作用。U-Boot作為嵌入式系統中一種比較流行、功能強大的Bootloader,支持多種嵌入式操作系統和多種處理器系列,性能可靠穩定,功能設置靈活,源代碼開放調試方便,可移植性強可以在不同硬件平臺上進行移植,通過修改可以方便的增加其功能。
在實際生產中,可以通過燒片器等手段將內核、文件系統映像燒入固態存儲設備中,U-Boot不需要具備燒寫功能。但在嵌入式產品開發過程中,為了方便通常在U-Boot中增加燒寫內核、文件系統映像文件等功能,完成向Flash中燒寫文件。在目前的U-Boot官方版本中僅能夠支持Cramfs、Jffs1/2文件系統的燒寫,這些文件系統最初是針對NOR Flash的設計的。現在大容量的NAND Flash使用越來越多,同時由于很多使用NAND Flash的系統,在Linux下都用Yaffs2作為存儲數據的文件系統,甚至是根文件系統,所以在實際開發過程中U-Boot能夠實現燒寫Yaffs2文件系統非常必要。
本次設計的嵌入式手持設備中用到的軟硬件開發平臺為處理器ARM+DSP結構,ARM處理器采用三星公司的S3C2440A,U-Boot為 u-boot-2010.06版本,基于嵌入式Linux操作系統。由于性能上的需要用到了三星大容量NAND Flash芯片,型號為K9K4G08U0M總容量512M,每頁大小為 (2048+64)字節,開發過程中需要使用UBoot燒寫Yaffs2文件系統。
要實現對Yaffs2文件系統的支持,首先要修改U-Boot的NAND Flash讀寫命令,增加燒寫Yaffs2文件系統的命令,其次重要的是實現U-Boot的內存技術設備 (memory technology device,MTD)層的驅動支持,針對大頁NAND Flash的特點增加處理OOB區域數據的功能。MTD是Linux中對ROM、NOR Flash、NAND Flash等存儲設備抽象出來的一個設備層,對Flash操作的接口提供了一系列的標準函數,將硬件驅動設計和系統程序設計分開,硬件驅動人員不用了解存儲設備的組織方法,只需提供標準的函數調用。無論是Jffs2還是Yaffs2[15],還有當NAND Flash進行寫入和擦出操作時,都需要MTD的支持。
在此之前還要針對具體的NAND Flash芯片,對NAND Flash的底層驅動代碼進行必要的修改,使U-Boot支持大容量的NAND Flash。
在U-Boot的源代碼目錄中,首先添加自己的開發板命名為Key2440(可任意設置),然后再添加配置文件include/configs/Key2440.h,并在文件中添加如下宏定義:
#define CONFIG_CMD_NAND_YAFFS2 1
/*支持Yaffs2文件系統*/
#define CONFIG _CMD _NAND _YAFFS2 _SKIPFB 1
/*Yaffs2文件系統特性決定跳過第一個可用的邏輯塊*/
U-Boot的命令為用戶提供了交互功能,并且已經實現了幾十個常用的命令。如果開發板需要很特殊的操作,可以添加新的U-Boot命令。U-Boot的每一個命令都是通過U_Boot_CMD宏定義的,這樣每一個U-Boot命令有一個結構體來描述。在u-boot-2010.06版本中已經可以通過“nand write…”、“nand write.jffs2…”等命令來燒寫內核,燒寫Cramfs、Jffs2文件系統,因此可以仿照此結構添加燒寫Yaffs2文件系統的命令。
3.4.1 修改common/cmd_nand.c文件
(1)先添加 “nand write [.Yaffs2]”命令的使用說明,U-Boot中的命令都在common/cmd_nand.c文件中定義。
U _BOOT _CMD (nand,CONFIG _SYS_MAXARGS,1,do_nand, …….
“nand write [.Yaffs2]addr off size- write the‘size’byte Yaffs2image starting\n” /*Yaffs2的寫命令*/
“at offset‘off’from memory address‘addr’(.Yaffs2 for 2048+64NAND)\n”
(2)修改函數do_nand,添加對 “write[.Yaffs2]”命令的支持,do_nand函數主要是處理與NAND Flash操作相關的命令,負責NAND命令族的區分和執行[16]。
}else if(s!=NULL &&!strcmp (s," .Yaffs2")){if(read)
{printf ("nand read.Yaffs [2]is not provide temporarily!" );}
else{nand->rw_oob=1;/*寫OOB數據區*/
#if defined(CONFIG_CMD_NAND_YAFFS2_SKIPFB)
nand->skipfirstblk=1;/*跳過第一個可用塊*/
#else nand->skipfirstblk=0;
#endif
ret=nand_write_skip_bad (nand,off,&size,(u_char*)addr);
3.4.2 修改include/linux/mtd/mtd.h文件
在修改do_nand時用到了rw_oob和skipfirstblk兩個結構體數據成員,它們是mtd_info結構體中新加的項,mtd_info是用于描述MTD原始設備的數據結構,其中定義了大量關于MTD的數據和操作函數,所以要修改mtd_info結構添加對兩個成員的支持。
struct mtd_in fo{u_int32_t writesize;
u_char rw_oob;
u_char skipfirstblk};
3.5.1 修改drivers/mtd/nand/nand_util.c文件
在文件中添加NAND Flash的OOB區數據的相關操作信息。
/*大頁NAND Flash中ECC校驗碼信息,OOB區為64字節*/
在進一步深化大學英語教學改革的熱潮下,面對本科辦學歷史較短、辦學經驗不足、辦學條件也較有限的辦學實情,新升格本科院校的藝體類本科大學英語教學改革所面臨的壓力和挑戰可想而知。但是,只要切實結合自身的辦學實情,嚴格遵循“分類指導、因材施教”、“動態分層”、“課程教學漸進性、持續性和靈活性”等原則,將分類分層教學模式與課程階段遞進式教學模式、必修課程和選修課程有機結合,勇于實踐和創新,新升格本科院校就一定能開辟出一條獨特的藝體類本科大學英語教學之路,培養出新時期國家和社會所需要的藝體類復合型人才。
static struct nand_ecclayout Yaffs2_ecclayout= {
.useecc= MTD_NANDECC_PLACE,
/*ECC的放置模式*/
.eccbytes=24, /*ECC字節數*/
.eccpos= { 40,41,……62,63 }
/*ECC校驗碼在OOB區中的位置*/
.oobfree= {{2,38}} /*還可被自由使用OOB區域的開始位置和長度*/};
剛才在添加 “nand write[.Yaffs2]”命令的代碼中,調用了nand_write_skip_bad函數,還要對其進行相應修改增加兩部分程序,一部分是為了計算正常數據區的長度;另一部分是為了在寫入一段數據后,數據指針能正確指向下一段數據。
(1)int nand_write_skip_bad (nand_info_t*nand,loff_t offset,size_t*length,u_char*buffer){
#if defined (CONFIG_CMD_NAND_YAFFS2)
/*得到正常數據區的長度*/
if(nand->rw_oob==1)
{size_t oobsize=nand->oobsize;
size_t datasize=nand->writesize;
datapages= *length/ (datasize+oobsize);
*length=datapages*datasize;
left_to_write= *length;
#if!defined (CONFIG_MTD_NAND_YAFFS2)
if(len_incl_bad== *length){
rval=nand_write(nand,offset,length,+buffer);
return rval; }
(2)/*使數據指針指向下一段數據*/
if(nand->rw_oob==1)
p_buffer+=write_size+ (write_size/nand->
writesiz*nand->+oobsize);else p_buffer+= write_size;
3.5.2 修改drivers/mtd/nand/nand_base.c文件
在上步中nand_write_skip_bad函數又對nand_write函數進行了訪問,所以還要對nand_write函數進行修改,添加對Yaffs2的支持。主要是添加兩部分代碼,一部分把正常數據與OOB區數據進行分離;另一部分將寫頁時的模式設置為MTD_OOB_RAW,使寫頁時不再進行ECC值的計算。因為根據Yaffs2文件系統的特性,ECC的校驗值已經包含在了Yaffs2文件系統自帶的OOB區中,不能重寫入。在此模式下,寫入正常數據后會把OOB區緩存的數據寫入NAND Flash的OOB區中。
nand_write函數在drivers/mtd/nand/nand_base.c文件中。
(1)static int nand_write (struct mtd_info*mtd,loff_t to,s ize_t len,size_t*retlen,const uint8_t*buf)
{ if(mtd->rw_oob==1)
{ size_t oobsize= mtd->oobsize;
/*mtd->oobsize是U-Boot初始化NAND Flash時得到的OOB區的大小,本系統中用的是三星K9K4G08U0M芯片OOB區為64字節*/
size_t datasize= mtd->writesize; /*NAND Flash頁大小2KB*/
uint8_t oobtemp [oobsize];/*臨時 OOB區*/
datapages=len/(datasize); /*需用頁數/*
for(i=0;i< (datapages);i++)
/*把正常數據與OOB區數據進行分離*/
{memcpy ((void*)oobtemp,(void*)(buf+datasize* (i+1)),oobsize);
memmove((void*)(buf+datasize* (i+1)),(void*)(buf+datasize* (i+1)+oobsize), (datapages- (i+1))* (datasize)+ (datapages-1)*oobsize);
…….. }}
(2)/*設置模式為MTD_OOB_RAW,使寫頁時不再進行ECC值的計算*/
chip->ops.mode=MTD_OOB_RAW/*模式設置*/
上述對U-Boot代碼的修改其實主要是通過修改U-Boot的NAND Flash讀寫命令,添加讀寫Yaffs2文件系統的命令,并對支持該命令的函數和被調用過的函數進行相應修改,針對大頁NAND Flash和Yaffs2文件系統的特點增加處理OOB區數據的功能,至此U-Boot已經實現了對Yaffs2文件系統的支持。
對U-Boot重新編譯,生成新的U-Boot.bin文件并用JLink工具將其燒入NAND Flash后啟動本系統,在串口工具中能夠看到提示信息,輸入nand info命令可查看到NAND Flash的信息,說明U-Boot識別出了NAND Flash。在U-Boot的命令行中輸入nand help命令,可以看到剛添加的命令nand write[.Yaffs2]addr off size,這樣就可以用它來下載Yaffs2文件系統了。
使用mkyaffs2image工具制作Yaffs2文件系統,手工輸入燒寫命令 Key2440>nand write.Yaffs2 0x30000000 0x50000 0x3625170,燒寫完畢后會提示:
NAND write:device 0offset 0x50000,size 0x3625170 skip the first good block 0x3838600
Bad block at 0x1040000in erase block from 0x1040000 will be skipped
Bad block at 0x1060000in erase block from 0x1060000 will be skipped
……..
Writing data at 0x0x3838600-100%complete
52348128bytes written:OK
說明Yaffs2文件系統已成功下載到NAND Flash中。
Yaffs2文件系統與大容量NAND Flash的結合,能夠加快文件系統的加載速度,實現錯誤檢測、壞塊處理以及可靠地掉電保護。編譯和測試后的結果表明改進后的UBoot可以將Yaffs2文件系統寫入到大容量NAND Flash中,完善了U-Boot的文件燒寫功能。改進后的U-Boot已經成功移植到正在開發的工業用嵌入式手持設備中,這樣可以在大容量NAND Flash中使用Yaffs2文件系統,為設計開發人員帶來了方便,同時產品的性能也得到了提升,在嵌入式系統的開發過程中具有實用價值。
[1]WU Yuxiang,ZHOU Jianxiang,GUO Jianxun.Porting and function expansion of U-boot based on S3C2410 [J].Computer Engineering and Design,2010,31 (14):729-732 (in Chinese). [吳玉香,周建香,郭建勛.U-Boot在S3C2410上的移植及功能擴展 [J].計算機工程與設計,2010,31 (14):729-732.]
[2]Lech Józwiak,Nadia Nedjah,Miguel Figueroa.Modern development methods and tools for embedded reconfigurable systems:a survey[J].Integration the VLSI Journal,2010,43 (1):1-33.
[3]LI Qingcheng,SUN Mingda.Design of NAND flash memorybased embedded file system [J].Application Research of Computers,2006,23 (4):231-233.(in Chinese).[李慶誠,孫明達.基于NAND型閃存的嵌入式文件系統設計 [J].計算機應用研究,2006,23 (4):231-233.]
[4]WEI Dongshan.Complete guide to embedded Linux application development[M].Beijing:Posts & Telecom Press,2008:283-287 (in Chinese).[韋東山.嵌入式Linux應用開發完全手冊 [M].北京:人民郵電出版社,2008:283-287.]
[5]Micron Company.Small block vs.large block NAND flash devices[EB/OL].[2007-01-20].http://www.micron.com.
[6]LI Jun.Detailed embedded Linux device driver development[M].Beijing:Posts & Telecom Press,2008:308-310 (in Chinese).[李俊.嵌入式Linux設備驅動開發詳解 [M].北京:人民郵電出版社,2008:308-310.]
[7]CHUNG Taesun,PARK Dong joo,PARK Sangwon,et al.A survey of flash translation layer [J].Journal of Systems Architecture,2009,55 (5-6):332-343.
[8]ZHANG Jian,WANG Jin.Approach to protect data on taxcontrolled system with ucLinux [J].Computer Engineering and Design,2006,27 (16):3055-3057 (in Chinese). [張健,王錦.基于ucLinux稅控系統的數據保護方案設計 [J].計算機工程與設計,2006,27 (16):3055-3057.]
[9]SUN Feng,ZHANG Fuxing.Resarch and improvement of YAFFS file system [J].Computer Engineering,2008,34(5):257-259 (in Chinese). [孫豐,張福新.YAFFS文件系統的 研 究 與 改 進 [J].計 算 機 工 程,2008,34 (5):257-259.]
[10]WEI Feng,LU Zaiqi,LIU Wei.Realization of YAFFS2in the embedded system [J].Modem Electronics Technique,2010,33 (8):30-34 (in Chinese). [韋峰,盧再奇,劉偉.YAFFS2在嵌入式系統中的實現 [J].現代電子技術,2010,33 (8):30-34.]
[11]LONG Yachun,HUANG Pu,WU Sheng.Create a YAFFS2 bases on super-large NAND flash in Linux [J].Journal of Beijing Electronic Science and Technology Institute,2007,15(2):80-84 (in Chinese).[龍亞春,黃璞,吳勝.超大容量NAND Flash文件系統—YAFFS2在Linux下的實現 [J].北京電子科技學院學報,2007,15 (2):80-84.]
[12]Wookey.YAFFS2specification and development notes [EB/OL].[2005-05-23].http://www.aleph1.co.uk/node/38.
[13]CAI Yong,PENG Fushi.Research on NAND flash system YAFFS [J].Journal of Zhengzhou University of Light Industry(Natural Science),2007,22 (6):54-58 (in Chinese).[蔡勇,彭福石.NAND閃存文件系統YAFFS的研究 [J].鄭州輕工業學院學報 (自然科學版),2007,22 (6):54-58.]
[14]LEE Kiyong,KIM Hyojun,WOO Kyounggu,et al.Design and implementation of MLC NAND flash-based DBMS for mobile devices [J].Journal of Systems and Software,2009,82(9):1447-1458.
[15]LU Chihyuan,Hsieh Kuangyeu,LIU Rich.Future challenges of flash memory technologies [J].Microelectronic Engineering,2009,86 (3):283-286.
[16]The U-boot transplantation mini2440detailed manual [R].Guangzhou:Friendly Arm Technology Co Ltd,2010:75-79(in Chinese). [mini2440之 U-boot移植詳細手冊 [R].廣州:友善之臂科技有限公司,2010:75-79.]