200812021343MMU (轉錄於大黑狗)

前面說過uClinux是改自正統Linux,它們大部分的程式碼其實是相同的,主要不同的地方除了與CPU相關的部分外,還有就是記憶體管理的部分,Linux有一部份的程式在處理虛擬記憶體的管理,這部分的程式對uClinux完全沒有意義,因為uClinux只支援沒有MMUCPU

 

雖然kernel程式碼中與CPU相關以及與MMU相關的部分有所不同,但LinuxuClinux所提供的系統呼叫介面幾乎一樣,所以理論上原本可執行於Linux上的程式碼經過重新編譯後就應該可以執行於uClinux上;依我們實作的經驗來說,在大部分的狀況下這種說法是對的,但是因為硬體不支援MMU的關係,所以會有幾個系統呼叫無法實現,或在實現時行為和原本的Linux不太一致。

 

而且uClinux上應用程式所使用的基本函式庫不是我們熟知的GNU LIBC,而是另一套較小型但仍與ANSI-C相容的函式庫,稱作uClibc。和完整的GNU LIBC比起來uClibc雖努力追求完全相容,但仍有其限制;也許大部分的限制在可見的將來都會解決,可是前面我們也說過,uClinux在功能上仍有些許先天上的限制,那根據底層系統呼叫來實現的函式庫要和原有的GNU LIBC完全相容可能還有一段路要走。

 

在這一節中我們將為讀者詳述uClinuxLinux主要的不同點,這樣使用者在開發時才不至於犯了不該犯的錯。在開始前必須要強調的是:雖然uClinux在記憶體管理以及多功能力上沒有Linux那麼powerful,但大部分的嵌入式系統都是客製化的專用系統,似乎用不著如此嚴密的功能﹙甚至有些產品就是一個process,連多工的能力都不需要﹚,而且值得一提的是,uClinux仍保有原來Linux的最大優勢之一:穩定的網路功能。

 

 

3-1 支援的CPU與硬體平台

 

Linux在設計上相當具有可移植性,目前大部分的桌上型或伺服器系統都有了Linux的版本,例如SPARC工作站,例如使用PowerPCMac等都可以安裝Linux,而且還有許多的移植計劃同步在進行中。

 

但是這些移植計劃的成果並沒有完全被收錄在官方公佈的Linux版本,如果您想知道目前最新的版本有支援哪種CPU平台,可以查看Linux原始碼中的”arch’目錄下有哪些目錄,以2.4.x而言,目前官方的Linux版本已經支援以下的CPU,相對於大部分的嵌入式產品,這些CPU確實算是蠻高階的:

 

alphaarmcrisi386ia64m68kMIPSMIPS64PA-RISC

PowerPCS390SHSPARCSPARC64

 

(大黑狗:現在肯定更多了)

 

至於uClinux支援的CPU則以沒有MMU的為主,目前發展的主力為ARM7系列以及68000系列,確實這兩顆CPU在中高階的嵌入式產品設計上用得相當多;此外uClinux還支援了以下的CPU或硬體平台:

 

- uClinux可以執行於Cisco 2500, 3000, 4000 routers

 

- 68000系列的CPU包含了Motorola ColdFire系列,目前直接可以執行的板子為﹙詳情請參考www.uclinux.org\ports\coldfire\faq.html﹚:

 

- 68000系列的CPU包含了Motorola DragonBall系列,支援的CPU6832868EZ328以及68VZ328,目前可以直接執行的硬體平台包含:

   => PalmPilot and Xcopilot 68328

   => PalmV 68EZ328

   => Motorola ADS Board68EZ328 or 68VZ328

   => Lineo uCSimm68EZ328 + 10base Ethernet

   => Lineo uCDimm 68VZ328 + 10base Ethernet

 

- ARM系列包含ARM7TDMI

- MC68EN302

- Intel i960

 

- 還有一些筆者不熟悉的CPU

   => Motorola QUICC - Quad Integrated Communications Controller

   => ETRAX

   => PRISMA

   => Atari 68k

 

有許多廠商已經利用uClinux來發展產品,我們將會在下一節提到這些應用。

 

 

3-2 實體記憶體管理

 

之前一直強調uClinux是一個執行於沒有MMUCPU上的作業系統,在這一小節中我們將大致說明所謂的MMU與作業系統之間的關係,進而引申出uClinux相較於Linux所無法實現的系統功能;在此我們不會談太多作業系統裡面的細節,只希望讀者能對作業系統使用MMU所能達到的效果有約略的了解。

 

在伺服器、個人電腦以及一些電腦應用上,作業系統必須能保證當同時有多個使用者登入,或同時執行多個應用程式時彼此不會互相干擾;簡單的說,這些程式同時都存在記憶體內準備取得CPU的使用權,如果其中某個有bug的程式﹙或由有惡意的programmer寫的程式﹚去破壞了屬於其他程式的記憶體區域,那後果將不堪設想。在這樣的系統中,作業系統必須負責將所有應用程式區隔開來,使其不能互相影響。

 

要達到這一點必須引入位址空間的觀念;位址空間的概念可以想成每個應用程式﹙或說process﹚都只能在自己的記憶體區塊上執行,一般狀況下應用程式無法去存取另一個應用程式的記憶體區塊,從而達到基本的區隔與保護的功能;要實現讓各個process有自己的位址空間必須要有硬體支援,換句話說,當作業系統把各個process可以存取的記憶體區塊分配好後,還必須保證process”不可能存取到其他process的實體記憶體,這個沒有CPU的支援是做不到的。

 

舉例來說,假設系統中的實體記憶體有16MBprocess1分配到前8MBprocess2則分配到後面8MB,如果沒有硬體機制的介入,作業系統如何能防止process2去操作前8MB的記憶體?

 

CPU中的MMU可以解決這個事情,最簡單的說法就是:讓應用程式無法直接操作實體記憶體位址,只能操作虛擬記憶體位址,虛擬記憶體位址必須透過作業系統維護的系統表格﹙page table,每個process有自己的page table﹚去作轉換才可以得到實體記憶體位址;針對應用程式給定的記憶體位址﹙虛擬記憶體位址﹚,CPU會自動根據這個表格去轉換出相應的實體記憶體位址。作業系統在這裡要負的責任就是保證無論輸入的虛擬記憶體位址為何,這個表格都不會轉換出不屬於這個process的實體位址。

 

CPUMMU除了用來實現虛擬記憶體的功能外,另一個重點就是所謂的swapping﹙將沒用到的RAM的區域﹚;我們在PC上安裝Linux時不都是要先建一個swap partitionswap file嗎?因為系統中實體的RAM有限,假設這些RAM已被系統中目前正在執行的process所瓜分,此時若再要執行另一個重要的應用程式時怎麼辦?在沒有MMU﹙硬體﹚或不提供swapping﹙軟體﹚的平台上會選擇移除一個較不重要的process以釋出記憶體資源;在有MMU的平台上可就有更合理的解決方案。

 

當系統的RAM已經用盡時可以選擇很久沒有使用的部分將其先存到swap partitionswap file中,空出的RAM可以馬上拿來使用,當需要時再故技重施將其從自swap空間中回存到RAM中。聽起來很單純,但是如果沒有硬體的MMU支援的話要作到這一點幾乎是不可能的任務!讀者可以思考一個問題,被置換出去的區域當其被置換回來後還會位於同一的實體位址嗎?機會不大吧,因為我們會選擇一塊最不常用的區域將其swap out;當一塊屬於某個process的記憶體區塊上次執行與這次恢復執行時居然位於不同的實體記憶體位址,而應用程式不可能預計這種狀況何時會產生,所以必須由CPU與作業系統聯手解決這個問題。

 

解決方式很簡單,前面說過應用程式是用虛擬記憶體位址來操作記憶體,由CPU自動參考這個processpage table將其轉換成實體記憶體位址;所以要解決上面的問題其實很簡單,應用程式要操作之記憶體區塊的實體記憶體位址已經變更了,但應用程式仍是使用相同的虛擬記憶體位址,所以要更改的只是虛擬記憶體位址以及實體記憶體的對應關係罷了,換句話說,作業系統在作swapping時必須是情形更改受影響processpage table

 

有關虛擬記憶體以及swapping技術的細節相當多,在此不再贅述;但是如果讀者對於以上MMU的原理介紹看得霧煞煞其實也沒有關係,讀者只需要清楚以下歸納的兩點:

 

- MMU可以讓各個process間獨立執行,不會互相干擾﹙不能操作其他process的記憶體空間﹚

 

- MMU可以將暫時不用的RAM先存到硬碟去,當需要的時候再取回,如此系統執行時就不會有RAM不夠的限制、

 

講了那麼多MMU的功用,筆者的目的只是想要點出:因為uClinux運行在沒有MMUCPU上,所以其先天上就會有些原本Linux既有的功能無法實現:

 

- process無法有自己的位址空間,有問題的應用程式可能會誤操作其他process的記憶體空間,進而造成系統崩潰。

 

- 作業系統無法實現swapping的功能

 

這樣的系統不可能應用在伺服器或個人電腦上,但是否適合使用於嵌入式系統呢?答案當然是肯定的,同樣有兩個理由:

 

- 嵌入式系統的應用程式多是由廠商自行研發,可以假設出貨前已經bug free,也不會有惡意的程式﹙例如網路下載的病毒程式﹚,而且除了PDA外,幾乎沒有產品在交到end user手上後還有download新應用程式的需求;保護機制在嵌入式系統的領域中似乎並不是那麼重要。

 

- 一般嵌入式系統根本沒有諸如硬碟這種儲存設備,那麼swapping似乎也無法在嵌入式系統中派上用場了!

 

雖然uClinux先天就無法像Linux具有那樣嚴謹的process間保護以及swapping的功能,但瑕不掩瑜,uClinux本來就是定位為嵌入式作業系統,而且更因為拿掉了這些功能,它的code sizeLinux小的多。

 

 

3-3多工能力

 

uClinux是一個多工的作業系統是無庸置疑的,只是在這方面和Linux比起來仍算有所缺陷:uClinux只有vfork(),沒有fork();在說明原因之前,我們必須先知道這兩個系統呼叫有何不同。

 

就功能而言:這兩個系統功能都可以複製出和呼叫者﹙parent﹚完全相同的processchild﹚,但呼叫vfork()後的parent process會被暫停,直到被複製出來的child process執行了exec()exit();而呼叫fork()後的parent process會和新產生的child process平行﹙concurrent﹚執行。

 

接下來我們必須約略解釋一下fork()Linux中的實現方式,旨在讓讀者知道為什麼這個系統功能沒法直接移植到沒有MMUCPU上;首先我們必須先介紹一下”copy-on-write”這個觀念:

 

一個程式在執行時會佔據記憶體空間,粗略可分為程式段、資料段、堆疊段與常數段,其中程式段與堆疊段是唯讀的,資料段與堆疊段的內容則有可能在執行時期被改變。在Linux中,當某個process呼叫fork()產生child process時,系統只會為新的process配置堆疊段,其他的記憶體區段都是共用的;實際上在child process呼叫exec()去執行另一個程式前,諸如程式段以及常數段這些內容不可以被改變的記憶體區段始終可以共用。可是資料段就不能一直共用,如果parentchild process同時去操作某個變數勢必會引起混亂。

 

Child processfork出來後馬上呼叫exec()去執行其他程式是最常用的流程,以此說來,雖然每個process都必須有獨立的資料段,但馬上為child process配置資料段是很不經濟的,因為在大部分的狀況下child process並不會去對資料段作寫入的動作,在執行exec()後,之前的資料段就沒用了。

 

為了解決這個問題,Linux採用”copy-on-write”的技術,在child process尚未對資料段作寫入的動作之前,parentchild process共用資料段;當child process對資料段記憶體作出寫入的要求時,系統會配置一塊實體記憶體﹙一個page﹚給child process,並將原本資料段中被要求寫入之page的內容複製到這塊新的page;接著系統會更改child processpage table,使要被寫入資料的虛擬位址可以對應到上述新配置的實體記憶體位址。

 

此時child processparent process的資料段大部分都還是功用的,不同的地方只是這次要被寫入的page;這種演算法的好處很多,在最節省記憶體的前提下使得parentchild process不致互相影響。要達到這種效果,CPU沒有支援MMU是做不到的,所以uClinux無法直接支援fork()這個系統功能。

 

uClinux無法作到安全的資料段分享機制,產生child process後複製整塊資料段也顯得有點笨拙,於是只好讓parent process停止執行,直到child process結束執行或有了自己的資料段之後才能恢復執行,前者表示child process出現例外或呼叫了exit(),而後者則表示child process呼叫了exec()去執行其他的程式。這樣妥協出來的功能,就是原本Linux中的vfork()系統呼叫。

 

如果讀者對copy-on-write的原理不清楚也沒關係,讀者在使用uClinux時只需知道一般Linux在實現fork()這個系統功能時必須用到MMU的機制,而uClinux執行在沒有MMUCPU之上,所以fork()無法直接移植到uClinux上;uClinux提供vfork()以達到多工的效果。

 

必須注意的是,使用vfork()產生的child process很可能會破壞parent process原本的資料段,所以程式設計師在uClinux上使用vfork()時必須格外小心;而且沒有fork()系統功能的事實使得許多原本運行在Linux上的應用程式無法完全不經修改救執行於uClinux之上。

 

 

3-4 支援的子系統與函式庫

 

在開始本節之前,筆者先說明一下我對子系統與函式庫這兩個詞的定義:函式庫是發展程式時會用到的功能集合,例如ANSI-C、數學函式庫、繪圖函式庫等。而子系統則是整個嵌入式系統中除了kernel之外的系統軟體,大一點的如視窗以及資料庫系統,小一點的如shellmount…這些系統工具。

 

目前uClinux支援的子系統與函式庫相較於Linux都顯得貧乏,其實移植Linux上既有的程式碼並不困難,重點是必須發時間與人力去測試,造成目前狀況的原因一來是人力問題,二來是實驗平台不易取得﹙每個程式設計師應該都有台PC,但不可能都有Dragon BallARM的發展平台吧﹚,這都使得大部分移植動作的進度相當的慢;在這樣的情形下,要使用uClinux發展產品的廠商只好根據需求自行作移植的動作,這樣的情形造成一些筆者認為不是很好的狀況:

 

- 各作各的,缺乏標準。

- 許多廠商基於open source的成果不主動開放,造成重複開發,程式碼不一致。

 

例如要使用uClinux來開發PDA的廠商都需要一套較小的視窗系統,Micro-Windows是其中一個選擇, Micro-Windows專案暫時還沒有支援uClinux的計劃,uClinux專案也沒有人力去做Micro-Windows的移植﹙就像Linux kernel團隊不會有時間去作X-Windows的維護吧﹚;於是乎有興趣的廠商各自為政,我相信應該已經有許多廠商已經移植甚至測試完成了,但是在uClinuxmail-list上每幾天就會有人問uClinux是否支援Micro-Windows,而回答的人也不多。其實答案當然是肯定的,只是作好的人沒有公開罷了!這是商業利益與open-source理想不得不然的衝突。

 

以上是筆者小小的牢騷,當然還是得言歸正傳;目前uClinux上可以用的函式庫其實已經可以充分應付大部分的狀況了,諸如ANSI-Cprintf()open()fopen()…﹚以及常用的數學函式庫﹙sin()cos()…﹚都可正常運行,但值得注意的是uClinux並不是使用我們在Linux上用的Gnu libclibm,而是使用較精簡的版本-uClibchttp://cvs.uclinux.org/uClibc.html﹚。

 

使用uClibc在程式寫作上其實和Gnu libc沒有什麼差別,只是目前Gnu libc包含的功能越來越齊全,相對的也變得越來越大,在嵌入式系統中對記憶以錙銖必較的狀況下屆顯得有點不合適

沒有上一則|日誌首頁|沒有下一則
回應





Powered by Xuite
    沒有新回應!
關鍵字