uClinux操作系統(tǒng)的實(shí)時(shí)化分析與研究
掃描二維碼
隨時(shí)隨地手機(jī)看文章
摘要:增強(qiáng)µClinux的實(shí)時(shí)性能是工業(yè)控制等實(shí)時(shí)性要求高的領(lǐng)域的必然要求,也是µClinux操作系統(tǒng)研究的關(guān)鍵技術(shù)之一。本文將RTAI移植至µClinux系統(tǒng)中,既滿足了嵌入式應(yīng)用的需求,同時(shí)又保證了系統(tǒng)的硬實(shí)時(shí)性。最后,給出了在RTAI+µClinux環(huán)境下開發(fā)實(shí)時(shí)系統(tǒng)應(yīng)用程序的設(shè)計(jì)方法。
關(guān)鍵詞:µClinux;實(shí)時(shí)性;RTAI;實(shí)時(shí)內(nèi)核
1.引言
嵌入式Linux作為一個(gè)開放源代碼的操作系統(tǒng),以價(jià)格低廉、功能強(qiáng)大又易于移植的特性正在被廣泛應(yīng)用,µClinux是專門針對(duì)沒有MMU(Memory Manage Unit)的處理器而設(shè)計(jì)的嵌入式Linux,非常適合中低端嵌入式系統(tǒng)的需求。µClinux雖然符合POSIX1003.1B關(guān)于實(shí)時(shí)擴(kuò)展部分的標(biāo)準(zhǔn),但其最初的設(shè)計(jì)目標(biāo)為通用分時(shí)操作系統(tǒng),如果把µClinux用在工業(yè)控制、進(jìn)程控制等微控制領(lǐng)域內(nèi),必須要增強(qiáng)µClinux的實(shí)時(shí)性能。
目前,對(duì)嵌入式Linux的實(shí)時(shí)化改造方案主要有3種:一種是直接修改內(nèi)核插入搶占點(diǎn)[3],另外一種是資源內(nèi)核方法[4],最后一種是雙內(nèi)核架構(gòu)的解決方案。但3種方法中前兩種都只能用于軟實(shí)時(shí)應(yīng)用,只有雙內(nèi)核[2]架構(gòu)的方案可以保障硬實(shí)時(shí)應(yīng)用需求。目前,Linux平臺(tái)下開發(fā)的具有硬實(shí)時(shí)功能的系統(tǒng)主要有:RTLinux和RTAI[1](Real Time Application Interface)?;赗TAI增強(qiáng)Linux的實(shí)時(shí)性方面研究得比較多,但是,基于RTAI增強(qiáng)µClinux實(shí)時(shí)性方面還未見到成型的產(chǎn)品。因此,本文借鑒RTAI對(duì)Linux的實(shí)時(shí)改進(jìn)機(jī)理,對(duì)µClinux的實(shí)時(shí)性改造進(jìn)行了分析與研究。
2. µClinux的內(nèi)存管理
標(biāo)準(zhǔn)Linux使用虛擬存儲(chǔ)器技術(shù),應(yīng)用在帶有MMU的處理器上,虛擬地址被送到MMU,把虛擬地址映射為物理地址。而µClinux同標(biāo)準(zhǔn)Linux的最大區(qū)別就在于內(nèi)存管理,只有了解它們內(nèi)存管理的差異后,才能更好地利用RTAI對(duì)µClinux進(jìn)行實(shí)時(shí)化改造。
µClinux雖然為嵌入式系統(tǒng)做了許多小型化的工作[5],但µClinux與標(biāo)準(zhǔn)Linux的架構(gòu)完全一致。µClinux雖然無法使用處理器的虛擬內(nèi)存管理技術(shù),但µClinux仍然采用存儲(chǔ)器的分頁(yè)管理,系統(tǒng)在啟動(dòng)時(shí)把實(shí)際存儲(chǔ)器進(jìn)行分頁(yè),在加載應(yīng)用程序時(shí)分頁(yè)加載。一個(gè)進(jìn)程在執(zhí)行前,系統(tǒng)必須為進(jìn)程分配足夠的連續(xù)地址空間,然后全部載入主存儲(chǔ)器的連續(xù)空間中。µClinux采用實(shí)存儲(chǔ)器管理策略,通過地址總線對(duì)物理內(nèi)存進(jìn)行直接訪問。所有程序中訪問的地址都是實(shí)際的物理地址,操作系統(tǒng)對(duì)內(nèi)存空間沒有保護(hù),所有的進(jìn)程都在一個(gè)運(yùn)行空間中運(yùn)行(包括內(nèi)核進(jìn)程)。
在µClinux系統(tǒng)中,缺少了 MMU的內(nèi)存映射,µClinux必須在可執(zhí)行文件加載階段對(duì)可執(zhí)行文件reloc處理,使得程序執(zhí)行時(shí)能夠直接使用物理內(nèi)存;其次,µClinux沒有自動(dòng)生長(zhǎng)的堆棧,也沒有brk()函數(shù),用戶空間的程序必須使用mmap()命令來分配內(nèi)存;同時(shí),在實(shí)現(xiàn)多個(gè)進(jìn)程時(shí)需要實(shí)現(xiàn)數(shù)據(jù)保護(hù),µClinux雖然支持fork()函數(shù),但實(shí)質(zhì)是所有的多進(jìn)程管理都通過vfork()函數(shù)來實(shí)現(xiàn)。vfork()是µClinux與標(biāo)準(zhǔn)Linux應(yīng)用程序的開發(fā)中最重要的不同之處,只有對(duì)vfork()與fork()兩個(gè)函數(shù)的差異和程序處理機(jī)制有詳細(xì)的了解后,才能順利地完成從Linux到µClinux的程序移植。
3. 基于RTAI的Linux硬實(shí)時(shí)支持方案
3.1 RTAI簡(jiǎn)介
RTAI for Linux[6]是雙內(nèi)核架構(gòu)的Linux實(shí)時(shí)化方案的典型代表,它由意大利的Milan大學(xué)主持,是近年來非常活躍的開源項(xiàng)目。系統(tǒng)的實(shí)現(xiàn)基礎(chǔ)是在Linux上定義了一組實(shí)時(shí)硬件抽象層RTHAL(Real Time Hardware Abstraction Layer),通過RTHAL進(jìn)行硬件管理,把基本內(nèi)核和實(shí)時(shí)內(nèi)核結(jié)合在一起,其中一個(gè)內(nèi)核的改變,不會(huì)影響另一個(gè)內(nèi)核的執(zhí)行,RTHAL將RTAI需要在Linux中修改的部分定義成一組程序界面,RTAI只使用這組界面和Linux溝通,其系統(tǒng)結(jié)構(gòu)如圖1所示。
3.2 RTAI的RTHAL
RTAI從內(nèi)核中提取一個(gè) RTHAL,RTAI首先是一個(gè)中斷分發(fā)器,當(dāng)RTAI模塊被加載后,CPU中斷仍由Linux管理,RTAI只接管外部設(shè)備的中斷并分發(fā)(有可能仍分發(fā)給Linux)。這種接管是通過RTHAL來實(shí)現(xiàn)的,RTHAL包含一些重要的函數(shù)和數(shù)據(jù)結(jié)構(gòu),RTAI模塊可能修改的內(nèi)容都收集在此結(jié)構(gòu)體中.
當(dāng)RTAI裝載時(shí),只需要重新設(shè)置RTHAL中的各項(xiàng)內(nèi)容。內(nèi)核需要修改執(zhí)行RTHAL以代替原來的內(nèi)容,如
do_IRQ(irq,&dummy);
被修改為:
rthal.c_do_IRQ(irq,&dummy);
Linux初始化RTHAL為指向原始的函數(shù)和數(shù)據(jù)結(jié)構(gòu),RTHAL僅僅進(jìn)行重定向。當(dāng)RTAI被激活,RTHAL保存并且改變這些函數(shù)的值為RTAI自己的內(nèi)容。以上段代碼為例,當(dāng)RTAI還沒有加載時(shí),rthal.c_do_IRQ的值就是Linux的do_IRQ,當(dāng)RTAI被加載時(shí),RTAI執(zhí)行以下代碼,將rthal.c_do_IRQ替換成RTAI自己的分發(fā)器:
rthal.c_do_IRQ=dispatch_irq;
3.3 RTAI的中斷處理機(jī)制
RTAI的最核心部分就是其中斷處理機(jī)制。RTAI構(gòu)建了一個(gè)小實(shí)時(shí)內(nèi)核接管硬件及中斷,支持EDF,RM兩種經(jīng)典實(shí)時(shí)調(diào)度算法,Linux作為此實(shí)時(shí)內(nèi)核的最低優(yōu)先級(jí)任務(wù)被執(zhí)行。因而實(shí)時(shí)任務(wù)執(zhí)行時(shí),Linux及其應(yīng)用程序?qū)⒈粨屨?。RTAI引入了軟中斷模擬技術(shù),在發(fā)生硬件中斷時(shí),實(shí)時(shí)內(nèi)核只是把它放到中斷記錄表中,在沒有實(shí)時(shí)應(yīng)用運(yùn)行時(shí)才向Linux派發(fā)這些被保留的中斷。同時(shí)實(shí)時(shí)內(nèi)核還監(jiān)控Linux的開/關(guān)中斷原語,以避免這些操作把實(shí)際的中斷關(guān)閉而影響實(shí)時(shí)內(nèi)核的響應(yīng)時(shí)間。主要包括以下幾個(gè)方面:
①函數(shù)替換
首先是Linux的開/關(guān)中斷等函數(shù)被RTAI提供的函數(shù)所替代,這樣Linux不能真正的關(guān)閉中斷,而只是一個(gè)軟件的機(jī)制。當(dāng)外設(shè)中斷到來時(shí),RTAI的替換函數(shù)必須檢查硬件中斷標(biāo)志是否關(guān)閉和調(diào)用是否來自RTAI上下文。在此兩種情況之下,不能直接調(diào)用Linux的中斷處理函數(shù),中斷分發(fā)器只用于當(dāng)CPU處于Linux上下文并且Linux開中斷時(shí),才調(diào)用Linux的中斷處理例程(ISR)。
②全局變量
RTAI為每個(gè)中斷源定義了一個(gè)全局的數(shù)據(jù)結(jié)構(gòu):[!--empirenews.page--]
struct linux_irq{struct list_head list;
int irq;
int masked;
int pending;}
其中l(wèi)ist_head用于從Linux的中斷掛起隊(duì)列中插入或刪除。irq被初始化為此結(jié)構(gòu)體所對(duì)應(yīng)的中斷號(hào)。masked是一個(gè)標(biāo)志位,可能具有以下3種值:1表示在中斷延遲函數(shù)中設(shè)置;2表示由Linux中斷mask函數(shù)設(shè)置;3表示由Linux中斷unmask函數(shù)設(shè)置。
③中斷傳遞
中斷傳遞可能被RTAI中斷分發(fā)器或Linux的開中斷函數(shù)所調(diào)用。當(dāng)Linux打開中斷時(shí),檢查掛起中斷鏈表是否為空,若不為空,則循環(huán)進(jìn)行處理,直到所有中斷都被處理為止。其算法如下:
while(irqlist 不空){
從irqlist隊(duì)列中取出一個(gè)中斷;
if(該中斷正在被屏蔽) continue;
else{關(guān)閉Linux中斷;執(zhí)行中斷處理例程;開中斷;}}
3.4 RTAI的任務(wù)調(diào)度
①細(xì)粒度定時(shí)器的實(shí)現(xiàn)
標(biāo)準(zhǔn)Linux的定時(shí)器提供10ms的調(diào)度粒度,不足以達(dá)到實(shí)時(shí)響應(yīng)速度的要求。RTAI通過提高系統(tǒng)時(shí)鐘精度改寫了時(shí)鐘處理程序,使之支持更高分辨率時(shí)鐘的周期模式,引入了兩種定時(shí)器模式:periodic(周期性)和one shot(一次性)。對(duì)于周期性實(shí)時(shí)任務(wù)應(yīng)用periodic模式,只需要在初始化時(shí)對(duì)定時(shí)器進(jìn)行設(shè)置,保證了處理效率;對(duì)于非周期實(shí)時(shí)任務(wù)應(yīng)用one shot模式。在任何時(shí)刻,時(shí)鐘的下一次中斷間隔由所有定時(shí)器中到期最早的一個(gè)來決定。一旦定時(shí)器到期,內(nèi)核便能夠立刻響應(yīng),內(nèi)核的響應(yīng)開銷只由中斷服務(wù)的時(shí)間所決定,使得實(shí)時(shí)應(yīng)用的響應(yīng)時(shí)間可以達(dá)到納秒級(jí)的水平,完全可以滿足一般工業(yè)應(yīng)用實(shí)時(shí)控制的要求。
②調(diào)度機(jī)制
在實(shí)時(shí)任務(wù)之間、實(shí)時(shí)任務(wù)與Linux應(yīng)用之間提供豐富的通訊機(jī)制(如FIFO管道、MBUFF共享內(nèi)存等)進(jìn)行通信;Linux應(yīng)用可以通過這些通訊機(jī)制與實(shí)時(shí)應(yīng)用交互,同時(shí)也可以通過實(shí)時(shí)內(nèi)核中的實(shí)時(shí)應(yīng)用代理(LXRT)運(yùn)行實(shí)時(shí)任務(wù)。
任何實(shí)時(shí)任務(wù)的優(yōu)先級(jí)都要高于Linux,只有當(dāng)沒有實(shí)時(shí)任務(wù)運(yùn)行時(shí),Linux才被調(diào)度,從而保證了RTAI的實(shí)時(shí)性。任務(wù)的調(diào)度周期在任務(wù)初始化時(shí)由程序員指定,也可在某個(gè)時(shí)刻調(diào)用API修改。 rt_task_struct包含多個(gè)雙向指針,所有的任務(wù)(包括Linux)都包括在各個(gè)鏈表中。如ready任務(wù)鏈表,其中Linux為鏈表頭,當(dāng)發(fā)生調(diào)度時(shí),RTAI在ready鏈表中搜尋優(yōu)先級(jí)最大的任務(wù)并切換執(zhí)行,當(dāng)沒有實(shí)時(shí)任務(wù)在ready態(tài)時(shí),則切換至Linux系統(tǒng)。
4. RTAI在µClinux上的移植
4.1 RTHAL的移植
借鑒RTHAL的思想,對(duì)µClinux核心進(jìn)行改動(dòng),將其與中斷控制器隔離,核心中的所有中斷操作指令都被替換成相應(yīng)的宏。對(duì)于RTAI的移植而言,最重要的部分就是RTHAL的移植,RTAI絕大部分與處理器相關(guān)的代碼都在這里,這里以作者所使用的S3C4510B(ARM7的核)和µClinux環(huán)境為例進(jìn)行說明。由于RTAI已經(jīng)有ARM處理器上的版本,因此可以參照 ARM7處理器的RTHAL來移植到S3C4510B上。由于µClinux為針對(duì)沒有MMU處理器的操作系統(tǒng),因此RTAI需要去除與MMU相關(guān)的代碼。對(duì)于S3C4510B和µClinux,其RTHAL主要包括如下數(shù)據(jù)結(jié)構(gòu):
{指向IDT的指針;
打開/關(guān)閉中斷函數(shù)(cli,sti&flags);
控制中斷mask/unmask函數(shù);
中斷狀態(tài)的數(shù)據(jù)描述符(status,hander,nestedlevel,…);}
4.2定時(shí)器的移植
如前面分析,對(duì)于一個(gè)實(shí)時(shí)操作系統(tǒng),必須有精確的計(jì)時(shí)。在i386體系結(jié)構(gòu)中,有時(shí)間標(biāo)簽計(jì)數(shù)器TSC(Time Stamp Count),在S3C4510B處理器上沒有這個(gè)寄存器,可以采用計(jì)時(shí)器2(Timer1)來模擬TSC的功能。每來一個(gè)時(shí)鐘脈沖,Timer1的 TCNT1寄存器減1,減到零后產(chǎn)生時(shí)鐘中斷,再?gòu)腡DATA1中讀TCNT1的值,往復(fù)運(yùn)行。具體的做法是使用一個(gè)內(nèi)核的全局變量,每次時(shí)鐘中斷來以后,在Timer1的寄存器中讀出值,計(jì)算其增量,為了使系統(tǒng)更精確,必須將Timer1中斷設(shè)置為最高優(yōu)先級(jí),這樣就可以模擬64位的TSC寄存器,從而得到當(dāng)前的準(zhǔn)確計(jì)時(shí)。
5.基于RTAI與µClinux的應(yīng)用程序的開發(fā)
編寫應(yīng)用程序時(shí),將實(shí)時(shí)系統(tǒng)的應(yīng)用程序分為實(shí)時(shí)任務(wù)和非實(shí)時(shí)任務(wù)。實(shí)時(shí)任務(wù)是實(shí)時(shí)模塊,作為µClinux核心可加載模塊運(yùn)行在核心態(tài)。它的設(shè)計(jì)應(yīng)盡可能簡(jiǎn)單,僅包含那些有強(qiáng)實(shí)時(shí)要求的處理模塊,如實(shí)時(shí)數(shù)據(jù)采集、外部設(shè)備控制等。非實(shí)時(shí)任務(wù)是普通的µClinux進(jìn)程,在用戶態(tài)執(zhí)行,完成大部分的數(shù)據(jù)處理、圖形顯示和通訊等任務(wù)。所有的實(shí)時(shí)任務(wù)均按照對(duì)實(shí)時(shí)性要求的高低來進(jìn)行優(yōu)先級(jí)排隊(duì),系統(tǒng)根據(jù)優(yōu)先級(jí)的高低來順序啟動(dòng)各個(gè)實(shí)時(shí)任務(wù)。而位于用戶態(tài)的界面,當(dāng)作一個(gè)背景程序來執(zhí)行。核心態(tài)的任務(wù)優(yōu)先級(jí)總是高于用戶態(tài)的界面任務(wù),且不能被其搶占。實(shí)時(shí)任務(wù)和非實(shí)時(shí)任務(wù)之間可通過FIFO隊(duì)列和共享內(nèi)存等方法通信?;赗TAI的µClinux應(yīng)用程序結(jié)構(gòu)圖如圖2所示。
實(shí)時(shí)系統(tǒng)的啟動(dòng)和結(jié)束可以用一個(gè)Shell程序來執(zhí)行,它的功能是實(shí)現(xiàn)各任務(wù)模塊的加載和卸載,以及用戶界面的運(yùn)行。Shell程序是介于使用者和操作系統(tǒng)的內(nèi)核程序間的一個(gè)界面,使用戶更為方便的使用操作系統(tǒng)。由于各個(gè)模塊之間具有相互依賴性,所以在加載和卸載各個(gè)模塊時(shí)按照一定的順序。首先要將RTAI提供的實(shí)時(shí)模塊加載,包括rtai、rtai_sched、 rtai_fifos和rtai_shm等模塊;然后裝入系統(tǒng)的各個(gè)實(shí)時(shí)模塊。卸載模塊的時(shí)候按照相反的順序依次卸載。實(shí)時(shí)系統(tǒng)的程序流程圖如圖3所示。
6.結(jié)束語
作者已將改造后的µClinux系統(tǒng)應(yīng)用在了江蘇省普通高校自然科學(xué)研究計(jì)劃資助項(xiàng)目“機(jī)房環(huán)境設(shè)備安全監(jiān)控軟件平臺(tái)的研制”等項(xiàng)目中,均取得了良好的效果,解決了µClinux在實(shí)時(shí)性方面的缺陷,滿足了設(shè)計(jì)要求。
本文作者創(chuàng)新點(diǎn)是:實(shí)現(xiàn)了RTAI在µClinux上的移植,形成了RTAI和µClinux相結(jié)合的雙內(nèi)核嵌入式系統(tǒng)運(yùn)行方案,既滿足了嵌入式應(yīng)用的需求,又保證了系統(tǒng)的硬實(shí)時(shí)性。