摘 要:VxWorks是專門為實時嵌入式系統設計開發的操作系統,為編程人員提供了高效的實時多任務調度、中斷管理、實時的系統資源以及實時的任務間通信。提出了一種以嵌入式微處理器為核心,移植VxWorks操作系統的方法。通過對VxWorks輸入/輸出系統的分析以及中斷處理和異常處理過程的研究,設計了相應的外圍器件,成功實現了VxWorks操作系統的移植。
關鍵詞:VxWorks;嵌入式微處理器;實時
中圖分類號:TP303文獻標志碼:A
文章編號:1001-3695(2007)06-0262-03
VxWorks是美國Wind River System公司(即WRS)開發的一個嵌入式實時操作系統(RTOS)。WRS 公司組建于1981年,是一個專門從事實時操作系統開發與生產的軟件公司,該公司在實時操作系統領域被世界公認為是最具有領導地位的公司。VxWorks是一個運行在目標機上的高性能、可裁減的嵌入式實時操作系統,以其良好的可靠性和卓越的實時性被廣泛地應用在通信、軍事、航空、航天等高精尖技術及實時性要求極高的領域中。主要商業用戶包括Cisco System、Bay Networks、3Com、Fore System、HP、Lucent、Qualcomm等著名公司,應用實例包括著名的火星探測車、愛國者導彈等[1]。
西北工業大學航空微電子中心基于自主研發的32位RISC結構高性能嵌入式微處理器,通過對VxWorks輸入輸出系統的分析以及中斷處理和異常處理過程的研究,設計了必要的外圍器件,實現了VxWorks操作系統的移植。
本文對VxWorks操作系統進行了分析,對嵌入式微處理器及其外圍器件進行了介紹,并分析了移植后的VxWorks操作系統的輸入輸出函數,討論了移植后的VxWorks操作系統的中斷處理過程和異常處理過程。
1 嵌入式實時操作系統VxWorks
VxWorks操作系統是一個具有可伸縮、可裁減、高可靠性,同時適用于所有流行CPU平臺的實時操作系統[2]。
根據面向嵌入式系統的需求,對VxWorks操作系統進行了裁減,裁減后的主要組件包括BSP(Board Support Package)、微內核Wind及輸入/輸出系統。
BSP:VxWorks采用模塊化設計方法,把依賴于硬件環境的函數和信息分離出來,放入稱為BSP的組件中,保證BSP可以向上層軟件提供一致的接口。BSP中包括硬件環境中CPU的初始化及系統各項硬件資源的安裝和配置,包括RAM、Clock、中斷控制器等。
Wind:微內核Wind是WindRiver公司自行開發的一種嵌入式操作系統內核,該內核具有標準的嵌入式實時操作系統的基本特征,如可裁減性、搶占式任務調度、異步事件響應等。
輸入/輸出:VxWorks的輸入/輸出系統提供了操作系統與各硬件設備的接口,主要包括字符設備、串行設備、塊設備、虛擬設備(管道、Socket)、監控設備和網絡設備等。
在嵌入式系統中運行VxWorks操作系統使用的是一種壓縮的ROM駐留型鏡像,編譯后生成的壓縮型的VxWorks鏡像文件被固化在一片Flash中。當系統上電后,首先將VxWorks鏡像文件經解壓后拷貝到內存中,然后再運行。這種啟動方式,在上電后的開始階段,程序由于需要解壓縮,系統的啟動時間較長,但是這種VxWorks的鏡像文件比非壓縮型的VxWorks鏡像文件占用的空間要少得多(接近一半)。
整個系統的啟動流程如圖1所示。
圖1 VxWorks 操作系統啟動流程
具體的執行過程是:
在Usrinit函數中首先調用sysStart函數,清除BSS(0填充),設置向量表基址。然后執行cacheLibInit函數,加入對Cache的支持。執行excVecInit函數初始化異常處理向量。執行sysHwInit函數,進行硬件初始化,調用sysSerialHwInit函數(它對串口進行了初始化)。調用usrCacheEnable函數,使用戶指令和數據高速緩存可用。調用usrKernelInit函數,對操作系統的核進行初始化,使usrroot函數為根任務,并使之執行。
在usrroot函數中首先調用usrKernelCoreInit函數,進行操作系統核的主要部分初始化(信號量、消息隊列、“看門狗”定時器、以及調用taskHookInit函數等)。然后調用memInit函數,進行內存管理器的初始化。調用usrMmuInit函數,初始化MMU。調用sysClkInit函數,進行系統時鐘的初始化。調用selectInit函數進行select library的初始化。調用usrIosCoreInit函數,對輸入/輸出系統的核心部分進行初始化。調用usrBootLineParse函數,解析Boot Device的配置信息,主要是與網絡相關的信息,如IP地址等。調用iosInit函數,對輸入/輸出系統進行初始化。調用ttyDrv函數,初始化并安裝串行設備。調用usrSerialInit函數,創建與串行通道對應的tty設備。調用usrKernelExtraInit函數,對操作系統的其他部分進行初始化(如hash table、symbol table及signal(信號)。調用usrIosExtraIni函數,對輸入/輸出其他部分進行初始化。調用selTaskDeleteHookAdd函數支持對任務的管理。調用usrToolsInit函數,對software development tools的初始化。調用cplusCtorsLink函數、usrCplusLibInit函數、cplusDemanglerInit函數,它們是和支持C++編譯相關的函數。調用usrAppInit函數,此函數存放于usrAppInit.c中,當需要編寫應用程序時,有關啟動應用程序的代碼放在usrAppInit函數中。
待usrroot函數中的所有函數執行完后再將被掛起的Shell重新激活,進入交互式的Shell中,等待用戶的命令輸入。
2 嵌入式微處理器及外圍器件
如圖2所示,根據面向嵌入式系統的需求,以嵌入式微處理器為核心,設計了包括控制外部SRAM、串行設備、Flash的存儲控制單元,用于中斷處理的中斷控制器,與微處理器連接的微處理器接口單元,用于總控的中央控制單元,保存配置信息的配置寄存器單元等[3]。
圖2 嵌入式系統總體結構圖
3 VxWorks輸入/輸出系統
在嵌入式系統中主要通過串行口來進行人機交互,所以使用的VxWorks操作系統的輸入/輸出系統就主要是指串行設備。
在VxWorks中,串行設備是一種特殊的設備,它既是VxWorks下的輸入/輸出系統,同時又是目標機的調試接口;它既可以工作在中斷模式,又可以工作在輪詢模式下。除此之外,串行設備驅動程序還要實現一些與設備無關的功能:將回車符輸出映射成回車換行輸出;提供命令行編輯能力;對輸入/輸出的數據進行緩沖等。
串行設備的驅動程序不是安裝在驅動程序列表中,而是通過回調方式掛在終端虛擬設備上。由于驅動程序的安裝方式不同,系統也就不會將串行設備驅動程序掛在設備列表上,即輸入/輸出系統是看不到串行設備的。
在輸入/輸出系統方面,終端虛擬設備作為一個字符型設備存在,它將自身的入口點函數掛在輸入/輸出系統上,創建設備描述符并將其加入到設備列表中。當用戶有輸入/輸出請求到達輸入/輸出系統時,該系統會調用終端虛擬設備相應的函數響應請求。同時,終端虛擬設備管理了緩沖區的互斥,提供了任務的同步操作。對于該系統,與之打交道的設備是終端虛擬設備。
另一方面,終端虛擬設備負責與實際的設備驅動程序交換信息。通過設備驅動程序提供的回調函數及必要的數據結構,終端虛擬設備將系統的輸入/輸出請求做相應的處理后,傳遞給設備驅動程序,由設備驅動程序來完成實際的輸入/輸出操作。
對于串行設備輸入,串行設備會發送一個輸入請求,等待讀中斷響應后將數據寫入輸入緩沖區,一旦緩沖區不為空時,則用戶程序或者操作系統的讀函數(在數據準備好以前已經處于等待狀態)會調用終端虛擬設備讀函數,將數據從輸入緩沖區拷貝到用戶緩沖區,對于用戶而言這是讀串行設備的過程。
對于串行設備輸出,用戶程序或者操作系統往串行設備寫數據時會調用寫函數而發出輸出請求, 輸入/輸出系統會調用終端虛擬設備相應的終端虛擬設備的寫函數將數據寫到輸出環形緩沖區,同時會啟動一次終端虛擬設備發送請求函數,終端虛擬設備發送請求函數會調用真實的串行設備啟動函數引發寫中斷,然后調用中斷將數據送到串行設備,對于用戶而言這是寫串行設備的過程。
3.1 輸入系統
VxWorks的輸入/輸出系統輸入函數主要是通過調用終端虛擬設備層終端虛擬設備庫中的終端虛擬設備讀函數,終端虛擬設備讀函數通過同步信號量與讀中斷通信來解決對讀緩沖區訪問沖突的問題。終端虛擬設備讀函數被輸入/輸出系統層iosLib庫中的iosRead函數調用,iosRead函數被應用層ioLib庫中的read函數調用。開始read函數處于阻塞狀態等待輸入,設備會發中斷請求將數據寫入到輸入環形緩沖區,當輸入環形緩沖區不為空時,終端虛擬設備讀函數就可以將輸入環形緩沖區的數據送入用戶緩沖區完成輸入。VxWorks系統運行的過程中任何進程要從外圍設備讀取數據必須調用read函數。下面就從iosRead函數開始分析VxWorks系統如何從讀緩沖區取出數據并傳遞給指定的變量。
iosRead函數是將read函數傳遞來的文件描述符參數fd,轉換成FD_ENTRY結構體類型變量pFdEntry,根據pFdEntry結構體中的值查找drvTable表中外圍設備驅動庫中的讀函數(如終端虛擬設備讀函數)。調用終端虛擬設備讀函數,并將設備的ID號和要讀的字符個數傳遞給終端虛擬設備讀函數。
read函數是接收fioRdString函數傳遞來的文件描述符fd(指向標準輸入設備)和讀取字符個數,調用輸入/輸出系統庫函數iosRead。
fioRdString函數的功能是根據給定的文件描述符fd(指向標準輸入設備),調用read函數將字符讀到字符串數組string[]中,并返回讀取的字符個數。
3.2 輸出系統
VxWorks的輸入/輸出系統的輸出函數主要是通過調用write函數,write函數調用iosWrite函數,iosWrite調用終端虛擬設備寫函數,并引發中斷來實現輸出。這里主要介紹打印函數printf。
printf函數是C語言的庫函數,VxWorks包含它可以打印信息到顯示終端以方便調試或實施交互。它是一個變參數的函數,它根據用戶寫的格式轉換字符串,輸出相應格式的字符串到顯示終端,也可以直接將用戶寫字符串輸出到顯示終端。
printf的格式為printf(“格式轉換字符串”[,變量]),格式轉換字符串由普通字符和格式轉換符%,以及字符串結束符組成。變量的類型和格式轉換符后所跟的變量類型說明符一致,有幾個變量類型說明符,就跟幾個變量。由于printf是函數,格式轉換字符串和后面的輸出列表實際上都是函數的參數,可以表示為printf(參數1,參數2,參數3,…,參數n)。printf函數的功能是將參數2,…,參數n按參數1給定的格式輸出。
printf函數的參數是連續存放在數據區的,首先放入格式轉換字符串,接著放第一個變量的起始地址,然后放第二個變量的起始地址,依次類推(如果包含通配符*,在相應的位置放代替通配符的整數)。
printf執行時,首先使一個指針指向存放第一個變量的地址,并將格式轉換字符串拷貝內存中,然后調用fioformatV函數。
fioformatV函數是printf的主體函數,由它完成格式轉換的任務,轉換完成后調用printfbuf函數寫入緩沖區。它先將fmt的首地址賦給cp(cp是一個字符串指針),然后從fmt的開頭逐個掃描字符,沒有遇到格式轉換符和字符結束符就一直向后掃描,一旦遇到了格式轉換符%和字符結束符,就將從cp開始到結束符或格式轉換符的所有字符打印到顯示終端;如果是結束符則程序執行完畢,如果是格式轉換符%,則根據其后所跟的格式說明符進行相應的格式轉換,得到適當的輸出串調用printbuf()輸出到顯示終端。
簡而言之,fioformatV函數就是一個無限循環,無限循環每次循環完成一種格式轉換和對應格式的輸出,或普通字符輸出,直到格式轉換字符串掃描完畢;它有可能會多次調用printbuf函數。
printbuf函數有三個參數,調用write函數將字符指針Buf所指向的Nbytes個字符寫入緩沖區。
write函數調用輸入/輸出系統寫函數iosWrite,iosWrite會調用終端虛擬設備寫函數,將用戶緩沖區的數據即希望printf輸出的字符串拷貝到輸出環形緩沖區,此時終端虛擬設備寫函數會發送一個寫請求,請求將數據寫入串口設備,通過串口送到顯示終端,它將引發中斷來完成寫過程。
4 中斷處理過程
中斷處理函數執行的流程是將intEnt函數、sysIntHandler函數和intExit函數連接起來執行的過程。
intEnt函數主要功能是保護現場并設置VxWorks系統運行狀態。
sysIntHandler函數是一個中斷分離程序,該函數可以根據不同的中斷源信號判斷中斷類型,執行相對應的ISR。
intExit函數的功能是恢復現場并且設置VxWorks系統運行狀態,其流程與intEnt相反。
VxWorks讀寫中斷由串口控制器完成,每次中斷處理可以完成10 個以下(包括10個)字符的接收或發送,中斷信號由串口控制器發送,進入中斷后先讀取串口控制器的ISR寄存器的值,然后和IMRcopy進行與操作,根據與的結果順序判斷是A信道讀,A信道寫,還是B信道讀,B信道寫。IMR寄存器是由操作系統寫的,在執行讀操作之前會調用ioctl函數清空IMR在內存中的副本IMRcopy,每次執行寫操作前調用串口控制器啟動函數寫IMR在內存中的副本IMRcopy。串口控制器發中斷的機制如下:
執行完一次寫中斷后寫IMRcopy清寫中斷,并回寫IMR。發送完或接收完一個字符后,中斷服務程序會再一次查詢ISR和IMR的與判斷是否還有中斷,如果還有中斷信號,順序判斷是A信道讀,A信道寫,還是B信道讀,B信道寫處理下一個字符。如果已經處理了10個字符,則退出中斷服務程序等待下一次中斷到來,處理余下的字符。如果一次中斷處理的字符少于10個(說明本次處理完后緩沖區就為空了)則中斷結束。讀寫中斷退出處理過程略有不同,對于寫中斷,處理完最后一個字符后,會再讀一次寫緩沖區,這次沒讀到數據,中斷程序會認為緩沖區已空并修改IMR寄存器屏蔽寫中斷,然后退出中斷服務程序;而對于讀中斷,處理完最后一個字符后,讀緩沖區為空,串口控制器會立即修改ISR的值屏蔽讀中斷,然后退出中斷服務程序。
5 異常處理過程
在任務運行過程中,會出現一些異常的情況,導致任務不能正常運行或者對操作系統造成影響。在VxWorks中,當任務的指令執行中出現了非法指令、地址尋址錯誤、總線錯、除數為0等情況時,就會出現CPU異常。
為了處理這些異常,VxWorks在usrInit函數中調用excVecInit函數初始化了異常向量表,共初始化了17個異常向量,每個異常都有一個默認的處理程序。除了900(定時器到時異常)和500(外部中斷)兩個是異步異常,異常的處理程序是excIntHandle函數外,其余的15個異常的默認處理程序都是excExcHandle函數。
用戶可以根據體系結構和需要連接自己的異常處理程序代替默認的異常處理程序。VXWorks在usrExcInit函數中調用excConnect函數連接了自己的異常處理程序usrMachExcHandler函數、usrDsiExcHandler函數、usrIsiExcHandler函數、usrAlignmentExcHandler函數、usrProgramExcHandler函數;在sysHwInit函數里調用excIntConnect函數連接usrDecHandler函數到900異常,在sysHwInit函數里調用sysIntInit函數,sysIntInit函數在調用excIntConnect函數連接sysIntHandler函數到500外部中斷。
VxWorks的異常處理機制是有優先級的,其中System Reset異常優先級最高,Machine Check次之,這兩個異常也是非屏蔽異常,500和900異常優先級最低,也是可屏蔽的。
任何異常發生后,CPU要從用戶態切換到內核態,異常處理程序一般的處理過程如下:
首先,保存機器狀態,包括機器狀態字MSR和當前指令地址,即MSR→SRR1;PC→SRR0。然后,修改機器狀態寄存器,包括屏蔽外部中斷、標記當前狀態。最后,跳轉到對應的異常處理向量表入口,開始執行異常處理程序。
6 結束語
VxWorks是一種功能強大的嵌入式實時操作系統,為編程人員提供了高效的實時多任務調度、中斷管理、實時的系統資源以及實時的任務間通信。本文通過對VxWorks操作系統啟動流程、輸入輸出系統的分析以及中斷處理和異常處理過程的研究,設計了相應的外圍器件,成功實現了VxWorks操作系統的移植。
本文中所涉及到的圖表、注解、公式等內容請以PDF格式閱讀原文。