級別: 初級
Anand K Santhanam (mailto:asanthan@in.ibm.com?subject=嵌入式設備上的 Linux 系統開發&cc=asanthan@in.ibm.com), 軟體工程師, IBM Global Services
Vishal Kulkarni (mailto:kvishal@in.ibm.com?subject=嵌入式設備上的 Linux 系統開發&cc=kvishal@in.ibm.com), 軟體工程師, IBM Global Services
2002 年 3 月 01 日
如果您剛接觸嵌入式開發,那麼大量可用的引導裝載程式(bootloader)、規模縮小的分發版(distribution)、檔系統和 GUI 看起來可能太多了。但是這些豐富的選項實際上是一種恩賜,允許您調整開發或用戶環境以完全符合您的需要。對 Linux 嵌入式開發的概述將幫助您理解所有這些選項。
Linux 正在嵌入式開發領域穩步發展。因為 Linux 使用 GPL(請參閱本文後面的 參考資料),所以任何對將 Linux 定制於 PDA、掌上機或者可佩帶設備感興趣的人都可以從網際網路免費下載其內核和應用程式,並開始移植或開發。許多 Linux 改良品種迎合了嵌入式/即時市場。它們包括 RTLinux(即時 Linux)、uclinux(用於非 MMU 設備的 Linux)、Montavista Linux(用於 ARM、MIPS、PPC 的 Linux 分發版)、ARM-Linux(ARM 上的 Linux)和其他 Linux 系統(請參閱 參考資料以鏈結到本文中提到的這些和其他術語及產品。)
嵌入式 Linux 開發大致涉及三個層次:引導裝載程式、Linux 內核和圖形用戶介面(或稱 GUI)。在本文中,我們將集中討論涉及這三層的一些基本概念;深入瞭解引導裝載程式、內核和檔系統是如何交互的;並將研究可用於檔系統、GUI 和引導裝載程式的眾多選項中的一部分。
引導裝載程式
引導裝載程式通常是在任何硬體上執行的第一段代碼。在象臺式機這樣的常規系統中,通常將引導裝載程式裝入主引導記錄(Master Boot Record,(MBR))中,或者裝入 Linux 駐留的磁片的第一個磁區中。通常,在臺式機或其他系統上,BIOS 將控制移交給引導裝載程式。這就提出了一個有趣的問題:誰將引導裝載程式裝入(在大多數情況中)沒有 BIOS 的嵌入式設備上呢?
解決這個問題有兩種常規技術:專用軟體和微小的引導代碼(tiny bootcode)。
專用軟體可以直接與遠端系統上的快閃記憶體設備進行交互並將引導裝載程式安裝在快閃記憶體的給定位置中。 快閃記憶體設備是與存儲設備功能類似的特殊晶片,而且它們能持久存儲資訊 ― 即,在重新引導時不會擦除其內容。
這個軟體使用目標(在嵌入式開發中,嵌入式設備通常被稱為 目標)上的 JTAG 埠,它是用於執行外部輸入(通常來自主機機器)的指令的介面。JFlash-linux 是一種用於直接寫快閃記憶體的流行工具。它支援為數眾多的快閃記憶體晶片;它在主機機器(通常是 i386 機器 ― 本文中我們把一台 i386 機器稱為 主機)上執行並通過 JTAG 介面使用平行埠訪問目標的快閃記憶體晶片。當然,這意味著目標需要有一個平行介面使它能與主機通信。Jflash-linux 在 Linux 和 Windows 版本中都可使用,可以在命令行中用以下命令啟動它:
Jflash-linux
某些種類的嵌入式設備具有 微小的引導代碼― 根據幾個位元組的指令 ― 它將初始化一些 DRAM 設置並啟用目標上的一個串列(或者 USB,或者乙太網)埠與主機程式通信。然後,主機程式或裝入程式可以使用這個連接將引導裝載程式傳送到目標上,並將它寫入快閃記憶體。
在安裝它並給予其控制後,這個引導裝載程式執行下列各類功能:
• 初始化 CPU 速度
• 初始化記憶體,包括啟用記憶體庫、初始化記憶體配置寄存器等
• 初始化序列埠(如果在目標上有的話)
• 啟用指令/資料快取記憶體
• 設置堆疊指標
• 設置參數區域並構造參數結構和標記(這是重要的一步,因為內核在標識根設備、頁面大小、記憶體大小以及更多內容時要使用引導參數)
• 執行 POST(加電自檢)來標識存在的設備並報告任何問題
• 為電源管理提供掛起/恢復支援
• 跳轉到內核的開始
帶有引導裝載程式、參數結構、內核和檔系統的系統典型記憶體佈局可能如下所示:
清單 1. 典型記憶體佈局
/* Top Of Memory */
Bootloader
Parameter Area
Kernel
Filesystem
/* End Of Memory */
嵌入式設備上一些流行的並可免費使用的 Linux 引導裝載程式有 Blob、Redboot 和 Bootldr(請參閱 參考資料獲得鏈結)。所有這些引導裝載程式都用於基於 ARM 設備上的 Linux,並需要 Jflash-linux 工具用於安裝。
一旦將引導裝載程式安裝到目標的快閃記憶體中,它就會執行我們上面提到的所有初始化工作。然後,它準備接收來自主機的內核和檔系統。一旦裝入了內核,引導裝載程式就將控制轉給內核。
設置工具鏈
設置工具鏈在主機機器上創建一個用於編譯將在目標上運行的內核和應用程式的構建環境 ― 這是因為目標硬體可能沒有與主機相容的二進位執行級別。
工具鏈由一套用於編譯、彙編和鏈結內核及應用程式的元件組成。 這些組件包括:
• Binutils ― 用於操作二進位檔的實用程式集合。它們包括諸如 ar 、 as 、 objdump 、 objcopy 這樣的實用程式。
• Gcc― GNU C 編譯器。
• Glibc― 所有用戶應用程式都將鏈結到的 C 庫。避免使用任何 C 庫函數的內核和其他應用程式可以在沒有該庫的情況下進行編譯。
構建工具鏈建立了一個交叉編譯器環境。 本地編譯器編譯與本機同類的處理器的指令。 交叉編譯器運行在某一種處理器上,卻可以編譯另一種處理器的指令。重頭設置交叉編譯器工具鏈可不是一項簡單的任務:它包括下載源代碼、修補補丁、配置、編譯、設置頭檔、安裝以及很多很多的操作。另外,這樣一個徹底的構建過程對記憶體和硬碟的需求是巨大的。如果沒有足夠的記憶體和硬碟空間,那麼在構建階段由於相關性、配置或頭檔設置等問題會突然冒出許多問題。
因此能夠從網際網路上獲得已預編譯的二進位檔是一件好事(但不太好的一點是,目前它們大多數只限於基於 ARM 的系統,但遲早會改變的)。一些比較流行的已預編譯的工具鏈包括那些來自 Compaq(Familiar Linux )、LART(LART Linux)和 Embedian(基於 Debian 但與它無關)的工具鏈 ― 所有這些工具鏈都用於基於 ARM 的平臺。
內核設置
Linux 社區正積極地為新硬體添加功能部件和支援、在內核中修正錯誤並且及時地進行常規改進。這導致大約每 6 個月(或 6 個月不到)就有一個穩定的 Linux 樹的新發行版。不同的維護者維護針對特定體系結構的不同內核樹和補丁。當為一個專案選擇了一個內核時,您需要評估最新發行版的穩定性如何、它是否符合專案要求和硬體平臺、從編程角度來看它的舒適程度以及其他難以確定的方面。還有一點也非常重要:找到需要應用於基本內核的所有補丁,以便為特定的體系結構調整內核。
內核佈局
內核佈局分為特定於體系結構的部分和與體系結構無關的部分。內核中特定於體系結構的部分首先執行,設置硬體寄存器、配置記憶體映射、執行特定於體系結構的初始化,然後將控制轉給內核中與體系結構無關的部分。系統的其餘部分在這第二個階段期間進行初始化。內核樹下的目錄 arch/ 由不同的子目錄組成,每個子目錄用於一個不同的體系結構(MIPS、ARM、i386、SPARC、PPC 等)。每一個這樣的子目錄都包含 kernel/ 和 mm/ 子目錄,它們包含特定於體系結構的代碼來完成象初始化記憶體、設置 IRQ、啟用快取記憶體、設置內核頁面表等操作。一旦裝入內核並給予其控制,就首先調用這些函數,然後初始化系統的其餘部分。
根據可用的系統資源和引導裝載程式的功能,內核可以編譯成 vmlinux、Image 或 zImage。vmlinux 和 zImage 之間的主要區別在於 vmlinux是實際的(未壓縮的)可執行檔,而 zImage是或多或少包含相同資訊的自解壓壓縮檔 ― 只是壓縮它以處理(通常是 Intel 強制的)640 KB 引導時間的限制。有關所有這些的權威性解釋,請參閱 Linux Magazine的文章“Kernel Configuration: dealing with the unexpected”(請參閱 參考資料)。
內核鏈結和裝入
一旦為目標系統編譯了內核後,通過使用引導裝載程式(它已經被裝入到目標的快閃記憶體中),內核就被裝入到目標系統的記憶體(在 DRAM 中或者在快閃記憶體中)。通過使用串列、USB 或乙太網埠,引導裝載程式與主機通信以將內核傳送到目標的快閃記憶體或 DRAM 中。在將內核完全裝入目標後,引導裝載程式將控制傳遞給裝入內核的位址。
內核可執行檔由許多鏈結在一起的物件檔組成。物件檔有許多節,如文本、資料、init 資料、bass 等等。這些物件檔都是由一個稱為 鏈結器腳本的檔鏈結並裝入的。這個鏈結器腳本的功能是將輸入物件檔的各節映射到輸出檔中;換句話說,它將所有輸入物件檔都鏈結到單一的可執行檔中,將該可執行檔的各節裝入到指定位址處。 vmlinux.lds是存在於 arch/
清單 2. 典型的 vmlinux.lds 文件
OUTPUT_ARCH(
ENTRY(stext) /* stext is the kernel entry point */
SECTIONS /* SECTIONS command describes the layout
of the output file */
{
. = TEXTADDR; /* TEXTADDR is LMA for the kernel */
.init : { /* Init code and data*/
_stext = .; /* First section is stext followed
by __init data section */
__init_begin = .;
*(.text.init)
__init_end = .;
}
.text : { /* Real text segment follows __init_data section */
_text = .;
*(.text)
_etext = .; /* End of text section*/
}
.data :{
_data=.; /* Data section comes after text section */
*(.data)
_edata=.;
} /* Data section ends here */
.bss : { /* BSS section follows symbol table section */
__bss_start = .;
*(.bss)
_end = . ; /* BSS section ends here */
}
}
LMA 是裝入模組位址;它表示將要裝入內核的目標虛擬記憶體中的位址。 TEXTADDR 是內核的虛擬起始位址,並且在 arch/
一旦引導裝載程式將內核複製到快閃記憶體或 DRAM 中,內核就被重新定位到 TEXTADDR — 它通常在 DRAM 中。然後,引導裝載程式將控制轉給這個位址,以便內核能開始執行。
參數傳遞和內核引導
stext 是內核入口點,這意味著在內核引導時將首先執行這一節下的代碼。它通常用組合語言編寫,並且通常它在 arch/
start_kernel 調用 setup_arch 作為執行的第一步,在其中完成特定於體系結構的設置。這包括初始化硬體寄存器、標識根設備和系統中可用的 DRAM 和快閃記憶體的數量、指定系統中可用頁面的數目、檔系統大小等等。所有這些資訊都以參數形式從引導裝載程式傳遞到內核。
將參數從引導裝載程式傳遞到內核有兩種方法:parameter_structure 和標記列表。在這兩種方法中,不贊成使用參數結構,因為它強加了限制:指定在記憶體中,每個參數必須位於 param_struct 中的特定偏移量處。最新的內核期望參數作為標記列表的格式來傳遞,並將參數轉化為已標記格式。 param_struct 定義在 include/asm/setup.h 中。它的一些重要欄位是:
清單 3. 樣本參數結構
struct param_struct {
unsigned long page_size; /* 0: Size of the page */
unsigned long nr_pages; /* 4: Number of pages in the system */
unsigned long ramdisk /* 8: ramdisk size */
unsigned long rootdev; /* 16: Number representing the root device */
unsigned long initrd_start; /* 64: starting address of initial ramdisk */
/* This can be either in flash/dram */
unsigned long initrd_size; /* 68: size of initial ramdisk */
}
請注意:這些數表示定義欄位的參數結構中的偏移量。這意味著如果引導裝載程式將參數結構放置在位址 0xc0000100,那麼 rootdev 參數將放置在 0xc0000100 + 16,initrd_start 將放置在 0xc0000100 + 64 等等 ― 否則,內核將在解釋正確的參數時遇到困難。
正如上面提到的,因為從引導裝載程式到內核的參數傳遞會有一些約束條件,所以大多數 2.4.x 系列內核期望參數以已標記的列表格式傳遞。在已標記的列表中,每個標記由標識被傳遞參數的 tag_header 以及其後的參數值組成。標記列表中標記的常規格式可以如下所示:
清單 4. 樣本標記格式。內核通過
#define
struct
u32
u32
};
/* Example tag for passing memory information */
#define ATAG_MEM 0x54410002 /* Magic number */
struct tag_mem32 {
u32 size; /* size of memory */
u32 start; /* physical start address of memory*/
};
setup_arch 還需要對快閃記憶體存儲庫、系統寄存器和其他特定設備執行記憶體映射。一旦完成了特定於體系結構的設置,控制就返回到初始化系統其餘部分的 start_kernel 函數。這些附加的初始化任務包含:
• 設置陷阱
• 初始化中斷
• 初始化計時器
• 初始化控制臺
• 調用 mem_init ,它計算各種區域、高記憶體區等內的頁面數量
• 初始化 slab 分配器並為 VFS、緩衝區快取記憶體等創建 slab 快取記憶體
• 建立各種檔系統,如 proc、ext2 和 JFFS2
• 創建 kernel_thread ,它執行檔系統中的 init 命令並顯示 lign 提示符。 如果在 /bin、/sbin 或 /etc 中沒有 init 程式,那麼內核將執行檔系統的 /bin 中的 shell。
回頁首
設備驅動程式
嵌入式系統通常有許多設備用於與用戶交互,象觸摸屏、小鍵盤、滾動輪、感測器、RA232 介面、LCD 等等。除了這些設備外,還有許多其他專用設備,包括快閃記憶體、USB、GSM 等。內核通過所有這些設備各自的設備驅動程式來控制它們,包括 GUI 用戶應用程式也通過訪問這些驅動程式來訪問設備。本節著重討論通常幾乎在每個嵌入式環境中都會使用的一些重要設備的設備驅動程式。
幀緩衝區驅動程式
這是最重要的驅動程式之一,因為通過這個驅動程式才能使系統螢幕顯示內容。幀緩衝區驅動程式通常有三層。最底層是基本控制臺驅動程式 drivers/char/console.c,它提供了文本控制臺常規介面的一部分。通過使用控制臺驅動程式函數,我們能將文本列印到螢幕上 ― 但圖形或動畫還不能(這樣做需要使用視頻模式功能,通常出現在中間層,也就是 drivers/video/fbcon.c 中)。這個第二層驅動程式提供了視頻模式中繪圖的常規介面。
幀緩衝區是顯卡上的記憶體,需要將它記憶體映射到用戶空間以便可以將圖形和文本能寫到這個記憶體段上:然後這個資訊將反映到螢幕上。幀緩衝區支援提高了繪圖的速度和整體性能。這也是頂層驅動程式引人注意之處:頂層是非常特定於硬體的驅動程式,它需要支援顯卡不同的硬體方面 ― 象啟用/禁用顯卡控制器、深度和模式的支援以及調色板等。所有這三層都相互依賴以實現正確的視頻功能。與幀緩衝區有關的設備是 /dev/fb0(主設備號 29,次設備號 0)。
輸入設備驅動程式
可觸摸板是用於嵌入式設備的最基本的用戶交互設備之一 ― 小鍵盤、感測器和滾動輪也包含在許多不同設備中以用於不同的用途。
觸摸板設備的主要功能是隨時報告用戶的觸摸,並標識觸摸的座標。這通常在每次發生觸摸時,通過生成一個中斷來實現。
然後,這個設備驅動程式的角色是每當出現中斷時就查詢觸摸屏控制器,並請求控制器發送觸摸的座標。一旦驅動程式接收到座標,它就將有關觸摸和任何可用資料的信號發送給用戶應用程式,並將資料發送給應用程式(如果可能的話)。然後用戶應用程式根據它的需要處理資料。
幾乎所有輸入設備 ― 包括小鍵盤 ― 都以類似原理工作。
快閃記憶體 MTD 驅動程式
MTD 設備是象快閃記憶體晶片、小型快閃記憶體卡、記憶棒等之類的設備,它們在嵌入式設備中的使用正在不斷增長。
MTD 驅動程式是在 Linux 下專門為嵌入式環境開發的新的一類驅動程式。相對於常規塊設備驅動程式,使用 MTD 驅動程式的主要優點在於 MTD 驅動程式是專門為基於快閃記憶體的設備所設計的,所以它們通常有更好的支援、更好的管理和基於磁區的擦除和讀寫操作的更好的介面。Linux 下的 MTD 驅動程式介面被劃分為兩類模組:用戶模組和硬體模組。
用戶模組
這些模組提供從用戶空間直接使用的介面:原始字元訪問、原始塊訪問、FTL(快閃記憶體轉換層,Flash Transition Layer ― 用在快閃記憶體上的一種檔系統)和 JFS(即日誌檔系統,Journaled File System ― 在快閃記憶體上直接提供檔系統而不是類比塊設備)。用於快閃記憶體的 JFS 的當前版本是 JFFS2(稍後將在本文中描述)。
硬體模組
這些模組提供對記憶體設備的物理訪問,但並不直接使用它們。通過上述的用戶模組來訪問它們。這些模組提供了在快閃記憶體上讀、擦除和寫操作的實際常式。
MTD 驅動程式設置
為了訪問特定的快閃記憶體設備並將檔系統置於其上,需要將 MTD 子系統編譯到內核中。這包括選擇適當的 MTD 硬體和用戶模組。當前,MTD 子系統支援為數眾多的快閃記憶體設備 ― 並且有越來越多的驅動程式正被添加進來以用於不同的快閃記憶體晶片。
有兩個流行的用戶模組可啟用對快閃記憶體的訪問: MTD_CHAR 和 MTD_BLOCK 。
MTD_CHAR 提供對快閃記憶體的原始字元訪問,而 MTD_BLOCK 將快閃記憶體設計為可以在上面創建檔系統的常規塊設備(象 IDE 磁片)。與 MTD_CHAR 關聯的設備是 /dev/mtd0、mtd1、mtd2(等等),而與 MTD_BLOCK 關聯的設備是 /dev/mtdblock0、mtdblock1(等等)。由於 MTD_BLOCK 設備提供象塊設備那樣的類比,通常更可取的是在這個模擬基礎上創建象 FTL 和 JFFS2 那樣的檔系統。
為了進行這個操作,可能需要創建分區表將快閃記憶體設備分拆到引導裝載程式節、內核節和檔系統節中。樣本分區表可能包含以下資訊:
清單 5. MTD 的簡單快閃記憶體設備分區
struct mtd_partition sample_partition = {
{
/* First partition */
name : bootloader, /* Bootloader section */
size : 0x00010000, /* Size */
offset : 0, /* Offset from start of flash- location 0x0*/
mask_flags : MTD_WRITEABLE /* This partition is not writable */
},
{ /* Second partition */
name : Kernel, /* Kernel section */
size : 0x00100000, /* Size */
offset : MTDPART_OFS_APPEND, /* Append after bootloader section */
mask_flags : MTD_WRITEABLE /* This partition is not writable */
},
{ /* Third partition */
name : JFFS2, /* JFFS2 filesystem */
size : MTDPART_SIZ_FULL, /* Occupy rest of flash */
offset : MTDPART_OFS_APPEND /* Append after kernel section */
}
}
上面的分區表使用了 MTD_BLOCK 介面對快閃記憶體設備進行分區。這些分區的設備節點是:
簡單快閃記憶體分區的設備節點
User device node Major number Minor number
Bootloader /dev/mtdblock0 31 0
Kernel /dev/mtdblock1 31 1
Filesystem /dev/mtdblock2 31 2
在本例中,引導裝載程式必須將有關 root 設備節點(/dev/mtdblock2)和可以在快閃記憶體中找到檔系統的位址(本例中是 FLASH_BASE_ADDRESS + 0x04000000 )的正確參數傳遞到內核。一旦完成分區,快閃記憶體設備就準備裝入或掛裝檔系統。
Linux 中 MTD 子系統的主要目標是在系統的硬體驅動程式和上層,或用戶模組之間提供通用介面。硬體驅動程式不需要知道象 JFFS2 和 FTL 那樣的用戶模組使用的方法。所有它們真正需要提供的就是一組對底層快閃記憶體系統進行 read 、 write 和 erase 操作的簡單常式。
回頁首
嵌入式設備的檔系統
系統需要一種以結構化格式存儲和檢索資訊的方法;這就需要檔系統的參與。Ramdisk(請參閱 參考資料)是通過將電腦的 RAM 用作設備來創建和掛裝檔系統的一種機制,它通常用於無盤系統(當然包括微型嵌入式設備,它只包含作為永久存儲媒質的快閃記憶體晶片)。
用戶可以根據可靠性、健壯性和/或增強的功能的需求來選擇檔系統的類型。下一節將討論幾個可用選項及其優缺點。
第二版擴展檔系統(Ext2fs)
Ext2fs 是 Linux 事實上的標準檔系統,它已經取代了它的前任 ― 擴展檔系統(或 Extfs)。Extfs 支持的檔大小最大為 2 GB,支持的最大檔案名稱大小為 255 個字元 ― 而且它不支援索引節點(包括資料修改時間標記)。Ext2fs 做得更好;它的 優點是:
• Ext2fs 支援達 4 TB 的記憶體。
• Ext2fs 檔案名稱最長可以到 1012 個字元。
• 當創建檔系統時,管理員可以選擇邏輯塊的大小(通常大小可選擇 1024、2048 和 4096 位元組)。
• Ext2fs 了實現快速符號鏈結:不需要為此目的而分配資料塊,並且將目標名稱直接存儲在索引節點(inode)表中。這使性能有所提高,特別是在速度上。
因為 Ext2 檔系統的穩定性、可靠性和健壯性,所以幾乎在所有基於 Linux 的系統(包括臺式機、伺服器和工作站 ― 並且甚至一些嵌入式設備)上都使用 Ext2 檔系統。然而,當在嵌入式設備中使用 Ext2fs 時,它有一些 缺點:
• Ext2fs 是為象 IDE 設備那樣的塊設備設計的,這些設備的邏輯塊大小是 512 位元組,1 K 位元組等這樣的倍數。這不太適合於磁區大小因設備不同而不同的快閃記憶體設備。
• Ext2 檔系統沒有提供對基於磁區的擦除/寫操作的良好管理。在 Ext2fs 中,為了在一個磁區中擦除單個位元組,必須將整個磁區複製到 RAM,然後擦除,然後重寫入。考慮到快閃記憶體設備具有有限的擦除壽命(大約能進行 100,000 次擦除),在此之後就不能使用它們,所以這不是一個特別好的方法。
• 在出現電源故障時,Ext2fs 不是防崩潰的。
• Ext2 檔系統不支援損耗平衡,因此縮短了磁區/快閃記憶體的壽命。(損耗平衡確保將位址範圍的不同區域輪流用於寫和/或擦除操作以延長快閃記憶體設備的壽命。)
• Ext2fs 沒有特別完美的磁區管理,這使設計塊驅動程式十分困難。
由於這些原因,通常相對於 Ext2fs,在嵌入式環境中使用 MTD/JFFS2 組合是更好的選擇。
用 Ramdisk 掛裝 Ext2fs
通過使用 Ramdisk 的概念,可以在嵌入式設備中創建並掛裝 Ext2 檔系統(以及用於這一目的的任何檔系統)。
清單 6. 創建一個簡單的基於 Ext2fs 的 Ramdisk
mke2fs -vm0 /dev/ram 4096
mount -t ext2 /dev/ram /mnt
cd /mnt
cp /bin, /sbin, /etc, /dev ... files in mnt
cd ../
umount /mnt
dd if=/dev/ram bs=1k count=4096 of=ext2ramdisk
mke2fs 是用於在任何設備上創建 ext2 檔系統的實用程式 — 它創建超級塊、索引節點以及索引節點表等等。
在上面的用法中, /dev/ram 是上面構建有 4096 個塊的 ext2 檔系統的設備。然後,將這個設備( /dev/ram )掛裝在名為 /mnt 的臨時目錄上並且複製所有必需的檔。一旦複製完這些檔,就卸裝這個檔系統並且設備( /dev/ram )的內容被轉儲到一個檔(ext2ramdisk)中,它就是所需的 Ramdisk(Ext2 檔系統)。
上面的順序創建了一個 4 MB 的 Ramdisk,並用必需的檔實用程式來填充它。
一些要包含在 Ramdisk 中的重要目錄是:
• /bin ― 保存大多數象 init 、 busybox 、 shell 、檔管理實用程式等二進位檔。
• /dev― 包含用在設備中的所有設備節點
• /etc― 包含系統的所有配置檔
• /lib― 包含所有必需的庫,如 libc、libdl 等
日誌快閃記憶體檔系統,版本 2(JFFS2)
瑞典的 Axis Communications 開發了最初的 JFFS,Red Hat 的 David Woodhouse 對它進行了改進。 第二個版本,JFFS2,作為用於微型嵌入式設備的原始快閃記憶體晶片的實際檔系統而出現。JFFS2 檔系統是日誌結構化的,這意味著它基本上是一長列節點。每個節點包含有關檔的部分資訊 ― 可能是檔的名稱、也許是一些資料。相對於 Ext2fs,JFFS2 因為有以下這些 優點而在無盤嵌入式設備中越來越受歡迎:
• JFFS2 在磁區級別上執行快閃記憶體擦除/寫/讀操作要比 Ext2 檔系統好。
• JFFS2 提供了比 Ext2fs 更好的崩潰/掉電安全保護。當需要更改少量資料時,Ext2 檔系統將整個磁區複製到記憶體(DRAM)中,在記憶體中合併新資料,並寫回整個磁區。這意味著為了更改單個字,必須對整個磁區(64 KB)執行讀/擦除/寫常式 ― 這樣做的效率非常低。要是運氣差,當正在 DRAM 中合併資料時,發生了電源故障或其他事故,那麼將丟失整個資料集合,因為在將資料讀入 DRAM 後就擦除了快閃記憶體磁區。JFFS2 附加檔而不是重寫整個磁區,並且具有崩潰/掉電安全保護這一功能。
• 這可能是最重要的一點:JFFS2 是專門為象快閃記憶體晶片那樣的嵌入式設備創建的,所以它的整個設計提供了更好的快閃記憶體管理。
因為本文主要是寫關於快閃記憶體設備的使用,所以在嵌入式環境中使用 JFFS2 的 缺點很少:
• 當檔系統已滿或接近滿時,JFFS2 會大大放慢運行速度。這是因為垃圾收集的問題(更多資訊,請參閱 參考資料)。
創建 JFFS2 檔系統
在 Linux 下,用 mkfs.jffs2 命令創建 JFFS2 檔系統(基本上是使用 JFFS2 的 Ramdisk)。
清單 7. 創建 JFFS2 檔系統
mkdir jffsfile
cd jffsfile
/* copy all the /bin, /etc, /usr/bin, /sbin/ binaries and /dev entries
that are needed for the filesystem here */
/* Type the following command under jffsfile directory to create the JFFS2 Image */
./mkfs.jffs2 -e 0x40000 -p -o ../jffs.image
上面顯示了 mkfs.jffs2 的典型用法。 -e 選項確定快閃記憶體的擦除磁區大小(通常是 64 千位元組)。 -p 選項用來在映射的剩餘空間用零填充。 -o 選項用於輸出檔,通常是 JFFS2 檔系統映射 ― 在本例中是 jffs.image。一旦創建了 JFFS2 檔系統,它就被裝入快閃記憶體中適當的位置(引導裝載程式告知內核查找檔系統的位址)以便內核能掛裝它。
tmpfs
當 Linux 運行於嵌入式設備上時,該設備就成為功能齊全的單元,許多守護進程會在後臺運行並生成許多日誌消息。另外,所有內核日誌記錄機制,象 syslogd、dmesg 和 klogd,會在 /var 和 /tmp 目錄下生成許多消息。由於這些進程產生了大量資料,所以允許將所有這些寫操作都發生在快閃記憶體是不可取的。由於在重新引導時這些消息不需要持久存儲,所以這個問題的解決方案是使用 tmpfs。
tmpfs 是基於記憶體的檔系統,它主要用於減少對系統的不必要的快閃記憶體寫操作這一唯一目的。因為 tmpfs 駐留在 RAM 中,所以寫/讀/擦除的操作發生在 RAM 中而不是在快閃記憶體中。因此,日誌消息寫入 RAM 而不是快閃記憶體中,在重新引導時不會保留它們。tmpfs 還使用磁片交換空間來存儲,並且當為存儲檔而請求頁面時,使用虛擬記憶體(VM)子系統。
tmpfs 的 優點包括:
• 動態檔系統大小 ― 檔系統大小可以根據被複製、創建或刪除的檔或目錄的數量來縮放。使得能夠最理想地使用記憶體。
• 速度 ― 因為 tmpfs 駐留在 RAM,所以讀和寫幾乎都是暫態的。即使以交換的形式存儲檔,I/O 操作的速度仍非常快。
tmpfs 的一個 缺點是當系統重新引導時會丟失所有資料。因此,重要的資料不能存儲在 tmpfs 上。
掛裝 tmpfs
諸如 Ext2fs 和 JFFS2 等大多數其他檔系統都駐留在底層塊設備之上,而 tmpfs 與它們不同,它直接位於 VM 上。因而,掛裝 tmpfs 檔系統是很簡單的事:
清單 8. 掛裝 tmpfs
/* Entries in /etc/rc.d/rc.sysinit for creating/using tmpfs */
# mount -t tmpfs tmpfs /var -o size=512k
# mkdir -p /var/tmp
# mkdir -p /var/log
# ln -s /var/tmp /tmp
上面的命令將在 /var 上創建 tmpfs 並將 tmpfs 的最大大小限制為 512 K。同時,tmp/ 和 log/ 目錄成為 tmpfs 的一部分以便在 RAM 中存儲日誌消息。
如果您想將 tmpfs 的一個項添加到 /etc/fstab,那麼它可能看起來象這樣:
tmpfs /var tmpfs size=32m 0 0
這將在 /var 上掛裝一個新的 tmpfs 檔系統。
圖形用戶介面(GUI)選項
從用戶的觀點來看,圖形用戶介面(GUI)是系統的一個最至關重要的方面:用戶通過 GUI 與系統進行交互。所以 GUI 應該易於使用並且非常可靠。但它還需要是有記憶體意識的,以便在記憶體受限的、微型嵌入式設備上可以無縫執行。所以,它應該是羽量級的,並且能夠快速裝入。
另一個要考慮的重要方面涉及許可證問題。一些 GUI 分發版具有允許免費使用的許可證,甚至在一些商業產品中也是如此。另一些許可證要求如果想將 GUI 合併入項目中則要支付版稅。
最後,大多數開發人員可能會選擇 XFree86,因為 XFree86 為他們提供了一個能使用他們喜歡的工具的熟悉環境。但是市場上較新的 GUI,象 Century Software 的 Microwindows(Nano-X)和 Trolltech 的 QT/Embedded,與 X 在嵌入式 Linux 的競技舞臺中展開了激烈競爭,這主要是因為它們佔用很少的資源、執行的速度很快並且具有定制視窗構件的支援。
讓我們看一看這些選項中的每一個。
Xfree86 4.X(帶幀緩衝區支持的 X11R6.4)
XFree86 Project, Inc. 是一家生產 XFree86 的公司,該產品是一個可以免費重複分發、開放源碼的 X Window 系統。X Window 系統(X11)為應用程式以圖形方式進行顯示提供了資源,並且它是 UNIX 和類 UNIX 的機器上最常用的視窗系統。它很小但很有效,它運行在為數眾多的硬體上,它對網路透明並且有良好的文檔說明。X11 為視窗管理、事件處理、同步和客戶機間通信提供強大的功能 ― 並且大多數開發人員已經熟悉了它的 API。它具有對內核幀緩衝區的內置支持,並佔用非常少的資源 ― 這非常有助於記憶體相對較少的設備。X 伺服器支援 VGA 和非 VGA 圖形卡,它對顏色深度 1、2、4、8、16 和 32 提供支援,並對渲染提供內置支援。最新的發行版是 XFree86 4.1.0。
它的 優點包括:
• 幀緩衝區體系結構的使用提高了性能。
• 佔用的資源相對很小 ― 大小在 600 K 到 700 K 位元組的範圍內,這使它很容易在小型設備上運行。
• 非常好的支持:線上有許多文檔可用,還有許多專用於 XFree86 開發的郵遞列表。
• X API 非常適合擴展。
它的 缺點包括:
• 比最近出現的嵌入式 GUI 工具性能差。
• 此外,當與 GUI 中最新的開發 ― 象專門為嵌入式環境設計的 Nano-X 或 QT/Embedded ― 相比時,XFree86 似乎需要更多的記憶體。
Microwindows
Microwindows 是 Century Software 的開放源代碼項目,設計用於帶小型顯示單元的微型設備。它有許多針對現代圖形視窗環境的功能部件。象 X 一樣,有多種平臺支持 Microwindows。
Microwindows 體系結構是基於客戶機/伺服器的並且具有分層設計。最底層是螢幕和輸入設備驅動程式(關於鍵盤或滑鼠)來與實際硬體交互。在中間層,可移植的圖形引擎提供對線的繪製、區域的填充、多邊形、裁剪以及顏色模型的支援。
在最上層,Microwindows 支援兩種 API:Win32/WinCE API 實現,稱為 Microwindows;另一種 API 與 GDK 非常相似,它稱為 Nano-X。Nano-X 用在 Linux 上。它是象 X 的 API,用於佔用資源少的應用程式。
Microwindows 支援 1、2、4 和 8 bpp(每圖元的位元數)的 palletized 顯示,以及 8、16、24 和 32 bpp 的真彩色顯示。Microwindows 還支援使它速度更快的幀緩衝區。Nano-X 伺服器佔用的資源大約在 100 K 到 150 K 位元組。
原始 Nano-X 應用程式的平均大小在 30 K 到 60 K。由於 Nano-X 是為有記憶體限制的低端設備設計的,所以它不象 X 那樣支援很多函數,因此它實際上不能作為微型 X(Xfree86 4.1)的替代品。
可以在 Microwindows 上運行 FLNX,它是針對 Nano-X 而不是 X 進行修改的 FLTK(快速輕巧工具箱(Fast Light Toolkit))應用程式開發環境的一個版本。本文中描述 FLTK。
Nano-X 的 優點包括:
• 與 Xlib 實現不同,Nano-X 仍在每個客戶機上同步運行,這意味著一旦發送了客戶機請求包,伺服器在為另一個客戶機提供服務之前一直等待,直到整個包都到達為止。這使伺服器代碼非常簡單,而運行的速度仍非常快。
• 佔用很小的資源
Nano-X 的 缺點包括:
• 聯網功能部件至今沒有經過適當地調整(特別是網路透明性)。
• 還沒有太多現成的應用程式可用。
• 與 X 相比,Nano-X 雖然近來正在加速開發,但仍沒有那麼多文檔說明而且沒有很好的支持,但這種情形會有所改變。
Microwindows 上的 FLTK API
FLTK 是一個簡單但靈活的 GUI 工具箱,它在 Linux 世界中贏得越來越多的關注,它特別適用于佔用資源很少的環境。它提供了您期望從 GUI 工具箱中獲得的大多數視窗構件,如按鈕、對話方塊、文本框以及出色的“賦值器”選擇(用於輸入數值的視窗構件)。還包括滑動器、捲軸、刻度盤和其他一些構件。
針對 Microwindows GUI 引擎的 FLTK 的 Linux 版本被稱為 FLNX。FLNX 由兩個組件構成:Fl_Widget 和 FLUID。Fl_Widget 由所有基本視窗構件 API 組成。FLUID(快速輕巧的用戶介面設計器(Fast Light User Interface Designer, FLUID))是用來產生 FLTK 源代碼的圖形編輯器。總的來說,FLNX 是能用來為嵌入式環境創建應用程式的一個出色的 UI 構建器。
Fl_Widget 佔用的資源大約是 40 K 到 48 K,而 FLUID(包括了每個窗口構件)大約佔用 380 K。這些非常小的資源佔用率使 Fl_Widget 和 FLUID 在嵌入式開發世界中非常受歡迎。
優點包括:
• 習慣於在象 Windows 這樣已建立得較好的環境中開發基於 GUI 的應用程式的任何人都會非常容易地適應 FLTK 環境。
• 它的文檔包括一本十分完整且編寫良好的手冊。
• 它使用 LGPL 進行分發,所以開發人員可以靈活地發放他們應用程式的許可證。
• FLTK 是一個 C++ 庫(Perl 和 Python 綁定也可用)。面向物件模型的選擇是一個好的選擇,因為大多數現代 GUI 環境都是面向物件的;這也使將編寫的應用程式移植到類似的 API 中變得更容易。
• Century Software 的環境提供了幾個有用的工具,諸如 ScreenToP 和 ViewML 流覽器。
它的 缺點是:
• 普通的 FLTK 可以與 X 和 Windows API 一同工作,而 FLNX 不能。它與 X 的不相容性阻礙了它在許多項目中的使用。
Qt/Embedded
Qt/Embedded 是 Trolltech 新開發的用於嵌入式 Linux 的圖形用戶介面系統。Trolltech 最初創建 Qt 作為跨平臺的開發工具用於 Linux 臺式機。它支援各種有 UNIX 特點的系統以及 Microsoft Windows。KDE ― 最流行的 Linux 桌面環境之一,就是用 Qt 編寫的。
Qt/Embedded 以原始 Qt 為基礎,並做了許多出色的調整以適用於嵌入式環境。Qt Embedded 通過 Qt API 與 Linux I/O 設施直接交互。那些熟悉並已適應了面向物件編程的人員將發現它是一個理想環境。而且,面向物件的體系結構使代碼結構化、可重用並且運行快速。與其他 GUI 相比,Qt GUI 非常快,並且它沒有分層,這使得 Qt/Embedded 成為用於運行基於 Qt 的程式的最緊湊環境。
Trolltech 還推出了 Qt 掌上機環境(Qt Palmtop Environment,俗稱 Qpe)。Qpe 提供了一個基本桌面視窗,並且該環境為開發提供了一個易於使用的介面。Qpe 包含全套的個人資訊管理(Personal Information Management (PIM))應用程式、網際網路客戶機、實用程式等等。然而,為了將 Qt/Embedded 或 Qpe 集成到一個產品中,需要從 Trolltech 獲得商業許可證。(原始 Qt 自版本 2.2 以後就可以根據 GPL 獲得 。)
它的 優點包括:
• 面向物件的體系結構有助於更快地執行
• 佔用很少的資源,大約 800 K
• 抗鋸齒文本和混合視頻的象素映射
它的 缺點是:
• Qt/Embedded 和 Qpe 只能在獲得商業許可證的情況下才能使用。
回頁首
結束語
嵌入式 Linux 開發正迅速地發展著。您必須學習並從引導裝載程式和分發版到檔系統和 GUI 中的每一個事物的各種選項中作出選擇。但是要感謝有這種選擇自由度以及非常活躍的 Linux 社區,Linux 上的嵌入式開發已經達到了新的境界,並且調整模組以適合您的規範從未比現在更簡單。這已經導致出現了許多時新的手持和微型設備作為開放盒,這是件好事 ― 因為事實是您不必成為一個專家從這些模組中進行選擇來調整您的設備以滿足您自己的要求和需要。
我們希望這篇對嵌入式 Linux 領域的介紹性概述能激起您進行試驗的欲望,並且希望您將體會擺弄微型設備的樂趣以滿足您的愛好。為進一步有助於您的專案,請參閱下面的“參考資料”,鏈結到有關我們這裏已經概述的技術的更深入的資訊。
參考資料
引導:
• 您可以參閱本文在 developerWorks 全球站點上的 英文原文.
• 如需獲得對 vmlinux 和 zimage 之間區別的極好解釋,請在 Alessandro Rubini 編寫的“ Kernel Configuration: dealing with the unexpected( Linux Magazine)的一文中找到“Booting your kernel”一節。
小型分發版:
• The Embedded Linux Distributions Quick Reference Guide涵蓋了許多商業的和開放源碼的分發版( Linux Devices,2001 年 8 月)。
• 請查看另一個 詳盡的分發版和有用的工具的清單( Linux-embedded.com)。
工具鏈:
• Wiki 工具鏈頁面包含到本文提到的所有三個工具鏈的鏈結,還有對它們的評論。
設備驅動程式:
• Memory Technology Device (MTD) Subsystem for Linux的目的是簡化記憶體設備(特別是快閃記憶體設備)的驅動程式的創建。
• Vipin Malik 編寫的 The Linux MTD, JFFS HOWTO將幫助您使 MTD 和 JFFS2 一起工作。
• Linux for PowerPC Embedded Systems HOWTO有一個很好的設備驅動程式清單。
• 理解 Linux device drivers有助於理解本篇介紹性文章( Penguin Magazine)。
• 要精通 Linux 設備驅動程式,請閱讀 O'Reilly 的 Linux Device Drivers,第 2 版一書。
有用的工具:
• Binutils、 GCC和 Glibc都可從 Free Software Foundation 下載獲得。
• 許多有用的下載都可從 Netwinder.org獲得,這是一個致力於 NetWinder 平臺上開發工作的志願者站點。
• 請在 Mark Nielsen 寫得非常棒的 How to use a Ramdisk for Linux一文中閱讀有關 Ramdisk 的所有資訊。
• FLNX 是以 FLTK(快速輕巧的工具箱)為基礎的。
檔系統:
• 第二版擴展檔系統 Ext2fs的主頁在 SourceForge。
• Red Hat 英國公司的 David Woodhouse 概述了大量有關 JFFS2:日誌快閃記憶體檔系統,第 2 版的背景知識。
• 您可以在 Linux HeadQuarters 閱讀更多有關 tmpfs的信息。
• Cliff Brake 和 Jeff Sutherland 編寫的 Flash Filesystems for Embedded Linux Systems一文論述了用於快閃記憶體設備的更多檔系統( Embedded Linux Journal)。
GUI:
• Xfree86 是 X 開發的主頁。
• 請查看一篇對 Microwindows 的一些缺點(GNOME gtk 開發人員的郵遞列表)的討論(時間比較長了)。
• 在 Trolltech 上查找有關 Qt/Embedded的更多資訊。
• The Embedded Linux GUI/Windowing Quick Reference Guide中有豐富的鏈結( Linux Devices,2002 年 2 月)。
一般參考資料:
• General Public License 或 GPL確保用戶複製、分發和修改軟體的權利。
• ARM Linux是您瞭解有關 Linux 用於 ARM 處理器的資訊的一個非常好的站點。它由 ARM 的創建者 Russell King 來維護。
• Penguinppc.org是關於 Linux 用於 PowerPC 系列處理器的的主頁。該站點上有一個關於為基於 PPC 的體系結構建立工具鏈的資料豐富的教程。
• Linux Devices是一個非常全面的站點,它包含有關 Linux 和嵌入式開發的出版發行、快速參考、新聞和特色報告等各種資訊。
• Silicon Penguin列表站點上擁有嵌入式 Linux 參考資料的詳盡集合。
• ARMLinux - the book可從 Aleph One 上獲得。您可以定購一本,也可以 線上閱讀。
• 嵌入式 Linux 協會(Embedded Linux Consortium)是一個非贏利的互助協會,它歡迎致力於嵌入式 Linux 領域的開發人員成為會員。
• IBM 的 Linux wristwatch是運行 Linux 的微型嵌入式設備的示例;本文的作者之一,Vishal Kulkarni 也參與了它的研發。請在 本文( FreeOS.com,2001 年 3 月)中閱讀有關它的資訊。
• 在 developerWorks上流覽 更多 Linux 參考資料。
• 在 developerWorks上流覽 更多無線領域的參考資料。
作者簡介
Anand K Santhanam 在印度 Madras 大學獲得電腦科學工學學士學位。自 1999 年 7 月以來他一直在印度為 IBM Global Services(軟體實驗室)工作。他是 IBM Linux 小組的成員,這個小組主要致力於嵌入式系統中的 ARM-Linux、設備驅動程式和電源管理的研究和開發。他感興趣的其他領域是 O/S 本質和聯網。可以通過 mailto:asanthan@in.ibm.com?cc=asanthan@in.ibm.com 與他聯繫。
Vishal Kulkarni 從印度 Maharashtra 的 Shivaji 大學獲得電子工程的學士學位。自 1999 年 3 月以來他一直在印度為 IBM Global Services(軟體實驗室)工作。在此之前,他曾在美國 IBM Austin 工作了一年半多。他是 IBM Linux 小組的成員,這個小組主要致力於嵌入式設備上的 ARM-Linux、設備驅動程式和 GUI。他感興趣的其他領域是 O/S 本質和聯網。可以通過 mailto:kvishal@in.ibm.com?cc=kvishal@in.ibm.com與他聯繫。