uclinux表示micro-control linux.即“微控制器領域中的Linux系統”,是Lineo公司的主打產品,同時也是開放源碼的嵌入式Linux的典范之作。uCLinux主要是針對目標處理器沒有存儲管理單元MMU(Memory Management Unit)的嵌入式系統而設計的。它已經被成功地移植到了很多平臺上。由于沒有MMU,其多任務的實現需要一定技巧。
uClinux是嵌入式Linux領域非常重要的分支,已成功應用于路由器、機頂盒、PDA等領域,與標準Linux在內存管理方面有著本質的區別。
Uclinux的配置和裁減也是利用的華恒科技提供的源碼包(用于hhbf531學習板)。我們使用的開發板信息如下:
CPU:BF533
FLASH:S29AL004D-512KB
這里我不敢說“uclinux的移植”,而只是以“配置與裁減”代之,是因為我覺得自己的工作真的談不上什么移植。現成的源碼包,所有的底層驅動都已經完成,我們所要做的只是選擇自己需要的驅動、配置一下內核、做一些裁減工作而已。每每聽到其他人提到“最近又完成了×××平臺的linux移植”,我都會有點擔心:國內有多少工程師能真正從最初始的工作開始,完成一個平臺的系統移植——應該很少吧。
下面,我分以下步驟簡單介紹一下我的配置過程。
一,配置并在RAM中運行內核(不帶根文件系統):
由于我們的flash空間有限,在沒有裁減之前,就算不帶根文件系統,也無法燒寫到flash內保存;所以先嘗試下載到RAM中運行。另外,我們目前的開發板上沒有網絡功能,只能通過串口下載,所以在這里配置內核的過程中,做一些簡單裁減,以便節約下載時間。
解壓源碼包后,進入uclinux目錄:
#cd uClinux-dist
設定交叉工具鏈:
#PATH=”/usr/local/bin/gcc-bfin-3.4-uclinux/bin/:$PATH”
進入配置:
#make menuconfig
運行后,進入“MainMenu”配置頁,可以在此選擇Vender/Product和Kernel/Library/Defaults等內容。根據我們使用的平臺,我們選擇:Vender-AnalogDevices,Product-HHBF533(或者HHBF531),Libc-uClibc;如果要配置內核和應用程序還要分別選中“Customize Kernel Settings”、“Customize Vender/User Settings”。退出保存后,將依次進入配置內核和配置應用程序頁。
如果想單獨配置內核,可以進入目錄linux-2.6.x/內運行“make menuconfig”。配置應用程序在這個源碼包里好像沒有單獨的config選項。這些關于內核源碼包結構的基本知識,需要大家提前了解。
下面,我們來配置內核。
配置一個可以在我們的SDRAM中運行的內核很簡單,因為底層工作都已經完成。我們只需要配置一下處理器相關內容即可。處理器選項位于內核配置頁的“Blackfin Processer Options”。進入該配置頁,進行如下配置:
CPU - BF533
System type - BF533-HHBF
Board Customizations - 根據你的開發板時鐘、SDRAM信息配置,其他不用修改。
Clock Settings - 取消“Re-programClocks while Kernel boots”,默認為u-boot的時鐘配置。
其他選項不用修改,各項配置功能介紹見文檔《附.Linux 2.6.19.x內核編譯配置選項簡介》。
以上配置正確后,下載到你的開發板上,應該就可以運行了。但通過串口下載速度太慢,我們先去掉一些不需要的驅動。由于我們沒有網絡功能,所以把網絡及其驅動全部取消,可以裁減150KB左右的空間;我們也不需要音視頻功能,所以把音視頻驅動也取消,又可以減小很大空間。如此配置后,我們可以嘗試下載到SDRAM中運行了。
現在,我們還不想裁減根文件系統,所以,我們想得到一個不帶根文件系統的壓縮內核鏡像。由于華恒提供的源碼包,編譯后不能得到壓縮的不帶根文件系統的鏡像,所以我們要通過修改Makefile得到我們需要的編譯結果。
需要修改的Makefile位于uClinux-dist目錄下,打開該Makefile,在“.PHONY:linux”項的”ln –f $(LINUXDIR)/vmlinux $(LINUXDIR)/linux;\”語句后,添加以下內容。
這樣在uClinux-dist目錄下執行“make linux”就可以生成壓縮的不帶根文件系統的內核鏡像了,該鏡像文件為uImage.bin,位于linux-2.6.x目錄內。現在,可以將得到的內核下載到SDRAM中運行了。因為是壓縮內核,所以運行時要使用u-boot的bootm命令。至于u-boot命令的使用方法,自行學習。
Makefile也是編譯內核的基礎知識,需要大家逐步掌握。
這樣,該步的工作就可以告一段落了。
下載到SDRAM中,如果解壓后無法運行,先檢查一下上述配置操作是否有誤。如果確定無誤,就需要分析內核的執行過程,仔細分析問題了。接下來簡單介紹一下內核執行流程。
二,內核執行流程:
承接上篇《u-boot引導uclinux過程分析》,介紹內核啟動流程。
A,內核vmlinux入口
u-boot執行“(*appl)(cmdline);”語句后,控制權就移交給linux內核,appl變量指向的地址就是linux內核的首地址。
Linux內核執行的第一個文件是/linux-2.6.x/arch/blackfin/mach-bf533/head.S。經過一系列的初始化,跳轉到start_kernel()函數,即進入linux系統初始化階段。
B, Linux系統初始化
Start_kernel()函數位于文件/linux-2.6.x/init/main.c中,是linux內核通用的初始化函數。無論對于什么體系結構的linux,都要執行這個函數。
Start_kernel()函數負責初始化內核各子系統,最后調用rest_init(),啟動一個叫作init的內核線程,繼續初始化。
起始內核線程init的任務依然是初始化,只不過是一種更高層次的初始化。
函數do_basic_setup()是init進程中最重要的函數,與嵌入式系統關系最緊密的是其中的do_initcalls()函數,該函數與設備驅動程序加載有關。
函數prepare_namespace()函數主要目的是準備好系統的命名空間,其中最重要的函數是mount_root(),其功能是掛載根文件系統。
四個run_init_process()函數查找init進程程序并嘗試執行。如果沒有找到一個可以執行的init程序,則報告錯誤“Noinit found”。
C,初始化設備驅動
參考B中的do_basic_setup()函數。
D,掛接根文件系統
參考B中的prepare_namespace()函數。
E, 啟動用戶空間init進程
當內核掛載了根文件系統后,內核的啟動工作就全部結束了,但系統還不能正常啟動起來,因為還需要通過根文件系統上的init程序來完成一下最后的設置工作。這個init程序一般在/sbin、/etc或/bin目錄下。
三,裁減內核(不帶根文件系統)并燒寫到flash中:
該步承接上步的工作。由于上步已經做了一定的裁減,該步只需要在此基礎上進一步裁減即可。該步工作相對叫簡單,只需要將不需要的驅動選項取消即可,當然要注意保證內核的依賴關系。
我們的flash容量為512KB,u-boot占有64KB空間,剩下的只有448KB。另外,根文件系統大約還需要100KB空間,所以內核大小要控制在350KB以內。我們先嘗試將不需要的驅動和選項全部取消,讓內核運行起來。
在“二,配置并在RAM中運行內核(不帶根文件系統)”的基礎上,我們進一步刪除的驅動包括:
l 取消“Loadble module support”支持
l 取消“Block layer”支持
l 取消“Bus options”所有支持
l 取消“Power management options”支持
l 取消“CPU Frequency scaling”支持
l 取消“Profiling Support”支持
l 取消“Security options”支持
l 取消“Cryptographic options”支持
l 取消除了串口和MTD以外的所有硬件驅動支持
l 取消內部RTC驅動
l 取消對ELF格式文件支持
取消以上選項后,內核可以控制在350KB以內了。所以,不需進一步修改Makefile來裁減內核了。這樣就可以下載并燒寫到flash內保存了。
四,配置應用程序和裁減根文件系統:
根文件系統掛載到內核有兩種基本方式:獨立于內核存放通過MTD分區識別并掛載和鏈接到內核數據段通過ramdisk掛載(兩種方式都是我自己概括的,可能描述上有些不盡合理,僅供參考)。不論那種方式,都需要MTD驅動支持,所以內核要支持MTD并配置正確,保持華恒源碼包原MTD配置即可。
HHBF5XX 的Linux BSP 使用ext2 格式的ramdisk 作為根文件系統,直接鏈接到內核數據段,所以這里介紹這種方式。另一種方式這里不作介紹,其相關資料更豐富。
與根文件系統(ramfs)相關的鏈接內容如下,位于文件/linux-2.6.x/arch/Blackfin/Kernel/vmlinux.lds.S中。
內核通過__initramfs_start和__initramfs_end找到根文件系統的img,這兩個變量在文件/linux-2.6.x/init/Initramfs.c中被引用。
介紹完根文件系統的掛載方式,我們來介紹如何配置和裁減應用程序。
由于flash容量限制,而且我們也并不需要很多應用程序的支持,所以我們可以只保留最簡單的init、sh、ls、cd等應用程序,其他應用全部裁減掉。注意必須保證要有init和sh,否則內核無法運行或沒有shell界面。另外,為了進一步裁減體積,我們利用busybox制作根文件系統,busybox的介紹文檔網上非常多,這里不再介紹。
按照以上分析,我們來配置應用程序和busybox。
按照“一,配置并在RAM中運行內核(不帶根文件系統)”中介紹的方法進入應用程序配置頁。只需選中Busybox內的BusyboxSVN,其余選項全部取消,完全用busybox代替。
然后,我們來配置busybox。進入busybox目錄,運行配置命令:
#cd user/busybox-svn
#make menuconfig
除了按照我們上面介紹的,保留最基本的應用程序之外,其他全部取消;還有一點需要特別注意。就是在“Build options”選擇中選中編譯成靜態庫,而不要編譯成共享庫,這樣在根文件系統掛載時省去很多麻煩,雖然最后得到的內核體積會稍微增大一下。共享庫的應用可以在內核運行成功后,進一步學習。
這樣配置得到的根文件系統已經裁減了很大體積,但下載到SDRAM中運行時會發現根文件系統占有的內存空間仍然很大,始終保持12.5MB空間。這是因為,根文件系統的運行空間是在生成鏡像時指定的。要裁減占有的內存空間,可以如下修改。
#vi vender/HHTech/BF533-HHBF/Makefile
修改第14行的“BLOCKS = 12800”為較小的值,比如說4096等,必須是256的整數倍,否則內核運行時根文件系統報錯。這樣修改后,根文件系統占有的flash和SDRAM空間都會相應減小。
通過以上裁減后,帶有根文件系統的內核鏡像完全可以控制在448KB以內,下載保存到flash后運行,你就可以看到可愛的“uClinux”歡迎界面了。
如果要進一步裁減根文件系統,可以修改和刪除vender/HHTech/BF533-HHBF/目錄下的相關文件,具體操作不再詳述。
uClinux的多進程處理
uClinux沒有mmu管理存儲器,在實現多個進程時(fork調用生成子進程)需要實現數據保護。 uClinux的fork和vfork:uClinux的fork等于vfork。實際上uClinux的多進程管理通過vfork來實現。這意味著 uClinux系統fork調用完程后,要么子進程代替父進程執行(此時父進程已經sleep)直到子進程調用exit退出,要么調用exec執行一個新的進程,這個時候將產生可執行文件的加載,即使這個進程只是父進程的拷貝,這個過程也不能避免。當子進程執行exit或exec后,子進程使用 wakeup把父進程喚醒,父進程繼續往下執行。 uClinux的這種多進程實現機制同它的內存管理緊密相關。 uClinux針對nommu處理器開發,所以被迫使用一種flat方式的內存管理模式,啟動新的應用程序時系統必須為應用程序分配存儲空間,并立即把應用程序加載到內存。缺少了MMU的內存重映射機制,uClinux必須在可執行文件加載階段對可執行文件reloc處理,使得程序執行時能夠直接使用物理內存。
評論
查看更多