嵌入式設備上的 Linux 系統開(kāi)發(fā)
Linux正在嵌入式開(kāi)發(fā)領(lǐng)域穩步發(fā)展。因為Linux使用GPL(請參閱本文后面的參考資料),所以任何對將Linux定制于PDA、掌上機或者可佩帶設備感興趣的人都可以從因特網(wǎng)免費下載其內核和應用程序,并開(kāi)始移植或開(kāi)發(fā)。許多Linux改良品種迎合了嵌入式/實(shí)時(shí)市場(chǎng)。它們包括RTLinux(實(shí)時(shí)Linux)、uclinux(用于非MMU設備的Linux)、MontavistaLinux(用于A(yíng)RM、MIPS、PPC的Linux分發(fā)版)、ARM-Linux(ARM上的Linux)和其它Linux系統(請參閱參考資料以鏈接到本文中提到的這些和其它術(shù)語(yǔ)及產(chǎn)品。)
嵌入式Linux開(kāi)發(fā)大致涉及三個(gè)層次:引導裝載程序、Linux內核和圖形用戶(hù)界面(或稱(chēng)GUI)。在本文中,我們將集中討論涉及這三層的一些基本概念;深入了解引導裝載程序、內核和文件系統是如何交互的;并將研究可用于文件系統、GUI和引導裝載程序的眾多選項中的一部分。
引導裝載程序
引導裝載程序通常是在任何硬件上執行的第一段代碼。在象臺式機這樣的常規系統中,通常將引導裝載程序裝入主引導記錄(MasterBootRecord,(MBR))中,或者裝入Linux駐留的磁盤(pán)的第一個(gè)扇區中。通常,在臺式機或其它系統上,BIOS將控制移交給引導裝載程序。這就提出了一個(gè)有趣的問(wèn)題:誰(shuí)將引導裝載程序裝入(在大多數情況中)沒(méi)有BIOS的嵌入式設備上呢?
解決這個(gè)問(wèn)題有兩種常規技術(shù):專(zhuān)用軟件和微小的引導代碼(tinybootcode)。
專(zhuān)用軟件可以直接與遠程系統上的閃存設備進(jìn)行交互并將引導裝載程序安裝在閃存的給定位置中。閃存設備是與存儲設備功能類(lèi)似的特殊芯片,而且它們能持久存儲信息D即,在重新引導時(shí)不會(huì )擦除其內容。
這個(gè)軟件使用目標(在嵌入式開(kāi)發(fā)中,嵌入式設備通常被稱(chēng)為目標)上的JTAG端口,它是用于執行外部輸入(通常來(lái)自主機機器)的指令的接口。JFlash-linux是一種用于直接寫(xiě)閃存的流行工具。它支持為數眾多的閃存芯片;它在主機機器(通常是i386機器D本文中我們把一臺i386機器稱(chēng)為主機)上執行并通過(guò)JTAG接口使用并行端口訪(fǎng)問(wèn)目標的閃存芯片。當然,這意味著(zhù)目標需要有一個(gè)并行接口使它能與主機通信。Jflash-linux在Linux和Windows版本中都可使用,可以在命令行中用以下命令啟動(dòng)它:
Jflash-linuxbootloader>
某些種類(lèi)的嵌入式設備具有微小的引導代碼D根據幾個(gè)字節的指令D它將初始化一些DRAM設置并啟用目標上的一個(gè)串行(或者USB,或者以太網(wǎng))端口與主機程序通信。然后,主機程序或裝入程序可以使用這個(gè)連接將引導裝載程序傳送到目標上,并將它寫(xiě)入閃存。
在安裝它并給予其控制后,這個(gè)引導裝載程序執行下列各類(lèi)功能:
初始化CPU速度
初始化內存,包括啟用內存庫、初始化內存配置寄存器等
初始化串行端口(如果在目標上有的話(huà))
啟用指令/數據高速緩存
設置堆棧指針
設置參數區域并構造參數結構和標記(這是重要的一步,因為內核在標識根設備、頁(yè)面大小、內存大小以及更多內容時(shí)要使用引導參數)
執行POST(加電自檢)來(lái)標識存在的設備并報告任何問(wèn)題
為電源管理提供掛起/恢復支持
跳轉到內核的開(kāi)始
帶有引導裝載程序、參數結構、內核和文件系統的系統典型內存布局可能如下所示:
清單1.典型內存布局
/*TopOfMemory*/
Bootloader
ParameterArea
Kernel
Filesystem
/*EndOfMemory*/
嵌入式設備上一些流行的并可免費使用的Linux引導裝載程序有Blob、Redboot和Bootldr(請參閱參考資料獲得鏈接)。所有這些引導裝載程序都用于基于A(yíng)RM設備上的Linux,并需要Jflash-linux工具用于安裝。
一旦將引導裝載程序安裝到目標的閃存中,它就會(huì )執行我們上面提到的所有初始化工作。然后,它準備接收來(lái)自主機的內核和文件系統。一旦裝入了內核,引導裝載程序就將控制轉給內核。
設置工具鏈
設置工具鏈在主機機器上創(chuàng )建一個(gè)用于編譯將在目標上運行的內核和應用程序的構建環(huán)境D這是因為目標硬件可能沒(méi)有與主機兼容的二進(jìn)制執行級別。
工具鏈由一套用于編譯、匯編和鏈接內核及應用程序的組件組成。這些組件包括:
BinutilsD用于操作二進(jìn)制文件的實(shí)用程序集合。它們包括諸如ar、as、objdump、objcopy這樣的實(shí)用程序。
GccDGNUC編譯器。
GlibcD所有用戶(hù)應用程序都將鏈接到的C庫。避免使用任何C庫函數的內核和其它應用程序可以在沒(méi)有該庫的情況下進(jìn)行編譯。
構建工具鏈建立了一個(gè)交叉編譯器環(huán)境。本地編譯器編譯與本機同類(lèi)的處理器的指令。交叉編譯器運行在某一種處理器上,卻可以編譯另一種處理器的指令。重頭設置交叉編譯器工具鏈可不是一項簡(jiǎn)單的任務(wù):它包括下載源代碼、修補補丁、配置、編譯、設置頭文件、安裝以及很多很多的操作。另外,這樣一個(gè)徹底的構建過(guò)程對內存和硬盤(pán)的需求是巨大的。如果沒(méi)有足夠的內存和硬盤(pán)空間,那么在構建階段由于相關(guān)性、配置或頭文件設置等問(wèn)題會(huì )突然冒出許多問(wèn)題。
因此能夠從因特網(wǎng)上獲得已預編譯的二進(jìn)制文件是一件好事(但不太好的一點(diǎn)是,目前它們大多數只限于基于A(yíng)RM的系統,但遲早會(huì )改變的)。一些比較流行的已預編譯的工具鏈包括那些來(lái)自Compaq(FamiliarLinux)、LART(LARTLinux)和Embedian(基于Debian但與它無(wú)關(guān))的工具鏈D所有這些工具鏈都用于基于A(yíng)RM的平臺。
內核設置
Linux社區正積極地為新硬件添加功能部件和支持、在內核中修正錯誤并且及時(shí)地進(jìn)行常規改進(jìn)。這導致大約每6個(gè)月(或6個(gè)月不到)就有一個(gè)穩定的Linux樹(shù)的新發(fā)行版。不同的維護者維護針對特定體系結構的不同內核樹(shù)和補丁。當為一個(gè)項目選擇了一個(gè)內核時(shí),您需要評估最新發(fā)行版的穩定性如何、它是否符合項目要求和硬件平臺、從編程角度來(lái)看它的舒適程度以及其它難以確定的方面。還有一點(diǎn)也非常重要:找到需要應用于基本內核的所有補丁,以便為特定的體系結構調整內核。
內核布局
內核布局分為特定于體系結構的部分和與體系結構無(wú)關(guān)的部分。內核中特定于體系結構的部分首先執行,設置硬件寄存器、配置內存映射、執行特定于體系結構的初始化,然后將控制轉給內核中與體系結構無(wú)關(guān)的部分。系統的其余部分在這第二個(gè)階段期間進(jìn)行初始化。內核樹(shù)下的目錄arch/由不同的子目錄組成,每個(gè)子目錄用于一個(gè)不同的體系結構(MIPS、ARM、i386、SPARC、PPC等)。每一個(gè)這樣的子目錄都包含kernel/和mm/子目錄,它們包含特定于體系結構的代碼來(lái)完成象初始化內存、設置IRQ、啟用高速緩存、設置內核頁(yè)面表等操作。一旦裝入內核并給予其控制,就首先調用這些函數,然后初始化系統的其余部分。
根據可用的系統資源和引導裝載程序的功能,內核可以編譯成vmlinux、Image或zImage。vmlinux和zImage之間的主要區別在于vmlinux是實(shí)際的(未壓縮的)可執行文件,而zImage是或多或少包含相同信息的自解壓壓縮文件D只是壓縮它以處理(通常是Intel強制的)640KB引導時(shí)間的限制。有關(guān)所有這些的權威性解釋?zhuān)垍㈤哃inuxMagazine的文章“KernelConfiguration:dealingwiththeunexpected”(請參閱參考資料)。
內核鏈接和裝入
一旦為目標系統編譯了內核后,通過(guò)使用引導裝載程序(它已經(jīng)被裝入到目標的閃存中),內核就被裝入到目標系統的內存(在DRAM中或者在閃存中)。通過(guò)使用串行、USB或以太網(wǎng)端口,引導裝載程序與主機通信以將內核傳送到目標的閃存或DRAM中。在將內核完全裝入目標后,引導裝載程序將控制傳遞給裝入內核的地址。
內核可執行文件由許多鏈接在一起的對象文件組成。對象文件有許多節,如文本、數據、init數據、bass等等。這些對象文件都是由一個(gè)稱(chēng)為鏈接器腳本的文件鏈接并裝入的。這個(gè)鏈接器腳本的功能是將輸入對象文件的各節映射到輸出文件中;換句話(huà)說(shuō),它將所有輸入對象文件都鏈接到單一的可執行文件中,將該可執行文件的各節裝入到指定地址處。vmlinux.lds是存在于arch/target>/目錄中的內核鏈接器腳本,它負責鏈接內核的各個(gè)節并將它們裝入內存中特定偏移量處。典型的vmlinux.lds看起來(lái)象這樣:
清單2.典型的vmlinux.lds文件
OUTPUT_ARCH(arch>)/*arch>includesarchitecturetype*/
ENTRY(stext)/*stextisthekernelentrypoint*/
SECTIONS/*SECTIONScommanddescribesthelayout
oftheoutputfile*/
{
.=TEXTADDR;/*TEXTADDRisLMAforthekernel*/
.init:{/*Initcodeanddata*/
_stext=.;/*Firstsectionisstextfollowed
by__initdatasection*/
__init_begin=.;
*(.text.init)
__init_end=.;
}
.text:{/*Realtextsegmentfollows__init_datasection*/
_text=.;
*(.text)
_etext=.;/*Endoftextsection*/
}
.data:{
_data=.;/*Datasectioncomesaftertextsection*/
*(.data)
_edata=.;
}/*Datasectionendshere*/
.bss:{/*BSSsectionfollowssymboltablesection*/
__bss_start=.;
*(.bss)
_end=.;/*BSSsectionendshere*/
}
}
LMA是裝入模塊地址;它表示將要裝入內核的目標虛擬內存中的地址。TEXTADDR是內核的虛擬起始地址,并且在arch/target>/下的Makefile中指定它的值。這個(gè)地址必須與引導裝載程序使用的地址相匹配。
一旦引導裝載程序將內核復制到閃存或DRAM中,內核就被重新定位到TEXTADDR―它通常在DRAM中。然后,引導裝載程序將控制轉給這個(gè)地址,以便內核能開(kāi)始執行。
參數傳遞和內核引導
stext是內核入口點(diǎn),這意味著(zhù)在內核引導時(shí)將首先執行這一節下的代碼。它通常用匯編語(yǔ)言編寫(xiě),并且通常它在arch/target>/內核目錄下。這個(gè)代碼設置內核頁(yè)面目錄、創(chuàng )建身份內核映射、標識體系結構和處理器以及執行分支start_kernel(初始化系統的主例程)。
start_kernel調用setup_arch作為執行的第一步,在其中完成特定于體系結構的設置。這包括初始化硬件寄存器、標識根設備和系統中可用的DRAM和閃存的數量、指定系統中可用頁(yè)面的數目、文件系統大小等等。所有這些信息都以參數形式從引導裝載程序傳遞到內核。
將參數從引導裝載程序傳遞到內核有兩種方法:parameter_structure和標記列表。在這兩種方法中,不贊成使用參數結構,因為它強加了限制:指定在內存中,每個(gè)參數必須位于param_struct中的特定偏移量處。最新的內核期望參數作為標記列表的格式來(lái)傳遞,并將參數轉化為已標記格式。param_struct定義在include/asm/setup.h中。它的一些重要字段是:
清單3.樣本參數結構
structparam_struct{
unsignedlongpage_size;/*0:Sizeofthepage*/
unsignedlongnr_pages;/*4:Numberofpagesinthesystem*/
unsignedlongramdisk/*8:ramdisksize*/
unsignedlongrootdev;/*16:Numberrepresentingtherootdevice*/
unsignedlonginitrd_start;/*64:startingaddressofinitialramdisk*/
/*Thiscanbeeitherinflash/dram*/
unsignedlonginitrd_size;/*68:sizeofinitialramdisk*/
}
請注意:這些數表示定義字段的參數結構中的偏移量。這意味著(zhù)如果引導裝載程序將參數結構放置在地址0xc0000100,那么rootdev參數將放置在0xc0000100+16,initrd_start將放置在0xc0000100+64等等D否則,內核將在解釋正確的參數時(shí)遇到困難。
正如上面提到的,因為從引導裝載程序到內核的參數傳遞會(huì )有一些約束條件,所以大多數2.4.x系列內核期望參數以已標記的列表格式傳遞。在已標記的列表中,每個(gè)標記由標識被傳遞參數的tag_header以及其后的參數值組成。標記列表中標記的常規格式可以如下所示:
清單4.樣本標記格式。內核通過(guò)ATAG_TAGNAME>頭來(lái)標識每個(gè)標記。
#defineaTAG_TAGNAME>SomeMagicnumber>
structtag_tagname>{
u32tag_param>;
u32tag_param>;
};
/*Exampletagforpassingmemoryinformation*/
#defineATAG_MEM0x54410002/*Magicnumber*/
structtag_mem32{
u32size;/*sizeofmemory*/
u32start;/*physicalstartaddressofmemory*/
};
setup_arch還需要對閃存存儲庫、系統寄存器和其它特定設備執行內存映射。一旦完成了特定于體系結構的設置,控制就返回到初始化系統其余部分的start_kernel函數。這些附加的初始化任務(wù)包含:
設置陷阱
初始化中斷
初始化計時(shí)器
初始化控制臺
調用mem_init,它計算各種區域、高內存區等內的頁(yè)面數量
初始化slab分配器并為VFS、緩沖區高速緩存等創(chuàng )建slab高速緩存
建立各種文件系統,如proc、ext2和JFFS2
創(chuàng )建kernel_thread,它執行文件系統中的init命令并顯示lign提示符。如果在/bin、/sbin或/etc中沒(méi)有init程序,那么內核將執行文件系統的/bin中的shell。
設備驅動(dòng)程序
嵌入式系統通常有許多設備用于與用戶(hù)交互,象觸摸屏、小鍵盤(pán)、滾動(dòng)輪、傳感器、RA232接口、LCD等等。除了這些設備外,還有許多其它專(zhuān)用設備,包括閃存、USB、GSM等。內核通過(guò)所有這些設備各自的設備驅動(dòng)程序來(lái)控制它們,包括GUI用戶(hù)應用程序也通過(guò)訪(fǎng)問(wèn)這些驅動(dòng)程序來(lái)訪(fǎng)問(wèn)設備。本節著(zhù)重討論通常幾乎在每個(gè)嵌入式環(huán)境中都會(huì )使用的一些重要設備的設備驅動(dòng)程序。
幀緩沖區驅動(dòng)程序
這是最重要的驅動(dòng)程序之一,因為通過(guò)這個(gè)驅動(dòng)程序才能使系統屏幕顯示內容。幀緩沖區驅動(dòng)程序通常有三層。最底層是基本控制臺驅動(dòng)程序drivers/char/console.c,它提供了文本控制臺常規接口的一部分。通過(guò)使用控制臺驅動(dòng)程序函數,我們能將文本打印到屏幕上D但圖形或動(dòng)畫(huà)還不能(這樣做需要使用視頻模式功能,通常出現在中間層,也就是drivers/video/fbcon.c中)。這個(gè)第二層驅動(dòng)程序提供了視頻模式中繪圖的常規接口。
幀緩沖區是顯卡上的內存,需要將它內存映射到用戶(hù)空間以便可以將圖形和文本能寫(xiě)到這個(gè)內存段上:然后這個(gè)信息將反映到屏幕上。幀緩沖區支持提高了繪圖的速度和整體性能。這也是頂層驅動(dòng)程序引人注意之處:頂層是非常特定于硬件的驅動(dòng)程序,它需要支持顯卡不同的硬件方面D象啟用/禁用顯卡控制器、深度和模式的支持以及調色板等。所有這三層都相互依賴(lài)以實(shí)現正確的視頻功能。與幀緩沖區有關(guān)的設備是/dev/fb0(主設備號29,次設備號0)。
輸入設備驅動(dòng)程序
可觸摸板是用于嵌入式設備的最基本的用戶(hù)交互設備之一D小鍵盤(pán)、傳感器和滾動(dòng)輪也包含在許多不同設備中以用于不同的用途。
觸摸板設備的主要功能是隨時(shí)報告用戶(hù)的觸摸,并標識觸摸的坐標。這通常在每次發(fā)生觸摸時(shí),通過(guò)生成一個(gè)中斷來(lái)實(shí)現。
然后,這個(gè)設備驅動(dòng)程序的角色是每當出現中斷時(shí)就查詢(xún)觸摸屏控制器,并請求控制器發(fā)送觸摸的坐標。一旦驅動(dòng)程序接收到坐標,它就將有關(guān)觸摸和任何可用數據的信號發(fā)送給用戶(hù)應用程序,并將數據發(fā)送給應用程序(如果可能的話(huà))。然后用戶(hù)應用程序根據它的需要處理數據。
幾乎所有輸入設備D包括小鍵盤(pán)D都以類(lèi)似原理工作。
閃存MTD驅動(dòng)程序
MTD設備是象閃存芯片、小型閃存卡、記憶棒等之類(lèi)的設備,它們在嵌入式設備中的使用正在不斷增長(cháng)。
MTD驅動(dòng)程序是在Linux下專(zhuān)門(mén)為嵌入式環(huán)境開(kāi)發(fā)的新的一類(lèi)驅動(dòng)程序。相對于常規塊設備驅動(dòng)程序,使用MTD驅動(dòng)程序的主要優(yōu)點(diǎn)在于MTD驅動(dòng)程序是專(zhuān)門(mén)為基于閃存的設備所設計的,所以它們通常有更好的支持、更好的管理和基于扇區的擦除和讀寫(xiě)操作的更好的接口。Linux下的MTD驅動(dòng)程序接口被劃分為兩類(lèi)模塊:用戶(hù)模塊和硬件模塊。
用戶(hù)模塊
這些模塊提供從用戶(hù)空間直接使用的接口:原始字符訪(fǎng)問(wèn)、原始塊訪(fǎng)問(wèn)、FTL(閃存轉換層,FlashTransitionLayerD用在閃存上的一種文件系統)和JFS(即日志文件系統,JournaledFileSystemD在閃存上直接提供文件系統而不是模擬塊設備)。用于閃存的JFS的當前版本是JFFS2(稍后將在本文中描述)。
硬件模塊
這些模塊提供對內存設備的物理訪(fǎng)問(wèn),但并不直接使用它們。通過(guò)上述的用戶(hù)模塊來(lái)訪(fǎng)問(wèn)它們。這些模塊提供了在閃存上讀、擦除和寫(xiě)操作的實(shí)際例程。
MTD驅動(dòng)程序設置
為了訪(fǎng)問(wèn)特定的閃存設備并將文件系統置于其上,需要將MTD子系統編譯到內核中。這包括選擇適當的MTD硬件和用戶(hù)模塊。當前,MTD子系統支持為數眾多的閃存設備D并且有越來(lái)越多的驅動(dòng)程序正被添加進(jìn)來(lái)以用于不同的閃存芯片。
有兩個(gè)流行的用戶(hù)模塊可啟用對閃存的訪(fǎng)問(wèn):MTD_CHAR和MTD_BLOCK。
MTD_CHAR提供對閃存的原始字符訪(fǎng)問(wèn),而MTD_BLOCK將閃存設計為可以在上面創(chuàng )建文件系統的常規塊設備(象IDE磁盤(pán))。與MTD_CHAR關(guān)聯(lián)的設備是/dev/mtd0、mtd1、mtd2(等等),而與MTD_BLOCK關(guān)聯(lián)的設備是/dev/mtdblock0、mtdblock1(等等)。由于MTD_BLOCK設備提供象塊設備那樣的模擬,通常更可取的是在這個(gè)模擬基礎上創(chuàng )建象FTL和JFFS2那樣的文件系統。
為了進(jìn)行這個(gè)操作,可能需要創(chuàng )建分區表將閃存設備分拆到引導裝載程序節、內核節和文件系統節中。樣本分區表可能包含以下信息:
清單5.MTD的簡(jiǎn)單閃存設備分區
structmtd_partitionsample_partition={
{
/*Firstpartition*/
name:bootloader,/*Bootloadersection*/
size:0x00010000,/*Size*/
offset:0,/*Offsetfromstartofflash-location0x0*/
mask_flags:MTD_WRITEABLE/*Thispartitionisnotwritable*/
},
{/*Secondpartition*/
name:Kernel,/*Kernelsection*/
size:0x00100000,/*Size*/
offset:MTDPART_OFS_APPEND,/*Appendafterbootloadersection*/
mask_flags:MTD_WRITEABLE/*Thispartitionisnotwritable*/
},
{/*Thirdpartition*/
name:JFFS2,/*JFFS2filesystem*/
size:MTDPART_SIZ_FULL,/*Occupyrestofflash*/
offset:MTDPART_OFS_APPEND/*Appendafterkernelsection*/
}
}
上面的分區表使用了MTD_BLOCK接口對閃存設備進(jìn)行分區。這些分區的設備節點(diǎn)是:
簡(jiǎn)單閃存分區的設備節點(diǎn)
UserdevicenodeMajornumberMinornumber
Bootloader/dev/mtdblock0310
Kernel/dev/mtdblock1311
Filesystem/dev/mtdblock2312
在本例中,引導裝載程序必須將有關(guān)root設備節點(diǎn)(/dev/mtdblock2)和可以在閃存中找到文件系統的地址(本例中是FLASH_BASE_ADDRESS+0x04000000)的正確參數傳遞到內核。一旦完成分區,閃存設備就準備裝入或掛裝文件系統。
Linux中MTD子系統的主要目標是在系統的硬件驅動(dòng)程序和上層,或用戶(hù)模塊之間提供通用接口。硬件驅動(dòng)程序不需要知道象JFFS2和FTL那樣的用戶(hù)模塊使用的方法。所有它們真正需要提供的就是一組對底層閃存系統進(jìn)行read、write和erase操作的簡(jiǎn)單例程。
嵌入式設備的文件系統
系統需要一種以結構化格式存儲和檢索信息的方法;這就需要文件系統的參與。Ramdisk(請參閱參考資料)是通過(guò)將計算機的RAM用作設備來(lái)創(chuàng )建和掛裝文件系統的一種機制,它通常用于無(wú)盤(pán)系統(當然包括微型嵌入式設備,它只包含作為永久存儲媒質(zhì)的閃存芯片)。
用戶(hù)可以根據可靠性、健壯性和/或增強的功能的需求來(lái)選擇文件系統的類(lèi)型。下一節將討論幾個(gè)可用選項及其優(yōu)缺點(diǎn)。
第二版擴展文件系統(Ext2fs)
Ext2fs是Linux事實(shí)上的標準文件系統,它已經(jīng)取代了它的前任D擴展文件系統(或Extfs)。Extfs支持的文件大小最大為2GB,支持的最大文件名稱(chēng)大小為255個(gè)字符D而且它不支持索引節點(diǎn)(包括數據修改時(shí)間標記)。Ext2fs做得更好;它的優(yōu)點(diǎn)是:
Ext2fs支持達4TB的內存。
Ext2fs文件名稱(chēng)最長(cháng)可以到1012個(gè)字符。
當創(chuàng )建文件系統時(shí),管理員可以選擇邏輯塊的大?。ㄍǔ4笮】蛇x擇1024、2048和4096字節)。
Ext2fs了實(shí)現快速符號鏈接:不需要為此目的而分配數據塊,并且將目標名稱(chēng)直接存儲在索引節點(diǎn)(inode)表中。這使性能有所提高,特別是在速度上。
因為Ext2文件系統的穩定性、可靠性和健壯性,所以幾乎在所有基于Linux的系統(包括臺式機、服務(wù)器和工作站D并且甚至一些嵌入式設備)上都使用Ext2文件系統。然而,當在嵌入式設備中使用Ext2fs時(shí),它有一些缺點(diǎn):
Ext2fs是為象IDE設備那樣的塊設備設計的,這些設備的邏輯塊大小是512字節,1K字節等這樣的倍數。這不太適合于扇區大小因設備不同而不同的閃存設備。
Ext2文件系統沒(méi)有提供對基于扇區的擦除/寫(xiě)操作的良好管理。在Ext2fs中,為了在一個(gè)扇區中擦除單個(gè)字節,必須將整個(gè)扇區復制到RAM,然后擦除,然后重寫(xiě)入??紤]到閃存設備具有有限的擦除壽命(大約能進(jìn)行100,000次擦除),在此之后就不能使用它們,所以這不是一個(gè)特別好的方法。
在出現電源故障時(shí),Ext2fs不是防崩潰的。
Ext2文件系統不支持損耗平衡,因此縮短了扇區/閃存的壽命。(損耗平衡確保將地址范圍的不同區域輪流用于寫(xiě)和/或擦除操作以延長(cháng)閃存設備的壽命。)
Ext2fs沒(méi)有特別完美的扇區管理,這使設計塊驅動(dòng)程序十分困難。
由于這些原因,通常相對于Ext2fs,在嵌入式環(huán)境中使用MTD/JFFS2組合是更好的選擇。
用Ramdisk掛裝Ext2fs
通過(guò)使用Ramdisk的概念,可以在嵌入式設備中創(chuàng )建并掛裝Ext2文件系統(以及用于這一目的的任何文件系統)。
清單6.創(chuàng )建一個(gè)簡(jiǎn)單的基于Ext2fs的Ramdisk
mke2fs-vm0/dev/ram4096
mount-text2/dev/ram/mnt
cd/mnt
cp/bin,/sbin,/etc,/dev...filesinmnt
cd../
umount/mnt
ddif=/dev/rambs=1kcount=4096of=ext2ramdisk
mke2fs是用于在任何設備上創(chuàng )建ext2文件系統的實(shí)用程序―它創(chuàng )建超級塊、索引節點(diǎn)以及索引節點(diǎn)表等等。
在上面的用法中,/dev/ram是上面構建有4096個(gè)塊的ext2文件系統的設備。然后,將這個(gè)設備(/dev/ram)掛裝在名為/mnt的臨時(shí)目錄上并且復制所有必需的文件。一旦復制完這些文件,就卸裝這個(gè)文件系統并且設備(/dev/ram)的內容被轉儲到一個(gè)文件(ext2ramdisk)中,它就是所需的Ramdisk(Ext2文件系統)。
上面的順序創(chuàng )建了一個(gè)4MB的Ramdisk,并用必需的文件實(shí)用程序來(lái)填充它。
一些要包含在Ramdisk中的重要目錄是:
/binD保存大多數象init、busybox、shell、文件管理實(shí)用程序等二進(jìn)制文件。
/devD包含用在設備中的所有設備節點(diǎn)
/etcD包含系統的所有配置文件
/libD包含所有必需的庫,如libc、libdl等
日志閃存文件系統,版本2(JFFS2)
瑞典的AxisCommunications開(kāi)發(fā)了最初的JFFS,RedHat的DavidWoodhouse對它進(jìn)行了改進(jìn)。第二個(gè)版本,JFFS2,作為用于微型嵌入式設備的原始閃存芯片的實(shí)際文件系統而出現。JFFS2文件系統是日志結構化的,這意味著(zhù)它基本上是一長(cháng)列節點(diǎn)。每個(gè)節點(diǎn)包含有關(guān)文件的部分信息D可能是文件的名稱(chēng)、也許是一些數據。相對于Ext2fs,JFFS2因為有以下這些優(yōu)點(diǎn)而在無(wú)盤(pán)嵌入式設備中越來(lái)越受歡迎:
JFFS2在扇區級別上執行閃存擦除/寫(xiě)/讀操作要比Ext2文件系統好。
JFFS2提供了比Ext2fs更好的崩潰/掉電安全保護。當需要更改少量數據時(shí),Ext2文件系統將整個(gè)扇區復制到內存(DRAM)中,在內存中合并新數據,并寫(xiě)回整個(gè)扇區。這意味著(zhù)為了更改單個(gè)字,必須對整個(gè)扇區(64KB)執行讀/擦除/寫(xiě)例程D這樣做的效率非常低。要是運氣差,當正在DRAM中合并數據時(shí),發(fā)生了電源故障或其它事故,那么將丟失整個(gè)數據集合,因為在將數據讀入DRAM后就擦除了閃存扇區。JFFS2附加文件而不是重寫(xiě)整個(gè)扇區,并且具有崩潰/掉電安全保護這一功能。
這可能是最重要的一點(diǎn):JFFS2是專(zhuān)門(mén)為象閃存芯片那樣的嵌入式設備創(chuàng )建的,所以它的整個(gè)設計提供了更好的閃存管理。
因為本文主要是寫(xiě)關(guān)于閃存設備的使用,所以在嵌入式環(huán)境中使用JFFS2的缺點(diǎn)很少:
當文件系統已滿(mǎn)或接近滿(mǎn)時(shí),JFFS2會(huì )大大放慢運行速度。這是因為垃圾收集的問(wèn)題(更多信息,請參閱參考資料)。
創(chuàng )建JFFS2文件系統
在Linux下,用mkfs.jffs2命令創(chuàng )建JFFS2文件系統(基本上是使用JFFS2的Ramdisk)。
清單7.創(chuàng )建JFFS2文件系統
mkdirjffsfile
cdjffsfile
/*copyallthe/bin,/etc,/usr/bin,/sbin/binariesand/deventries
thatareneededforthefilesystemhere*/
/*TypethefollowingcommandunderjffsfiledirectorytocreatetheJFFS2Image*/
./mkfs.jffs2-e0x40000-p-o../jffs.image
上面顯示了mkfs.jffs2的典型用法。-e選項確定閃存的擦除扇區大?。ㄍǔJ?4千字節)。-p選項用來(lái)在映像的剩余空間用零填充。-o選項用于輸出文件,通常是JFFS2文件系統映像D在本例中是jffs.image。一旦創(chuàng )建了JFFS2文件系統,它就被裝入閃存中適當的位置(引導裝載程序告知內核查找文件系統的地址)以便內核能掛裝它。
tmpfs
當Linux運行于嵌入式設備上時(shí),該設備就成為功能齊全的單元,許多守護進(jìn)程會(huì )在后臺運行并生成許多日志消息。另外,所有內核日志記錄機制,象syslogd、dmesg和klogd,會(huì )在/var和/tmp目錄下生成許多消息。由于這些進(jìn)程產(chǎn)生了大量數據,所以允許將所有這些寫(xiě)操作都發(fā)生在閃存是不可取的。由于在重新引導時(shí)這些消息不需要持久存儲,所以這個(gè)問(wèn)題的解決方案是使用tmpfs。
tmpfs是基于內存的文件系統,它主要用于減少對系統的不必要的閃存寫(xiě)操作這一唯一目的。因為tmpfs駐留在RAM中,所以寫(xiě)/讀/擦除的操作發(fā)生在RAM中而不是在閃存中。因此,日志消息寫(xiě)入RAM而不是閃存中,在重新引導時(shí)不會(huì )保留它們。tmpfs還使用磁盤(pán)交換空間來(lái)存儲,并且當為存儲文件而請求頁(yè)面時(shí),使用虛擬內存(VM)子系統。
tmpfs的優(yōu)點(diǎn)包括:
動(dòng)態(tài)文件系統大小D文件系統大小可以根據被復制、創(chuàng )建或刪除的文件或目錄的數量來(lái)縮放。使得能夠最理想地使用內存。
速度D因為tmpfs駐留在RAM,所以讀和寫(xiě)幾乎都是瞬時(shí)的。即使以交換的形式存儲文件,I/O操作的速度仍非???。
tmpfs的一個(gè)缺點(diǎn)是當系統重新引導時(shí)會(huì )丟失所有數據。因此,重要的數據不能存儲在tmpfs上。
掛裝tmpfs
諸如Ext2fs和JFFS2等大多數其它文件系統都駐留在底層塊設備之上,而tmpfs與它們不同,它直接位于VM上。因而,掛裝tmpfs文件系統是很簡(jiǎn)單的事:
清單8.掛裝tmpfs
/*Entriesin/etc/rc.d/rc.sysinitforcreating/usingtmpfs*/
#mount-ttmpfstmpfs/var-osize=512k
#mkdir-p/var/tmp
#mkdir-p/var/log
#ln-s/var/tmp/tmp
上面的命令將在/var上創(chuàng )建tmpfs并將tmpfs的最大大小限制為512K。同時(shí),tmp/和log/目錄成為tmpfs的一部分以便在RAM中存儲日志消息。
如果您想將tmpfs的一個(gè)項添加到/etc/fstab,那么它可能看起來(lái)象這樣:tmpfs/vartmpfssize=32m00
這將在/var上掛裝一個(gè)新的tmpfs文件系統。
圖形用戶(hù)界面(GUI)選項
從用戶(hù)的觀(guān)點(diǎn)來(lái)看,圖形用戶(hù)界面(GUI)是系統的一個(gè)最至關(guān)重要的方面:用戶(hù)通過(guò)GUI與系統進(jìn)行交互。所以GUI應該易于使用并且非??煽?。但它還需要是有內存意識的,以便在內存受限的、微型嵌入式設備上可以無(wú)縫執行。所以,它應該是輕量級的,并且能夠快速裝入。
另一個(gè)要考慮的重要方面涉及許可證問(wèn)題。一些GUI分發(fā)版具有允許免費使用的許可證,甚至在一些商業(yè)產(chǎn)品中也是如此。另一些許可證要求如果想將GUI合并入項目中則要支付版稅。
最后,大多數開(kāi)發(fā)人員可能會(huì )選擇XFree86,因為XFree86為他們提供了一個(gè)能使用他們喜歡的工具的熟悉環(huán)境。但是市場(chǎng)上較新的GUI,象CenturySoftware的Microwindows(Nano-X)和Trolltech的QT/Embedded,與X在嵌入式Linux的競技舞臺中展開(kāi)了激烈競爭,這主要是因為它們占用很少的資源、執行的速度很快并且具有定制窗口構件的支持。
讓我們看一看這些選項中的每一個(gè)。
Xfree864.X(帶幀緩沖區支持的X11R6.4)
XFree86Project,Inc.是一家生產(chǎn)XFree86的公司,該產(chǎn)品是一個(gè)可以免費重復分發(fā)、開(kāi)放源碼的XWindow系統。XWindow系統(X11)為應用程序以圖形方式進(jìn)行顯示提供了資源,并且它是UNIX和類(lèi)UNIX的機器上最常用的窗口系統。它很小但很有效,它運行在為數眾多的硬件上,它對網(wǎng)絡(luò )透明并且有良好的文檔說(shuō)明。X11為窗口管理、事件處理、同步和客戶(hù)機間通信提供強大的功能D并且大多數開(kāi)發(fā)人員已經(jīng)熟悉了它的API。它具有對內核幀緩沖區的內置支持,并占用非常少的資源D這非常有助于內存相對較少的設備。X服務(wù)器支持VGA和非VGA圖形卡,它對顏色深度1、2、4、8、16和32提供支持,并對渲染提供內置支持。最新的發(fā)行版是XFree864.1.0。
它的優(yōu)點(diǎn)包括:
幀緩沖區體系結構的使用提高了性能。
占用的資源相對很小D大小在600K到700K字節的范圍內,這使它很容易在小型設備上運行。
非常好的支持:在線(xiàn)有許多文檔可用,還有許多專(zhuān)用于XFree86開(kāi)發(fā)的郵遞列表。
XAPI非常適合擴展。
它的缺點(diǎn)包括:
比最近出現的嵌入式GUI工具性能差。
此外,當與GUI中最新的開(kāi)發(fā)D象專(zhuān)門(mén)為嵌入式環(huán)境設計的Nano-X或QT/EmbeddedD相比時(shí),XFree86似乎需要更多的內存。
Microwindows
Microwindows是CenturySoftware的開(kāi)放源代碼項目,設計用于帶小型顯示單元的微型設備。它有許多針對現代圖形視窗環(huán)境的功能部件。象X一樣,有多種平臺支持Microwindows。
Microwindows體系結構是基于客戶(hù)機/服務(wù)器的并且具有分層設計。最底層是屏幕和輸入設備驅動(dòng)程序(關(guān)于鍵盤(pán)或鼠標)來(lái)與實(shí)際硬件交互。在中間層,可移植的圖形引擎提供對線(xiàn)的繪制、區域的填充、多邊形、裁剪以及顏色模型的支持。
在最上層,Microwindows支持兩種API:Win32/WinCEAPI實(shí)現,稱(chēng)為Microwindows;另一種API與GDK非常相似,它稱(chēng)為Nano-X。Nano-X用在Linux上。它是象X的API,用于占用資源少的應用程序。
Microwindows支持1、2、4和8bpp(每像素的位數)的palletized顯示,以及8、16、24和32bpp的真彩色顯示。Microwindows還支持使它速度更快的幀緩沖區。Nano-X服務(wù)器占用的資源大約在100K到150K字節。
原始Nano-X應用程序的平均大小在30K到60K。由于Nano-X是為有內存限制的低端設備設計的,所以它不象X那樣支持很多函數,因此它實(shí)際上不能作為微型X(Xfree864.1)的替代品。
可以在Microwindows上運行FLNX,它是針對Nano-X而不是X進(jìn)行修改的FLTK(快速輕巧工具箱(FastLightToolkit))應用程序開(kāi)發(fā)環(huán)境的一個(gè)版本。本文中描述FLTK。
Nano-X的優(yōu)點(diǎn)包括:
與Xlib實(shí)現不同,Nano-X仍在每個(gè)客戶(hù)機上同步運行,這意味著(zhù)一旦發(fā)送了客戶(hù)機請求包,服務(wù)器在為另一個(gè)客戶(hù)機提供服務(wù)之前一直等待,直到整個(gè)包都到達為止。這使服務(wù)器代碼非常簡(jiǎn)單,而運行的速度仍非???。
占用很小的資源
Nano-X的缺點(diǎn)包括:
聯(lián)網(wǎng)功能部件至今沒(méi)有經(jīng)過(guò)適當地調整(特別是網(wǎng)絡(luò )透明性)。
還沒(méi)有太多現成的應用程序可用。
與X相比,Nano-X雖然近來(lái)正在加速開(kāi)發(fā),但仍沒(méi)有那么多文檔說(shuō)明而且沒(méi)有很好的支持,但這種情形會(huì )有所改變。
Microwindows上的FLTKAPI
FLTK是一個(gè)簡(jiǎn)單但靈活的GUI工具箱,它在Linux世界中贏(yíng)得越來(lái)越多的關(guān)注,它特別適用于占用資源很少的環(huán)境。它提供了您期望從GUI工具箱中獲得的大多數窗口構件,如按鈕、對話(huà)框、文本框以及出色的“賦值器”選擇(用于輸入數值的窗口構件)。還包括滑動(dòng)器、滾動(dòng)條、刻度盤(pán)和其它一些構件。
針對MicrowindowsGUI引擎的FLTK的Linux版本被稱(chēng)為FLNX。FLNX由兩個(gè)組件構成:Fl_Widget和FLUID。Fl_Widget由所有基本窗口構件API組成。FLUID(快速輕巧的用戶(hù)界面設計器(FastLightUserInterfaceDesigner,FLUID))是用來(lái)產(chǎn)生FLTK源代碼的圖形編輯器??偟膩?lái)說(shuō),FLNX是能用來(lái)為嵌入式環(huán)境創(chuàng )建應用程序的一個(gè)出色的UI構建器。
Fl_Widget占用的資源大約是40K到48K,而FLUID(包括了每個(gè)窗口構件)大約占用380K。這些非常小的資源占用率使Fl_Widget和FLUID在嵌入式開(kāi)發(fā)世界中非常受歡迎。
優(yōu)點(diǎn)包括:
習慣于在象Windows這樣已建立得較好的環(huán)境中開(kāi)發(fā)基于GUI的應用程序的任何人都會(huì )非常容易地適應FLTK環(huán)境。
它的文檔包括一本十分完整且編寫(xiě)良好的手冊。
它使用LGPL進(jìn)行分發(fā),所以開(kāi)發(fā)人員可以靈活地發(fā)放他們應用程序的許可證。
FLTK是一個(gè)C++庫(Perl和Python綁定也可用)。面向對象模型的選擇是一個(gè)好的選擇,因為大多數現代GUI環(huán)境都是面向對象的;這也使將編寫(xiě)的應用程序移植到類(lèi)似的API中變得更容易。
CenturySoftware的環(huán)境提供了幾個(gè)有用的工具,諸如ScreenToP和ViewML瀏覽器。
它的缺點(diǎn)是:
普通的FLTK可以與X和WindowsAPI一同工作,而FLNX不能。它與X的不兼容性阻礙了它在許多項目中的使用。
Qt/Embedded
Qt/Embedded是Trolltech新開(kāi)發(fā)的用于嵌入式Linux的圖形用戶(hù)界面系統。Trolltech最初創(chuàng )建Qt作為跨平臺的開(kāi)發(fā)工具用于Linux臺式機。它支持各種有UNIX特點(diǎn)的系統以及MicrosoftWindows。KDED最流行的Linux桌面環(huán)境之一,就是用Qt編寫(xiě)的。
Qt/Embedded以原始Qt為基礎,并做了許多出色的調整以適用于嵌入式環(huán)境。QtEmbedded通過(guò)QtAPI與LinuxI/O設施直接交互。那些熟悉并已適應了面向對象編程的人員將發(fā)現它是一個(gè)理想環(huán)境。而且,面向對象的體系結構使代碼結構化、可重用并且運行快速。與其它GUI相比,QtGUI非???,并且它沒(méi)有分層,這使得Qt/Embedded成為用于運行基于Qt的程序的最緊湊環(huán)境。
Trolltech還推出了Qt掌上機環(huán)境(QtPalmtopEnvironment,俗稱(chēng)Qpe)。Qpe提供了一個(gè)基本桌面窗口,并且該環(huán)境為開(kāi)發(fā)提供了一個(gè)易于使用的界面。Qpe包含全套的個(gè)人信息管理(PersonalInformationManagement(PIM))應用程序、因特網(wǎng)客戶(hù)機、實(shí)用程序等等。然而,為了將Qt/Embedded或Qpe集成到一個(gè)產(chǎn)品中,需要從Trolltech獲得商業(yè)許可證。(原始Qt自版本2.2以后就可以根據GPL獲得。)
它的優(yōu)點(diǎn)包括:
面向對象的體系結構有助于更快地執行
占用很少的資源,大約800K
抗鋸齒文本和混合視頻的象素映射
它的缺點(diǎn)是:
Qt/Embedded和Qpe只能在獲得商業(yè)許可證的情況下才能使用。
結束語(yǔ)
嵌入式Linux開(kāi)發(fā)正迅速地發(fā)展著(zhù)。您必須學(xué)習并從引導裝載程序和分發(fā)版到文件系統和GUI中的每一個(gè)事物的各種選項中作出選擇。但是要感謝有這種選擇自由度以及非?;钴S的Linux社區,Linux上的嵌入式開(kāi)發(fā)已經(jīng)達到了新的境界,并且調整模塊以適合您的規范從未比現在更簡(jiǎn)單。這已經(jīng)導致出現了許多時(shí)新的手持和微型設備作為開(kāi)放盒,這是件好事D因為事實(shí)是您不必成為一個(gè)專(zhuān)家從這些模塊中進(jìn)行選擇來(lái)調整您的設備以滿(mǎn)足您自己的要求和需要。
我們希望這篇對嵌入式Linux領(lǐng)域的介紹性概述能激起您進(jìn)行試驗的欲望,并且希望您將體會(huì )擺弄微型設備的樂(lè )趣以滿(mǎn)足您的愛(ài)好。為進(jìn)一步有助于您的項目,請參閱下面的“參考資料”,鏈接到有關(guān)我們這里已經(jīng)概述的技術(shù)的更深入的信息。
評論