基于MIPS32平臺(tái)的Linux操作系統(tǒng)移植
引言
目前,linux作為僅次于微軟windows的操作系統(tǒng)已經(jīng)在pc和嵌入式領(lǐng)域得到了廣泛的應(yīng)用,尤其是在嵌入式開(kāi)發(fā)領(lǐng)域,由于linux操作系統(tǒng)具有成本低,可靠性高,源碼方法等顯著的優(yōu)點(diǎn),已經(jīng)成為受眾多嵌入式開(kāi)發(fā)者青睞的操作系統(tǒng)之一。目前,linux操作系統(tǒng)所支持的包括x86、arm、mips、mips64、sun
sparc、power pc、motorola 68k、ibm s/390、alpha、ia64、cris、parisc、sh等主要的體系結(jié)構(gòu)。本文以實(shí)際項(xiàng)目中一個(gè)mips32架構(gòu)的cpu和板級(jí)系統(tǒng)為例,闡述了如何將linux操作系統(tǒng)移植到目標(biāo)平臺(tái)上。
1 目標(biāo)平臺(tái)概述
本文所討論的開(kāi)發(fā)平臺(tái)采用的cpu是同濟(jì)大學(xué)微電子中心自主開(kāi)發(fā)的bc320處理器,采用mips 4kc的體系結(jié)構(gòu),帶mmu、無(wú)浮點(diǎn)協(xié)處理器、標(biāo)準(zhǔn)5段流水線,指令及數(shù)據(jù)cache的大小各為4kb,尋址空間為4gb,其中0x00000000-0x7fffffff為用戶空間,0x80000000-0xffffffff為核心空間,板級(jí)系統(tǒng)采用了pmc的pm8172芯片組,支持最高128mb的sdram,boot
rom的地址空間是0x1fc00000-0x1fffffff。
2 linux交叉編譯環(huán)境的建立及內(nèi)核配置和編譯
在進(jìn)行實(shí)際的linux操作系統(tǒng)移植之前,需要在宿主機(jī)上建立圖1所示的mips的交叉編譯環(huán)境,以便能在普通pc機(jī)上通過(guò)交叉編譯工具來(lái)調(diào)試運(yùn)行在目標(biāo)開(kāi)發(fā)板上的程序。
建立mips交叉編譯環(huán)境的主要工具有binutils、gcc、glibc以及作為調(diào)試器的gdb等,其中binutils為二進(jìn)制文件的處理工具,它主要包括一些輔助開(kāi)發(fā)工具,例如:readelf可顯示elf文件信息及段信息;nm可列出程序的符號(hào)表;strip將不必要的代碼去掉以減小可執(zhí)行文件,objdump可用來(lái)顯示返匯編代碼等,gcc是gnu提供的支持多種輸入高級(jí)語(yǔ)言與多種輸出機(jī)器碼的編譯器,是linux操作系統(tǒng)的配套編譯器,支持linux所采用的擴(kuò)展c語(yǔ)言。glibc是連接和運(yùn)行庫(kù),由于此鏈接和運(yùn)行庫(kù)須運(yùn)行在目標(biāo)開(kāi)發(fā)板上,所以必須用先前建立的交叉編譯器對(duì)其進(jìn)行編譯,如圖內(nèi)核大小要求較為苛刻。還可以使用uclibc等其他鏈接和運(yùn)行庫(kù)作為glibc的替代品,此外,若不是從硬盤啟動(dòng),則還須為linux制作ramdisk。在ramdisk上,除了要安放/dev(放置linux操作系統(tǒng)所需要的設(shè)備文件)、/etc(放置linux系統(tǒng)配置文件)、/lib(放置交叉編譯后生成的庫(kù)文件)等目錄及其下的文件外,還需要在/bin和/sbin下放置各種系統(tǒng)必需的命令程序,如shell、init、vi等,為此需要busybox或者tinylogin等專為linux操作系統(tǒng)提供的標(biāo)準(zhǔn)工具程序。凡此種種,都可以在gnu旗下的網(wǎng)站下載并自由修改其源代碼。
由于linux操作系統(tǒng)的內(nèi)核源代碼支持各種不同的體系結(jié)構(gòu)和不同的應(yīng)用需要,所以在使用交叉譯碼器編譯前還需要進(jìn)行內(nèi)核的配置工作,包括選擇處理器的體系結(jié)構(gòu)、文件系統(tǒng)的種類、板級(jí)支持,對(duì)設(shè)備驅(qū)動(dòng)的支持以及是否使用ramdisk等。配置工具包括make
config、make menuconfig、make xconfig,推薦使用操作界面更為良好的make menuconfig及make
xconfig。在內(nèi)核配置工作完成后即可進(jìn)行內(nèi)核編譯工作,linux源代碼提供的強(qiáng)大的makefile功能,使得復(fù)雜的編譯過(guò)程操作起來(lái)并不困難。
關(guān)于linux交叉編譯環(huán)境的建立及內(nèi)核配置和編譯的詳細(xì)流程,在《building embedded linux systems》(karim
yaghmour著)內(nèi)有詳細(xì)的論述,本文為此不再贅述。
3 linux移植中實(shí)際指令集小于標(biāo)準(zhǔn)mips指令集的問(wèn)題
隨著軟件可移植問(wèn)題在整個(gè)軟件方法學(xué)中重要性的日益增長(zhǎng),各種大型軟件無(wú)不把提高自身的跨平臺(tái)性作為軟件設(shè)計(jì)的主要目標(biāo)之一。為此,linux提供了對(duì)應(yīng)用領(lǐng)域內(nèi)各大主流體系結(jié)構(gòu)的支持,僅以mips體系結(jié)構(gòu)為例,linux操作系統(tǒng)2.4.26版本的內(nèi)核就支持幾乎所有32位和64位不同版本的mips架構(gòu),為操作系統(tǒng)的移植工作提供了巨大的便利。然而,處于種種原因(諸如專利保護(hù)或特殊應(yīng)用),有相當(dāng)一部分采用mips體系結(jié)構(gòu)的芯片產(chǎn)品只提供了標(biāo)準(zhǔn)的mips指令集的一個(gè)子集。一旦內(nèi)核代碼在編譯完成后生成了不屬于實(shí)際指令集的指令,cpu將發(fā)生保留指令例外,可以說(shuō),當(dāng)體系結(jié)構(gòu)間的差異不再成為最主要的移植工作時(shí),如何邏輯等效地消除實(shí)際指令集和標(biāo)準(zhǔn)指令集間的差異成了linux移植工作中最重要的一環(huán),由于mips的專利保護(hù),相當(dāng)多mips兼容芯片的開(kāi)發(fā)者并未對(duì)指令集的4條非對(duì)齊存取指令(lwl、lwr、swl、swr)加以實(shí)現(xiàn),如realtek
rtl8181"wireless lan access point/gateway controller"等,下文將以同濟(jì)大學(xué)自主開(kāi)發(fā)的bc320芯片為例,從修改內(nèi)核源代碼、修改編譯器及匯編器這兩個(gè)方面出發(fā),討論如何解決4條非對(duì)齊存取指令未被實(shí)現(xiàn)的問(wèn)題,由于編譯器及匯編器的修改涉及編譯原理方面的知識(shí),不在本文范圍之內(nèi),所以將把重點(diǎn)放在討論修改內(nèi)核源代碼的方法上,對(duì)gcc和gas修改的基本知識(shí)僅作一般介紹。
3.1 修改內(nèi)核源代碼中的保留指令例外處理程序
當(dāng)cpu執(zhí)行到未被實(shí)現(xiàn)的機(jī)器碼時(shí),將會(huì)發(fā)生reserved instruction exception,然后根據(jù)例外的種類跳轉(zhuǎn)到相應(yīng)的例外處理程序入口處。借助于編寫對(duì)應(yīng)的例外處理程序,可以為被實(shí)際指令集實(shí)現(xiàn)但又屬于標(biāo)準(zhǔn)指令集的指令(iwl、lwr、swl、swr為例)提供邏輯等效的替換方法。在linux內(nèi)核源(以2.4.26版本為例)代碼的目錄樹下進(jìn)入.archmipskernal目錄,打開(kāi)traps.c文件,并添加simulate_lxri函數(shù),代碼如下:
其中:_op_為宏操作,可取出32位機(jī)器碼中的操作碼以判斷操作類型;0x22對(duì)應(yīng)于lwl指令、0x26對(duì)應(yīng)于lwr指令,0x2a對(duì)應(yīng)于swl指令,而0x2e則對(duì)應(yīng)于swr指令。程序?qū)⒏鶕?jù)不同的操作碼進(jìn)入不同的替代程序。va和byte變量則計(jì)算出4條非對(duì)齊指令的偏移量。
完成代碼后將此函數(shù)添加到同一文件的do_ri函數(shù)中去,此函數(shù)即負(fù)責(zé)處理linux操作系統(tǒng)的保留指令例外,添加的代碼為:
if(simulate_lxri(regs,opcode)){
compute_return_epc(regs);
return;
}
即當(dāng)simulate_lxri正確處理完非對(duì)齊存取指令并返回1后,系統(tǒng)將通過(guò)compute_return_epc函數(shù)把epc寄存器的值放回pc寄存器并返回;否則,繼續(xù)處理do_ri中其他的例外處理程序。
這一方法工作量小,容易保證修改后的等效性,大多數(shù)熟悉c語(yǔ)言的程序員來(lái)說(shuō)都是易于掌握的。在軟硬件協(xié)同開(kāi)發(fā)的系統(tǒng)設(shè)計(jì)前期具有很大的實(shí)際使用價(jià)值。系統(tǒng)設(shè)計(jì)師可快速建立原型機(jī)跑通操作系統(tǒng),以驗(yàn)證軟硬件的正確性。但由于其采用的是例外處理的方式,若頻繁發(fā)生例外則將影響系統(tǒng)性能,所以對(duì)memcpy(此函數(shù)代碼在linux源代碼的rachmipslib目錄下的memcpy.s文件中)這樣使用頻繁的匯編程序應(yīng)手工修改其代碼。再加上編譯器一般不會(huì)生成4條非對(duì)齊指令(僅當(dāng)c程序中的結(jié)構(gòu)體有非字對(duì)齊等少數(shù)情況下會(huì)出現(xiàn)),所以此修改方法可保證大致接近原性能。
3.2 修改gcc編譯器或gas匯編器
盡管利用exception handler來(lái)解決保留指令例外問(wèn)題方便、快捷、但其效率終究是低于直接修改gcc編譯器或gas匯編器的,此外,修改exception
handler的方法在smp的情況下有可能帶來(lái)沖突,所以,直接修改gcc或gas的方法是有其實(shí)用價(jià)值的。
gcc的前端可以支持多種語(yǔ)音,后端可以支持多種體系結(jié)構(gòu),這一特性是由作為中間語(yǔ)言的rtl(寄存器傳輸語(yǔ)言)實(shí)現(xiàn)的,其大致結(jié)構(gòu)如圖2所示。
其中負(fù)責(zé)指令生成的部分在后端,涉及的源代碼文件包括inst-cmit.c、inst-flags.h、inst-config.h、inst-code.h、inst-extrax.h、inst-opinit.c、inst-output.c等。此外,作為機(jī)器描述的machine.h、machine.md、machine.h文件也必須加以考慮,相當(dāng)一部分以inst開(kāi)頭的文件是由gcc提供的一組gen*工具根據(jù)這3個(gè)機(jī)器描述文件自動(dòng)生成的。
修改gas相對(duì)簡(jiǎn)單,只須修改gas源代碼中的tcmips.c文件,但效率相對(duì)低于修改gcc源代碼。
直接修改gcc編譯器的效率且一勞永逸,但由于編譯器的實(shí)現(xiàn)原理和操作系統(tǒng)大相徑庭,所以此方法難度較大,可能會(huì)拖延移植工作進(jìn)度,而編譯器修改其本身的測(cè)試工作由于要和linux操作系統(tǒng)的移植工作混合在一起進(jìn)行,對(duì)軟件debug來(lái)說(shuō)也是相當(dāng)復(fù)雜的,所以,在系統(tǒng)開(kāi)發(fā)早期推薦使用修改保留指令例外處理程序的方法,當(dāng)軟硬件都能保證相當(dāng)?shù)恼_性時(shí)再使用修改gcc編譯器的方法。
結(jié)語(yǔ)
本文根據(jù)一個(gè)特定的開(kāi)發(fā)平臺(tái),介紹了如何將linux操作系統(tǒng)移植到mips體系結(jié)構(gòu)系統(tǒng)上的大致流程和主要技術(shù),就移植過(guò)程中所遇到的問(wèn)題,以4條非對(duì)齊指令為例,具體討論了如何解決實(shí)際實(shí)現(xiàn)的指令集未能完全覆蓋標(biāo)準(zhǔn)指令集而產(chǎn)生保留指令例外的問(wèn)題,文中詳細(xì)介紹了修改保留指令例外處理程序的方法,簡(jiǎn)述了修改gcc或gas的方法,掌握這些移植流程和修改技術(shù),對(duì)于開(kāi)發(fā)嵌入式系統(tǒng)相當(dāng)?shù)膶?shí)用價(jià)值,對(duì)于由其他體系結(jié)構(gòu)實(shí)現(xiàn)的開(kāi)發(fā)平臺(tái)也具有相當(dāng)?shù)膮⒖家饬x。
評(píng)論