什么是Uclinux?
uCLinux是一個完全符合GNU/GPL公約的項目,完全開放代碼,現(xiàn)由Lineo公司支持維護。英文單詞中u表示Micro,小的意思,C表示Control,控制的意思,所以uCLinux就是Micro-Control-Linux,字面上的理解就是“微控制領域中的Linux系統(tǒng)”。它專門針對沒有MMU的CPU,并專為嵌入式系統(tǒng)做了許多小型化的工作,已支持前面提到的多款CPU。官方主頁在http://www.uclinux.org。國內(nèi)從事uclinux開發(fā)有合肥華恒科技等幾家公司 。
核心開發(fā)人員12人左右。To join, send mail to majordomo@uclinux.org with the command "subscribe uclinux-dev" in the body of the message.
已成功使用uCLinux的案例
合肥華恒的基于coldfire 5272/5407的家庭網(wǎng)關Soho/Home/VPN Router、基于68EZ328的PDA開發(fā)套件
Maple?信號處理公司基于DragonBallVZ和TMS320C541xx?DSP的DAQStick?系列嵌入式信號處理板卡
珠海萬禾的基于VZ328的多串口設備Webport2000,基于68VZ328的PDA開發(fā)套件
Lineo 公司的uCsimm、uCdimm開發(fā)套件以及商業(yè)音樂媒體服務器BMMS-MP3.COM采用
西南交通大學電氣檢測與故障診斷信息研究室的嵌入式電力設備運行狀態(tài)監(jiān)測系統(tǒng)
NetSilicon公司 NET+Works設備網(wǎng)絡平臺(基于ARM7TDMI)-為Wireless Networks 公司的BlueLAN 提供接入點
東軟的智能家庭網(wǎng)關產(chǎn)品
愛立信的基于ARM7TDMI藍芽BLIP無線通信設備
基于ARM7TDMI的Aplio公司的voice-over-IP電話
AXIS公司的AXIS2001網(wǎng)絡數(shù)碼相機
Adomo公司的家庭機頂盒
Snapsear的VPN安全設備
瑞士洛桑的Smartdata公司的微型計算機Chipslice
uCLinux內(nèi)存管理
uClinux同標準Linux的最大區(qū)別就在于內(nèi)存管理????????標準Linux使用的虛擬存儲器技術
?◇標準Linux是針對有內(nèi)存管理單元的處理器設計的。虛擬地址被送到內(nèi)存管理單元(MMU),把虛擬地址映射為物理地址。采用分頁的方式來載入進程。實際存儲器分割為相同大小的頁面。
◇虛擬存儲器由存儲器管理機制及一個大容量的快速硬盤存儲器支持。它的實現(xiàn)基于局部性原理,當一個程序在運行之前,沒有必要全部裝入內(nèi)存,而是僅將那些當前要運行的那些部分頁面裝入內(nèi)存運行(copy-on-write),其余暫時留在硬盤上程序運行時如果它所要訪問的頁已存在,則程序繼續(xù)運行,如果發(fā)現(xiàn)不存在的頁,操作系統(tǒng)將產(chǎn)生一個頁失效異常,導致操作系統(tǒng)把需要運行的部分加載到內(nèi)存中。必要時操作系統(tǒng)還可以把不需要的內(nèi)存頁交換到磁盤上。
?◇通過賦予每個任務不同的虛擬--物理地址轉(zhuǎn)換映射(頁表),還可支持不同任務之間的保護、共享等。
?◇對于多進程管理當處理器進行進程切換并執(zhí)行一個新任務時,一個重要部分就是為新任務切換頁表。
標準Linux系統(tǒng)的內(nèi)存管理功能??
◇可以運行只加載了部分的程序,縮短了程序啟動的時間
??? ◇運行比內(nèi)存還要大的程序。理想情況下應該可以運行任意大小的程序 ◇可以使多個程序同時駐留在內(nèi)存中提高CPU的利用率 ◇可以運行重定位程序。即程序可以方于內(nèi)存中的任何一處,而且可以在執(zhí)行過程中移動 ◇寫機器無關的代碼。程序不必事先約定機器的配置情況 ◇減輕程序員分配和管理內(nèi)存資源的負擔
???? ◇可以進行程序代碼共享 ◇提供內(nèi)存保護,進程不能以非授權方式訪問或修改頁面,內(nèi)核保護單個進程的數(shù)據(jù)和代碼以防止其它進程修改它們。否則,用戶程序可能會偶然(或惡意)的破壞內(nèi)核或其它用戶程序
??? 代價:內(nèi)存管理需要地址轉(zhuǎn)換表和其他一些數(shù)據(jù)結構,留給程序的內(nèi)存減少了。地址轉(zhuǎn)換增加了每條指令的執(zhí)行時間,而對于有額外內(nèi)存操作的指令會更嚴重。當進程訪問不在內(nèi)存的頁面時,系統(tǒng)處理失效的磁盤I/O操作極耗時間。
uCLinux針對NOMMU的特殊處理
uClinux針對沒有MMU的處理器設計,不能使用處理器的虛擬內(nèi)存管理技術,但出現(xiàn)簡單和盡量靠攏標準Linux得需要,uClinux仍然沿用標準Linux的分頁內(nèi)存管理結構,系統(tǒng)在啟動時把實際存儲器進行分頁,但實際上采用的是實存儲器管理策略。
uClinux系統(tǒng)對于內(nèi)存的訪問是直接的,(它對地址的訪問不需要經(jīng)過MMU,而是直接送到地址線上輸出),所有程序中訪問的地址都是實際的物理地址。
操作系統(tǒng)對內(nèi)存空間沒有保護(這實際上是很多嵌入式系統(tǒng)的特點),各個進程實際上共享一個運行空間(沒有獨立的地址轉(zhuǎn)換表)。
一個進程在執(zhí)行前,系統(tǒng)必須為進程分配足夠的連續(xù)地址空間,然后全部載入主存儲器的連續(xù)空間中。由于程序加載地址與預期(ld文件中指出的)通常都不相同,這樣relocation過程就是必須的。
磁盤交換空間無法使用的,系統(tǒng)執(zhí)行時如果缺少內(nèi)存將無法通過磁盤交換來得到改善。
uCLinux對開發(fā)人員提出的更高要求
從易用性來說,uClinux的內(nèi)存管理實際上是一種倒退,退回了到了UNIX早期或是Dos系統(tǒng)時代。開發(fā)人員不得不參與系統(tǒng)的內(nèi)存管理。從編譯內(nèi)核開始,開發(fā)人員必須告訴系統(tǒng)這塊開發(fā)板到底擁有多少的內(nèi)存。
由于應用程序加載時必須分配連續(xù)的地址空間,而針對可連續(xù)地址分配內(nèi)存大小是受限的,開發(fā)人員在開發(fā)應用程序時必須考慮內(nèi)存的分配情況并關注應用程序需要運行空間的大小。另外由于采用實存儲器管理策略,
用戶程序同內(nèi)核以及其它用戶程序在一個地址空間,程序開發(fā)時要保證不侵犯其它程序的地址空間,以使得程序不至于破壞系統(tǒng)的正常工作,或?qū)е缕渌绦虻倪\行異常。從內(nèi)存的訪問角度來看,開發(fā)人員的權利增大了(開發(fā)人員在編程時可以訪問任意的地址空間),但與此同時系統(tǒng)的安全性也大為下降。
從嵌入式設備實現(xiàn)的功能來看,嵌入式設備通常在某一特定的環(huán)境下運行,只要實現(xiàn)特定的功能,其功能相對簡單,內(nèi)存管理的要求完全可以由開發(fā)人員考慮。
uCLinux內(nèi)核加載方式
?? uCLinux的內(nèi)核有兩種可選的運行方式:可以在flash上直接運行,也可以加載到內(nèi)存中運行。后者可以減少內(nèi)存需要。 ??? Flash運行方式(XIP):把內(nèi)核的可執(zhí)行映像燒寫到flash上,系統(tǒng)啟動時從flash的某個地址開始逐句執(zhí)行。這種方法實際上是很多嵌入式系統(tǒng)采用的方法。 ??? 內(nèi)核加載方式:把內(nèi)核的壓縮文件存放在flash上,系統(tǒng)啟動時讀取壓縮文件在內(nèi)存里解壓,然后開始執(zhí)行,這種方式相對復雜一些,但是運行速度可能更快(RAM的存取速率要比Flash高)。
uCLinux根(root)文件系統(tǒng)
?? uCLinux系統(tǒng)采用romfs文件系統(tǒng),這種文件系統(tǒng)相對于一般的ext2文件系統(tǒng)要求更少的空間??臻g的節(jié)約來自于兩個方面:首先內(nèi)核支持romfs文件系統(tǒng)比支持ext2文件系統(tǒng)需要更少的代碼;其次romfs文件系統(tǒng)相對簡單,在建立文件系統(tǒng)超級塊(superblock)需要更少的存儲空間。Romfs文件系統(tǒng)不支持動態(tài)擦寫保存,對于系統(tǒng)需要動態(tài)保存的數(shù)據(jù)采用虛擬ram盤/JFFS的方法進行處理(ram盤將采用ext2文件系統(tǒng))。
uCLinux應用程序庫
uCLinux小型化的另一個做法是重寫了應用程序庫,相對于越來越大且越來越全的glibc庫,uClibc對libc做了精簡。 http://uclibc.org/uClibc.html
uClibm數(shù)學庫
uCLinux對用戶程序采用靜態(tài)鏈接的形式,這種做法會使應用程序變大,但是基于內(nèi)存管理的問題,也就是基于沒有MMU的特性,只能這樣做,同時這種做法也更接近于通常嵌入式系統(tǒng)的做法。
標準Linux系統(tǒng)系統(tǒng)數(shù)據(jù)段,代碼段,堆和棧在虛存層面是連續(xù)的。堆向上增長,棧向下增長,在堆底和棧頂之間有256MB的內(nèi)存可供分配。uClinux采用了實內(nèi)存模式,各個內(nèi)存段在物理內(nèi)存層面是連續(xù)的,棧段在同數(shù)據(jù)段在一起,堆有系統(tǒng)內(nèi)存管理,所有進程共享,由于內(nèi)存連續(xù)和保護的要求,棧段,數(shù)據(jù)段,代碼段都是在程序加載是分配。 這種內(nèi)存空間布局阻礙了動態(tài)連接庫的運用。棧段的大小固定(在生成應用時可以指定棧段大?。?,開發(fā)人員在開發(fā)時不得不使用一些方法估計判斷棧段的大小,使其即能滿足程序的需要,又不浪費內(nèi)存。
?uClinux可執(zhí)行文件格式
? uCLinux系統(tǒng)使用flat可執(zhí)行文件格式,目前也支持elf文件格式。先解釋幾種可執(zhí)行文件格式。 coff(common object file format):一種通用的對象文件格式; elf(executive linked file):一種為Linux系統(tǒng)所采用的通用文件格式,支持動態(tài)連接和重定位; flat:elf格式有很大的文件頭,flat文件對文件頭和一些段信息做了簡化,可執(zhí)行程序小。
? 當用戶執(zhí)行一個應用時,內(nèi)核的執(zhí)行文件加載器將對flat文件進行進一步處理,主要是對reloc段進行修正(詳見fs/binfmt_flat.c)。 需要reloc段的根本原因是,程序在連接時連接器所假定的程序運行空間與實際程序加載到的內(nèi)存空間不同。假如有這樣一條指令: jsr app_start; 這一條指令采用直接尋址,跳轉(zhuǎn)到app_start地址處執(zhí)行,連接程序?qū)⒃诰幾g完成是計算出app_start的實際地址(設若實際地址為0x10000),這個實際地址是根據(jù)ld文件計算出來。但實際上由于內(nèi)存分配的關系,操作系統(tǒng)在加載時無法保證程序?qū)磍d文件加載。這時如果程序仍然跳轉(zhuǎn)到絕對地址0x10000處執(zhí)行,通常情況這是不正確的。
?? 一個解決辦法是增加一個存儲空間,用于存儲app_start的實際地址,設若使用變量addr表示這個存儲空間。則以上這句程序?qū)⒏臑椋?movl addr, a0;??? jsr (a0); 增加的變量addr將在數(shù)據(jù)段中占用一個4字節(jié)的空間,連接器將app_start的絕對地址存儲到該變量。在可執(zhí)行文件加載時,可執(zhí)行文件加載器根據(jù)程序?qū)⒁虞d的內(nèi)存空間計算出app_start在內(nèi)存中的實際位置,寫入addr變量。系統(tǒng)在實際處理是不需要知道這個變量的確切存儲位置(也不可能知道),系統(tǒng)只要對整個reloc段進行處理就可以了(reloc段有標識,系統(tǒng)可以讀出來)。處理很簡單只需要對reloc段中存儲的值統(tǒng)一加上一個偏置(如果加載的空間比預想的要靠前,實際上是減去一個偏移量)。偏置由實際的物理地址起始值同ld文件指定的地址起始值相減計算出。
標準Linux 的多進程管理
??? fork創(chuàng)建的進程幾乎是父進程的精確復制,從fork返回后,父子進程執(zhí)行同樣的程序,有同樣的數(shù)據(jù)和堆棧區(qū),并從緊跟fork后的指令繼續(xù)執(zhí)行。
???? exec系統(tǒng)調(diào)用提供一個進程去執(zhí)行另一個進程的能力,exec系統(tǒng)調(diào)用是采用覆蓋舊有進程存儲器內(nèi)容的方式,所以原來程序的堆棧、數(shù)據(jù)段與程序段都會被修改。 fork的優(yōu)化:
??? (1)COW (寫時拷貝),首先由System V使用。不進行頁面復制,父子進程共享頁面,頁面置為只讀,無論父進程還是子進程試圖修改頁時,發(fā)生頁失效,頁失效處理程序進行頁面復制,并清除只讀標志。
??? (2)BSD采用的vfork,多數(shù)程序調(diào)用完成fork后會馬上執(zhí)行exec,因此vfork不進行頁面復制,父進程將地址空間租界給子進程,并將自己阻塞,直到子進程將地址空間還給它。因此,子進程會一直使用父進程的地址空間直到它調(diào)用exec或exit,內(nèi)核再將地址空間返回給父進程并喚醒它。fork非???,甚至無需拷貝頁表。它允許一個進程使用修改另一進程的地址空間。
?? uClinux NOMMU 但支持多進程
?? MMU不是支持多進程的必要條件,只是更好的支持了多進程操作系統(tǒng)的實現(xiàn)。
?? uClinux沒有MMU管理存儲器,不支持COW的機制,因此fork 的優(yōu)化只有采用vfork這一途徑,并且由于不支持虛擬地址空間,簡單復制的fork實現(xiàn)也必須修正reloc段。 最終,uClinux的fork/vfork都用vfork實現(xiàn)。子進程要么代替父進程執(zhí)行(此時父進程已經(jīng)sleep)直到子進程調(diào)用exit退出,要么調(diào)用exec執(zhí)行一個新的進程,這個時候?qū)a(chǎn)生可執(zhí)行文件的加載,即使這個進程只是父進程的拷貝,這個過程也不能避免。當子進程執(zhí)行exit或exec后,子進程使用wakeup把父進程喚醒,父進程繼續(xù)往下執(zhí)行。
??? 經(jīng)過如上各方面的小型化改造,就形成了一個高度優(yōu)化的、代碼緊湊的嵌入式Linux,雖然它的體積很小,uCLinux仍然保留了Linux的大多數(shù)的優(yōu)點:穩(wěn)定、良好的移植性、優(yōu)秀的網(wǎng)絡功能、完備的對各種文件系統(tǒng)的支持、以及標準豐富的API。它的主要特征如下: ●通用Linux API ●內(nèi)核體積 < 512 KB ●內(nèi)核 +文件系統(tǒng)<900 KB ●完整的TCP/IP 協(xié)議棧 ●支持大量其它的網(wǎng)絡協(xié)議 ●支持各種文件系統(tǒng),包括 NFS、ext2、ROMfs and JFFS、MS-DOS和FAT16/32
?uClinux開發(fā)環(huán)境
基于uCLinux的應用開發(fā)環(huán)境一般是由目標系統(tǒng)硬件開發(fā)板和宿主PC機所構成。硬件開發(fā)板用于操作系統(tǒng)和目標系統(tǒng)應用軟件的運行,而操作系統(tǒng)內(nèi)核的編譯、應用軟件的開發(fā)和調(diào)試則需要借助宿主PC機來完成。雙方之間一般通過串口建立連接關系。 建立交叉開發(fā)環(huán)境 在軟件開發(fā)環(huán)境建立方面,由于uCLinux及相關工具集都是開放源碼的項目,所以大多數(shù)軟件都可以從網(wǎng)絡上下載獲得。首先要在宿主機上安裝標準Linux發(fā)行版,比如Red-Hat Linux,接下來就可以建立交叉開發(fā)環(huán)境。 1.安裝交叉編譯工具 針對uCLinux目前有兩套編譯工具:m68k-coff和m68k-elf,它們都是GNU組織開發(fā)的優(yōu)秀的編譯器GCC的不同應用版本。它們的區(qū)別在于形成最終flat目標碼之前的中間代碼格式分別是coff和elf類型。elf格式的編譯器比coff格式的編譯器有許多優(yōu)越性,建議使用m68k-elf交叉編譯器。編譯工具包中除了交叉編譯器以外,還有鏈接器(ld)、匯編器(as)以及一些為了方便開發(fā)的二進制處理工具,包括生成靜態(tài)庫工具(ar、ranlib)、二進制碼察看工具(nm、size)、二進制格式轉(zhuǎn)換工具(objcopy)。這些都要安裝在宿主機上。
????????? 2.安裝uCLinux內(nèi)核 利用已安裝的交叉編譯器編譯生成運行與目標機上的uCLinux內(nèi)核。與標準Linux相同的是,uCLinux內(nèi)核可以以配置的方式選擇需要安裝的模塊,而增加系統(tǒng)的靈活性。 3.安裝應用程序庫 用交叉編譯器編譯uC-libc和uC-libm源碼,生成libc.a應用程序庫和libm.a數(shù)學庫。 4.安裝其他工具 用GCC編譯elf2flt源碼,生成格式轉(zhuǎn)換工具elf2flt。用GCC編譯genromfs源碼,得到生成romfs工具genromfs。 經(jīng)過以上的準備工作之后,下面要針對特定應用所需要的設備編寫或改造設備驅(qū)動程序。有一些設備驅(qū)動,uCLinux本身就已經(jīng)具有。即便沒有,因為uCLinux開放源碼的特性,用戶也可以很方便地把自己的驅(qū)動程序加入內(nèi)核。如果用戶對系統(tǒng)實時性,特別是硬實時有特殊的要求,uCLinux可以加入RT-Linux的實時模塊。完成這些工作,一個嵌入式應用開發(fā)平臺就已經(jīng)搭建好了,在此之上,根據(jù)不同需要可以開發(fā)不同的嵌入式應用。
評論