摘 要:在UCOS移植前,必須先要建立一定的硬件環境讓其運行。原始的UCOS實際上構成了具體內核中的外層或高層,而真正位于內核底層的則是CPU。而這兩者之間就由“硬件抽象層”(HAL)來連接。本文在基于HMS30C7202硬件平臺的基礎上,詳細講述了UCOS在HMS30C7202移植中,硬件抽象層的實現步驟。
關鍵詞:UCOS移植;硬件抽象層;中斷二次跳轉
引言
一般常用的嵌入式操作系統和通用操作系統一樣,在內核完成了自身的初始化以后便會創建一個shell進程或者相應的窗口。之后,其他應用進程的創建和啟動就是這個shell進程或者窗口的事情了。然而,像類似于UCOS這類比較小而是專用的嵌入式操作系統就不同了,內核和應用程序之間沒有明確的界限,它們共享一個地址空間,在物理地址或者邏輯地址上都形成一個整體。整個系統的映像中就只有一個入口函數。
UCOS啟動中,系統在完成最初的硬件初始化以后便轉入由開發者提供的main(),在main()中再調用一個內核函數OSInit()來完成內核的初始化,然后在完成了與應用相關的初始化以后,就可以調用一個內核函數OSStart()啟動內核的進程調度。從上面的過程可以看出,main0函數其實是一個回調函數,整個系統的入口其實是在HAL程序中。
HAL簡介
一般HAL中包含著特定CPU的匯編語言編寫的底層函數和數據結構,例如對CPU內部一些特殊寄存器的設置、開中斷/關中斷、中斷向量的設置等等。
在不同類型的操作系統中,HAL存在的形式也有很大的不同。在一體化內核的Linux操作系統中,不存在獨立的HAL。在Linux內核的源碼中,目錄arch/下面就是依賴于各種不同CPU的底層代碼,那就是需要靜態連接到內核中的HAL。所以,Linux所需要的就只是一個基本的引導裝入程序。一旦內核開始運行,引導裝入程序就完成了使命,Linux內核及其應用程序不會調用引導裝入程序中的任何一段代碼。然而在微內核的UCOS操作系統中,內核引導裝入程序與HAL連接在一起,或者說在HAL的基礎上構建內核引導裝入程序。
在Hms30C7202上構建HAL
Hms30c7202是一款基于ARM720T內核的32位處理器。主要特征如下:更詳細的芯片功能介紹請見參考文獻。
·內核運行速率可達70MHz
·8KB綜合指令/數據的cache
·內存管理單元MMU
·支持小端操作系統
·2KBSRAM可用于內部buffer。
如上所說,在ARM上運行UCOS的HAL要完成系統硬件的初始化和操作系統的引導兩個工作。系統的初始化,主要包括下面幾個步驟:
·標志整個代碼的初始入口點
·設置異常中斷向量表
·初始化存儲系統
·初始化MMU
·將已經初始化的數據搬運到可寫的數據區
·初始化各個模式下的數據棧
·初始化一些特殊外圍接口
·安放好中斷處理程序
·使能IRQ異常中斷
以上的步驟中根據處理器中相應的寄存器,進行數據的讀寫即可。但是要注意MMU的初始化和中斷結構的設計。在Hms30c7202中,對于MMU設置如下:
IMPORT LOPageTable
ldrr0,=LOPageTable
mcr
p15,0,r0,c2,c0,0
mvn
rO,#0
mcr
p15,0,r0,c3,c0,0
mov
rO,#CtrlMMU+CtrlCache+CtrlWBuff
mcr
p15,0,rO,c1,c0,0
首先我們將建立好的頁表地址的基址存入寄存器C2(translationtablebase),然后通過寄存器C3設置好內存的訪問權限,最后使能MMU單元,CACHE和BUFF。在LOPageTable開始的內存頁表中,規劃’了4G內存的分配情況。其實根據UCOS的自身特點可以不使用MMU或者將內存映射為1—1的甲板映射就可以。這里將4G的空間劃分開來主要是為了更好的通用性,將來如果引導Linux,就也可以使用這段代碼。
中斷結構和中斷處理程序的設計,應該是HAL中最為重要的一個環節。因為UCOS做為一個多任務操作系統,其本質就是在響應系統指定的時鐘中斷后進行任務切換。為了使中斷處理程序的安裝更為方便,因此采用了中斷二次跳轉的方法。首先在ARM處理器定義的中斷向量處安放跳轉指令,跳轉到指定位置后,再進行位置的第二次映射。其中位置的映射是通過一個匯編定義的宏來實現的。其代碼如下:
MACRO
$SourceHANDLER$Destination
$Source
subsp,sp,#4
stmfdsp!,{rO}
1drr0,=$Destination
ldr ro.[ro]
strl0,[sp,#4]
Idmfd sp!,{r0,pc}
MEND
這樣就可以在程序的任意位置定義自己的中斷處理函數,而不必擔心因為使用B指令帶來的跳轉范圍的限制問題。以[RQ中斷為例:
HandlerlRQ
HANDLERHandlelRQ
IRQ中斷發生時,PC指向地址0X18處,在此處放一條:B HandlerlRQ,程序跳轉到Handler處,根據宏所定義的操作,PC指向HandlelRQ所代表的地址處。也就是說當IRQ中斷發生時,其中斷向量已經是HandleFlQ所代表的地址了,從這個地址再映射到UCOS IRQHANDLER就可以正確的實現IRQ中斷的響應了。Hms30c7202中其他中斷資源也都有自己固定的中斷向量地址,也可以使用類似的方法進行處理。在需要用到的中斷資源對應的中斷向量處,安放相應中斷處理函數的起始地址即可。
在UCOS中需要用到一個周期性的中斷源來產生系統的時鐘節拍。對于Hms 30c7202,可以選擇使用WATCHDOGTimer、RTC或者是Timer來實現。這三者都可以實現周期中斷,只是操作的難易程度不一樣。如果系統要求高精度實時中斷,使用Timer比較奸。如果系統要求比較低的話,用RTC實現則十分的簡單。不管哪一種方法實現,其中斷處理程序是相似的,給出偽代碼如下:
XXX_IRQ_Handler
{
清除中斷標志位
重新設置中斷條件
OSTimeTick()
}
當周期中斷發生時,Hms30c7202先進入IRQ中斷,再來判別中斷源。所以當進入UCOSIRQHANDLER后,在其中因該調用一個C函數來實現中斷源的判別和相應處理函數的運行。
EXPORT UCOS IRQHandler
UCOS IRQHandler
stmfdsp!,{rO-r3,r12,1r}
blOSIntEnter
b1C IRQHandler
blOSIntExit
ldrr0,=OSIntCtxSwFlag
ldrrl,[rO]
cmprl,#1
beq_IntCtxSw
ldmfdsp!,{r0-r3,r12,1r}
subs pc,lr,#4
至此,整個HAL的框架已經建好,按照先前提出的步驟和上面講到的中斷處理的方法,編寫好整個HAL程序和os cpu a.s和os_cpu_c.c中6個關鍵的移植函數。再跳轉到main()程序入口,初始化UCOS操作系統,創建任務,啟動系統時鐘,啟動系統即可運行自己定義的任務。
結語
對于UCOS來講,在其運行以前HAL就已經把運行操作系統所必需的硬件環境建立好,并且隱藏了UCOS在調用系統硬件資源時實現的具體操作細節。從這點可以認為簡單的HAL其實就是一個硬件資源初始化的程序。然而實際上完全可以基于HAL寫一個普通的監控程序或者是引導/裝入程序,甚至是一個內核。ARM公司為操作系統的開發提供了一個HAL,稱為μHAL。μHAL是一組庫程序。ARM公司向用戶提供LlHAL的源代碼和已經編譯好的兩個二進制文件,分別用于“半寄宿(semihost)“和獨立運行(standalone)。具體內容請見參考文獻當然也可以自己編寫這些代碼,本文就是這種情況。這樣做工作量會變大,但是整個程序也許會更加的簡練,執行的效率會更高。注:本文中所涉及到的圖表、注解、公式等內容請以PDF格式閱讀原文。