歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux嵌入式 >> 輕松控制uClinux嵌入式開發過程一(圖)

輕松控制uClinux嵌入式開發過程一(圖)

日期:2017/2/27 9:25:24   编辑:Linux嵌入式
  UCLinux是目前比較普及的嵌入式Linux版本之一,它的功能很多,並且隨著低成本、可運行uClinux的32位CPU的激增,以及uClinux首次成為Linux 2.6內核的一部分,uClinux將更加流行(如圖1)。下面討論一下開發者使用uClinux時如何控制開發過程,以及將會遇到的與普通Linux的不同之處。     圖1 uClinux運行在Palm上    應用無內存管理    uClinux與普通Linux系統的主要區別就是它沒有內存管理。在普通Linux下,通過使用虛擬內存(VM)來實現內存管理。虛擬內存一般是通過內存管理單元(Memory Management Unit,簡稱MMU)來實現,而在uClinux的世界裡,經常可以看到“NOMMU”這個詞。    在有虛擬內存的情況下,所有的進程都在相同的地址空間運行,由虛擬內存系統處理虛擬內存到物理內存的映射。因此,即使進程看到的虛擬內存是連續的,它所占的物理內存也可能是分散的,有的甚至被交換到了硬盤。因為物理內存能映射到進程地址空間的任何位置,所以這種環境下能夠向正在運行的進程添加內存。    在沒有虛擬內存的情況下,每個進程必須被分配到固定的內存位置。由於一個進程的上、下(內存位置)都可能有別的進程在運行,所以它通常不能動態擴展內存。這就是說,在uClinux下運行的進程不能在運行過程中動態增加可用內存,這與傳統Linux下的情況有所不同。    對於uClinux開發者來說,分配內存是一個棘手的問題,並且由於沒有任何形式的內存保護,任何應用程序或內核都可能破壞系統。更為糟糕的是,無意識的誤操作不會引人注意,造成要跟蹤隨機的、進程間的破壞非常困難。但是這些缺陷對於uClinux來說幾乎不算問題,這是因為使用uClinux的系統一般沒有硬盤驅動器和足夠的內存,完全沒有必要做復雜的管理和交換。    做足內存映射    對於內核開發者,uClinux與普通Linux區別很小。惟一真正會遇到的問題是uClinux內核開發者不能利用MMU提供的分頁支持,比如,依賴虛擬內存的tmpfs文件系統在uClinux下就不起作用。類似的,普通Linux下的標准可執行文件格式uClinux都不支持,因為它們都要利用虛擬內存的特性。uClinux需要一種新的格式——Flat,它是一種壓縮的可執行文件格式,只保存可執行的代碼和數據,以及將可執行程序裝載到內存時所需要的重定位信息。    理解uClinux內核中內存映射的實現方式也是很有必要的,因為有些方式在uClinux系統上行不通,理解內存映射的實現後可以避免使用這些方式。uClinux要求內存映射能夠直接在文件系統中指到文件,從而保證它是順序的和連續的,否則就必須事先為文件分配好內存,並把數據拷貝到分配給它的內存塊上。    因此,uClinux下有效內存映射的用法要素非常明確:首先,當前惟一能夠保證文件連續存儲的文件系統是ROM文件系統(Romfs),所以必須使用Romfs來避免傳統內存分配;其次,只有只讀的內存映射能夠被共享,也就是說,為了避免傳統內存分配,映射必須是只讀的。由於這些原因,uClinux下的開發者不能利用“Copy-on-Write”特性。    要將設備驅動程序移植到uClinux環境,需要做一些修改,這並不是因為內核上的區別,而是由於與硬件細節相關部分有所不同造成的。比如,普通Linux下,SMC網絡驅動程序可以支持ISA SMC卡。該驅動程序是16位的,並且一般都分配到0x3ff以下的I/O地址空間。    但是用來支持SMC卡的非ISA嵌入式版本,驅動程序要求運行在8位、16位或32位模式下都是可能的,並且在滿32位的I/O地址中,中斷號一般要高於ISA的最大值16。所以,與硬件細節相關的部分可能還是要做一些移植工作。    恰當的內存分配    uClinux除了提供跟普通Linux一樣的內存分配器之外,還提供另一個可選的。普通Linux中缺省的內存分配器是使用“2的冪”的分配方法,這樣可以快速找到符合要求的內存區域。不幸的是,在uClinux下這種方法可能會帶來令人痛苦的結果。    為了理解這一問題帶來的結果,尤其是大的內存分配,我們舉例說明。試想一個應用程序要求33KB的內存空間進行裝載。如果使用“2的冪”的分配方法,就必須分配64KB(2的6次方)內存空間,多余的31KB內存空間不能被利用上。在uClinux中,這種浪費是不能接受的。為了解決這個問題,專門為uClinux內核設計了可選的內存分配器。不同的內核版本,這個可選的內存分配器不同,一般是page_alloc2和kmalloc2。    page_alloc2能解決缺省的分配方法造成的浪費問題。雖然它也是使用“2的冪”的分配方法,但它是按頁(每頁4096字節,即4KB)分配的,分配的內存大小如果已經滿足了要求,則只是將當前的一頁分配出去,其它的就不再分配。


在前面的例子中,如果使用這種方法,就只是分配36KB(≥33KB,且為整頁)即可,這樣就能節省28KB的空間。    page_alloc2還采取了一些避免內存碎片的方法。它將所有的兩頁(8KB)或更少的內存需求從空閒內存開始部分向上分配,所有大的內存需求從剩余內存的末尾部分開始向下分配。這樣防止了網絡緩存等的臨時分配,避免了內存碎片的出現。    一旦開發者理解了內核內存分配的區別,應用程序中就會出現變化。    1.沒有動態棧的問題    在使用虛擬內存的Linux上,當一個應用程序試圖沖銷棧頂單元時,會被標記異常,同時系統會映射新的內存到棧頂以便讓棧增長。在uClinux下,由於必須在編譯階段給棧分配好內存,所以不會有這樣的增長。當出現莫名其妙的崩潰或者新移植的應用程序出現怪異行為時,開發者首先應該考慮到的是給棧分配的內存大小問題。缺省情況下,uClinux為棧分配4KB的內存空間,開發者可以用下面提到的方法之一來增加棧的空間。    ◆ 應用程序build之前    應用程序build之前,可以在Makefile文件中增加以下兩行代碼:    FLTFLAGS = -s   eXPort FLTFLAGS    ◆ 應用程序build之後    應用程序build之後,可以運行以下命令:    flthdr -s executable    其中,stacksize 就是為棧增加的內存空間。    2.沒有動態堆的問題    堆是C語言中malloc及相關函數分配內存的區域。在有虛擬內存的Linux上,應用程序可能通過動態堆在運行過程中改變進程的大小。這個功能是通過在底層使用sbrk()和brk()系統調用來實現的。sbrk()是在進程的末尾增加內存空間,所以調用sbrk()能夠使應用程序獲得額外的內存。    brk()可以把任意位置設置為進程空間的末尾,因此,可以通過調用brk()減少或增加內存空間的占用。由於uClinux不能實現brk()和sbrk(),它采用了一個全局的內存池,就是內核的空閒內存池。使用全局內存池的方法有一些優點。



Copyright © Linux教程網 All Rights Reserved