構建嵌入式Linux系統
2004年11月A
本文引用地址:http://dyxdggzs.com/article/4749.htm摘要:本文針對構建一個(gè)Linux嵌入式操作系統所面臨的問(wèn)題作了深入的分析,這些問(wèn)題包括精簡(jiǎn)內核、系統啟動(dòng)和編寫(xiě)硬件驅動(dòng)程序。
關(guān)鍵詞:嵌入式操作系統;驅動(dòng);模塊;內核
引言:
目前嵌入式系統的應用越來(lái)越廣泛,一臺通用PC的外部設備就有5~10個(gè)嵌入式微處理器,如鍵盤(pán)、軟驅、硬盤(pán)、顯示器、打印機、掃描儀、USB接口等均是由嵌入式處理器控制的。在制造工業(yè)、過(guò)程控制、通信電視、儀器儀表、汽車(chē)船舶、航空航天、消費類(lèi)產(chǎn)品均是嵌入式系統的應用領(lǐng)域。嵌入式系統目前主要有:Windows CE、VxWorks、QNX等,它們都具較好的實(shí)時(shí)性,系統可靠性,任務(wù)處理隨機性等優(yōu)點(diǎn)。但是它們的價(jià)格普遍偏高,很多開(kāi)發(fā)商承受不起。因而,Linux操作系統成為嵌入式操作系統的首選,原因如下:
在精簡(jiǎn)內核在編譯內核之前,首先要明確需要那些驅動(dòng)和模塊,然后只選擇需要的驅動(dòng)和模塊,例如,如果系統不需要網(wǎng)絡(luò )支持,則可以去掉網(wǎng)絡(luò )模塊。內核一般是以壓縮方式存放的,在系統啟動(dòng)時(shí)會(huì )自行解壓。內核都是常駐內存的,當需要調用應用程序時(shí),再把需要的程序從磁盤(pán)調入內存運行。
構建內核常用的命令包括:
◆ make config:內核配置,調用 ./scripts/Configure 按照 arch/i386/config.in 來(lái)進(jìn)行配置。
◆ make dep:尋找依賴(lài)關(guān)系。
◆ make clean:清除以前構建內核所產(chǎn)生的所有目標文件、模塊文件、以及一些臨時(shí)文件等。
◆ make rmproper:刪除所有因構建內核過(guò)程中產(chǎn)生的所有文件,把內核恢復到最原始的狀態(tài)。
◆ make:構核,通過(guò)各目錄的Makefile 文件將會(huì )在各個(gè)目錄下產(chǎn)生許多目標文件。如果內核沒(méi)有錯誤,將產(chǎn)生文件vmlinux,這就是構建的內核。
◆ make zImage:在make 的基礎上產(chǎn)生壓縮的內核映象文件./arch/$(ARCH)/boot/zImage 以及在 ./arch/$(ARCH)/boot/compresed/目錄下產(chǎn)生臨時(shí)文件。 ◆ make bzImage:在make 的基礎上產(chǎn)生壓縮比例更大的內核映象文件./arch/$(ARCH)/boot/bzImage 以及在 ./arch/$(ARCH)/boot/compresed/目錄下產(chǎn)生臨時(shí)文件。
◆ make modules:編譯模塊文件,在make config 時(shí)所配置的所有模塊將在這時(shí)編譯,形成模塊目標文件,并把這些目標文件存放在modules 目錄中。 ◆ make modules_install:把上面編譯好的模塊目標文件放置在目錄 ./lib/modules/$KERNEL_VERSION/ 中。上面的編譯內核是在沒(méi)有改變源代碼的情況下實(shí)現的,如果覺(jué)得源代碼提供的功能在某些方面不能滿(mǎn)足要求,就要修改源代碼了。源代碼中主要有以下幾個(gè)關(guān)鍵部分:有關(guān)進(jìn)程管理的task_struct 結構,這個(gè)結構幾乎包括了與進(jìn)程有關(guān)的所有文件內容,還有任務(wù)隊列、時(shí)鐘管理和中斷管理,各種進(jìn)程間的通信機制,內存管理中各種內存分配函數的實(shí)現,虛擬文件系統。
系統啟動(dòng)
引導啟動(dòng)程序主要包括以下三個(gè)文件:bootsect.s,head.s和setup.s 這三個(gè)文件雖然都是匯編程序,但確使用了兩種語(yǔ)法格式。bootsect.s和setup.s 采用了近似于Intel的匯編語(yǔ)言語(yǔ)法,需要使用Intel 8086 匯編器和連接器 as86和ld86。head.s 則使用了GUN的匯編格式,并且運行在保護模式下,需要用GUN的as 進(jìn)行編譯。這是一種AT&T語(yǔ)法的匯編語(yǔ)言格式。 Bootsect.s代碼時(shí)磁盤(pán)引導塊程序,駐留在磁盤(pán)的第一個(gè)扇區中,在PC機加電ROM-BIOS自檢后,引導扇區由BIOS加載到內存0x7C00處,然后將自己移動(dòng)到內存0x90000處。該程序的主要作用是首先將setup模塊(由setup.s編譯的)從磁盤(pán)加載到內存緊接著(zhù)bootsect的后面位置(0x90200),然后利用BIOS中斷0x13取磁盤(pán)參數表中當前啟動(dòng)引導盤(pán)的參數,接著(zhù)在屏幕上顯示“Loading system...”字符串。再將system模塊從磁盤(pán)上加載到內存0x10000開(kāi)始的地方。隨后確定根文件系統的設備號。 Setup程序的作用主要是利用ROM-BIOS中斷讀取機器系統數據,并將這些數據保存到0x90000開(kāi)始的位置(覆蓋了bootsect程序所在的地方)。然后setup程序將system模塊從0x10000整塊向下移動(dòng)到內存絕對地址0x0000處,接下來(lái)加載中斷描述符表寄存器(idtr)和全局描述表寄存器(gdtr)。開(kāi)啟A20地址線(xiàn),重新設置兩個(gè)中斷控制芯片8259A,將硬件中斷號重新設置為0x20-0x2f。最后設置CPU的控制寄存器CR0(也稱(chēng)機器狀態(tài)字),從而進(jìn)入32位保護模式進(jìn)行,并跳轉到位于system模塊最前面部分的head.s程序繼續運行。 Head.s程序在被編譯后,會(huì )被連接成system模塊的最前面開(kāi)始部分,即頭部(head)程序。從這里開(kāi)始,內核完全都是在保護模式下運行了。這段程序實(shí)際上處于內存絕對地址0處開(kāi)始的地方。這個(gè)程序功能比較單一,首先是加載各個(gè)數據段寄存器,重新設置中斷描述符表idt,共256項。然后重新設置中斷描述符表gdt,接下來(lái)檢測A20地址線(xiàn)是不是開(kāi)啟了,再檢測PC機是否含有數學(xué)協(xié)處理器芯片,然后設置管理內存的分頁(yè)處理機制,最后利用返回指令將預先放置在堆棧中的/init/main.c程序的入口地址彈出,去運行main()內核初始化程序。
設備驅動(dòng)程序
設備驅動(dòng)程序在Linux內核中扮演著(zhù)特殊的角色,它們是一個(gè)個(gè)獨立的“黑盒子”,使某個(gè)特定的硬件響應一個(gè)定義良好的內部編程接口,同時(shí)完全隱藏了設備的工作細節。用戶(hù)操作通過(guò)一組標準化的調用完成,而這些調用是和特定的驅動(dòng)程序無(wú)關(guān)的。設備驅動(dòng)程序提供的功能是同外設進(jìn)行數據傳送。設備包括三種類(lèi)型:字符設備、塊設備和網(wǎng)絡(luò )接口。每個(gè)模塊通常實(shí)現其中一種類(lèi)型,相應地,模塊可分為字符模塊(char module)、塊模塊(block module)和網(wǎng)絡(luò )模塊(network module)三種。然而這種分類(lèi)方式并不是十分嚴格,程序員可以構建一個(gè)大的模塊,在其中實(shí)現不同類(lèi)型的設備驅動(dòng)程序。三種類(lèi)型的設備如下:
● 字符模塊
字符設備是能夠象字節流(比如文件)一樣被訪(fǎng)問(wèn)的設備,由字符設備驅動(dòng)程序來(lái)實(shí)現這種特性。字符設備驅動(dòng)程序通常至少需要實(shí)現open、close、read和write的系統調用。字符終端(dev/console)和串口(/dev/ttySO以及設備類(lèi)型)就是字符設備的兩個(gè)例子,它們能夠用流抽象很好地表示。
● 塊設備
和字符設備一樣,塊設備也是通過(guò)/dev目錄下的文件系統節點(diǎn)被訪(fǎng)問(wèn)的。塊設備(例如磁盤(pán))上能夠容納文件系統。在大多數Unix系統中,塊設備包括整數個(gè)塊,而每塊包含1KB或2的幾次冪字節的數據。Linux允許應用程序如字符設備那樣讀寫(xiě)塊設備,可以一次傳遞任意多字節的數據。因而,塊設備和字符設備的區別僅僅在于內核內部管理數據的方式,也就是內核和驅動(dòng)程序的接口不同。塊設備的接口必須支持掛裝(mount)文件系統。
● 網(wǎng)絡(luò )接口
任何網(wǎng)絡(luò )事務(wù)都要經(jīng)過(guò)一個(gè)網(wǎng)絡(luò )接口,即一個(gè)能夠和其它主機交換數據的設備。通常接口是個(gè)硬件設備,但也可能是個(gè)純軟件設備,比如回環(huán)(loopback)接口。網(wǎng)絡(luò )接口由內核中的網(wǎng)絡(luò )子系統驅動(dòng),負責發(fā)送和接收數據包,它必須了解每項事務(wù)是如何映射到實(shí)際傳送的數據包的。盡管Telnet和FTP連接都是面向流的,它們都使用了同一個(gè)設備,但這個(gè)設備看到的只是數據包,而不是獨立的流。
在Linux里,除了直接修改系統內核的源代碼,把設備驅動(dòng)程序加進(jìn)內核以外,還可以把設備驅動(dòng)程序作為可加載的模塊,由系統管理員動(dòng)態(tài)的加載和卸載,使之成為內核的一部分。Linux的模塊可以用C語(yǔ)言編寫(xiě),用gcc編譯成目標文件(不進(jìn)行鏈接,作為*.o文件存在),為此需要在gcc命令行里加上-c的參數。由于在不鏈接時(shí),gcc只允許一個(gè)輸入文件,因此一個(gè)模塊的所有部分都必須在一個(gè)文件里實(shí)現。編譯好的模塊*.o放在/lib/modules/xxxx/misc下(xxxx表示內核版本),然后用depmod -a使此模塊成為可加載模塊。模塊用insmod命令加載,用rmmod命令來(lái)卸載,并可以用lsmod命令來(lái)察看所有已經(jīng)加載的模塊的狀態(tài)。編寫(xiě)模塊時(shí)必須提供兩個(gè)函數,一個(gè)是init_module(void),供insmod在加載的時(shí)候自動(dòng)調用,負責進(jìn)行設備驅動(dòng)程序的初始化工作。Init_module返回0表示初始化成功,返回負數表示失敗。另一個(gè)函數是void cleanup_module(void),載模塊卸載時(shí)調用,負責進(jìn)行設備驅動(dòng)程序的清除工作。在成功的向系統注冊了設備驅動(dòng)程序后(調用register_chrdev成功后),就可以用mknod命令來(lái)把設備映射成一個(gè)特別文件,其它程序社用這個(gè)設備的時(shí)候,只要對此特別文件進(jìn)行操作就可以了。
結語(yǔ)
本文主要論述了如何構造嵌入式Linux系統,設計和實(shí)現一個(gè)完整并且小巧使用的嵌入式Linux系統是一個(gè)非常復雜的過(guò)程。由于嵌入式Linux是由標準Linux裁減而來(lái)的,所以需要對Linux的內核有深入的了解。本文所構建的一個(gè)小型嵌入式Linux系統,已成功運用于S3C2410。所欠缺的是構建的內核還不夠小,原因可能是存在一些不必要的硬件驅動(dòng)程序以及庫的裁減不夠理想導致的。今后的工作主要集中在對外設模塊和庫的裁減上,以及開(kāi)發(fā)一些特定硬件的驅動(dòng)程序。 參考文獻: 1 魏永明,駱剛,姜軍譯。Linux設備驅動(dòng)程序(第二版)。中國電力出版社,2002 2 趙炯著(zhù)。Linux內核完全注釋?zhuān)?004 3 馮永紅,朱善君。裁剪Linux技術(shù)分析。2001嵌入式系統及單片機國際學(xué)術(shù)交流會(huì )論文集,2001 本文于2004年8月30日收到。劉新朝:研究生,研究方向為微機控制。
linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)linux相關(guān)文章:linux教程
三維掃描儀相關(guān)文章:三維掃描儀原理
評論