1. 程式人生 > >VxWorks中的中斷應用設計要點

VxWorks中的中斷應用設計要點

硬體中斷處理是實時系統設計中的關鍵性問題,設計人員有必要對其作深入研究,以更好地滿足開發工作需要。文中以VxWorks作業系統為軟體平臺,討論了在實時系統中進行中斷應用設計時要注意的一些問題。由於軟硬體的相關性,選用廣泛應用的X86架構的嵌入式汁算機為硬體平臺,對PenriumCPU和計算機主機板對硬體中斷的管理機制也做了詳細介紹 所得出的研究結論在具體的開發專案中均得以驗證,可供相關技術人員參考。

硬體中斷處理是實時系統設計中最重要、最關鍵的問題。文中綜合軟硬體,從工程應用的角度對此問題加以討論。文中所述內容針對的軟體平臺是VxWorks實時作業系統,硬體平臺選用廣泛使用的X86架構的嵌入式計算機,全文按照CPU、主機板、作業系統自下而上的順序展開。

1 Pentium CPU的中斷型別
有兩類事件可引起Pentium掛起當前的指令流,即中斷和異常。中斷是由外部事件引發的,在程式執行的任何時刻都可能出現;異常也稱異常中斷,是由內部事件引發的。中斷和異常各有兩類觸發源:
(1)中斷。
可遮蔽中斷:CPU的INTR引腳收到有效訊號,如果Pentium標誌暫存器IF位為1,則允許中斷,否則訊號在CPU內被遮蔽。
非遮蔽中斷:CPU的NMI引腳收到有效訊號而引發的中斷,這類中斷不能被阻止。
(2)異常。
執行異常:CPU試圖執行一條指令的過程中出現錯誤、故障等不正常條件而引發的異常中斷。
執行軟體中斷指令:Pentium指令系統中包括一些如INTO,INT n這類軟體中斷指令,執行時產生異常中斷。
詳細分類的話,Pentium可以識別256種中斷和異常。每種中斷給予一個編號,即0~255,稱為中斷向量號(interrupt vector number)。其中NMI、異常以及系統保留佔用中斷向量號0~31,而32~255為使用者中斷向量號,可供INTR和自定義軟體中斷(如彙編中的INT指令)使用。

2 Pentium CPU的中斷響應過程
中斷處理子程式的入口地址資訊存於記憶體中的一個表內,真實模式為中斷向量表IVT,保護模式為中斷描述符表IDT。中斷髮生時,CPU首先通過某種方式獲得中斷向量號,再以中斷向量號檢索此表,即可獲取中斷服務子程式入口地址,詳述如下:
(1)真實模式使用中斷向量表。
中斷向量表IVR的基地址由IDTR(中斷描述符暫存器)指定,大小為1kB。中斷響應時的查表過程與8086/8088一致,在此不再贅述。
(2)保護模式使用中斷描述符表。
中斷描述符表(IDT)的基地址也由IDTR指定,大小為2kB。中斷描述符表每一表項對應一箇中斷向量號,但表項稱為中斷門描述符或陷阱門描述符。這些門描述符為8位元組長,對應256箇中斷向量號。以中斷向量號乘以8作為訪問IDT的偏移,讀取相應的中斷門/陷阱門描述符表項。門描述符給出中斷服務子程式人口地址(段:偏移),其中32位偏移量裝入EIP,16位的段值被裝入CS暫存器。但此段值是選擇符,CPU會自動查GDT或LDT取得程式碼段描述符並送到相應的描述符暫存器中。

3 X86架構的計算機對外部中斷的管理
在嵌入式應用中,人們感興趣的主要是指由硬體訊號觸發的非遮蔽中斷與可遮蔽中斷。在單CPU的X86計算機中,採用兩片8259級聯來管理16個可遮蔽外部中斷,由於主8259的IRQ2用於級聯,所以實際可用的IRQ只有15個,其中又有一些被系統佔用,這種邏輯如今已被整合在主機板晶片組的南橋中,如圖1所示。由於傳統的PIC提供的中斷資源較少,現代PC開始採用APIC(高階可程式設計中斷控制器)管理外部中斷,它的一個顯著優點是能夠擴充系統可用的IRQ資源。文中問題的討論基於傳統的PIC結構。

圖1 外部中斷管理邏輯

4 在VxWorks中設計中斷應用
Vxworks執行在保護模式下。在Vxworks中,可以採用intConnect關聯中斷服務程式至某個中斷向量。然而intConnect並不是直接將使用者設計的ISR與中斷門描述符相關聯,而是對它加了一層封裝,然後將封裝程式碼的記憶體首地址與中斷門描述符相關聯,中斷響應過程如圖2所示。採用intConnect為ISA匯流排裝置關聯中斷服務程式IRQ—ISR至IRQ10的程式片斷如下:

程式碼
  1. #define IRQNum 10 /*1*/
  2. ……
  3. /* 2,3 */
  4. if(intConneet((VOIDFUNCPTR)INUM_TO_IVEC(IRQNum+0x20),IRQ_ISR,0)==OK)
  5. {
  6. if(sysIntEnablePIC(IRQNum)==OK) /*4*/
  7. {
  8. print{("Succeeded.\n");
  9. }
  10. }
  11. void IRQ_ISR()
  12. {
  13. int intLockKey;
  14. intLockKey=intLock();/*5*/
  15. ……(critical section)
  16. intUnlock(intLocKey);
  17. }


圖2 中斷響應過程
程式要點詳述:
① X86架構的計算機中,一些中斷資源已經固定地分配給某些外部裝置,如系統時鐘固定使用IRQ0,所以在選擇中斷號時首先應參考硬體手冊,避免與已用的中斷資源衝突。選定中斷號後,需要在BIOS中加以設定。避免BIOS在初始化時,把此中斷號作為可用資源分配給PCI裝置,造成中斷衝突。以上是在開發ISA裝置時要注意的,若開發PCI裝置,一般不做上述考慮,因為BIOS可為PCI裝置動態分配中斷資源,且多個PCI裝置可共享一箇中斷號,只需從PCI配置頭中讀取分配到的中斷號使用即可。
② VxWorks中使用intConnect掛接中斷服務程式,但對於PCI裝置,一般採用pciIntConnect掛接中斷,它與intConnect的主要不同在於intConnect使用的中斷向量是獨佔的,而pciIntConnect則可使多個外部中斷共享一箇中斷向量。它在內部使用一個連結串列管理多個ISR,發生中斷時,連結在一個連結串列上的各個ISR被依次呼叫,pciIntConnect要求每個ISR被呼叫時,應該首先查詢是否為自己的裝置產生的中斷,不是則應立即返回,以繼續呼叫其它ISR。
③ 在VxWorks中要注意區分以下4個與中斷相關的概念:IRQNumber,INumber,IVector,ILevel。

  • IRQNumber:外部中斷訊號由兩片8259級聯構成的PIC的那個輸入管腳引入,主8259的8條中斷輸入線對應IRQ0~IRQ7,從8259對應IRQ8~IRQ15。
  • INumber:Pentium CPU 的中斷向量號。INumber=IRQNumber+INT_NUM_IRQ0,INT_NUM_IRQ0,即IRQ0對應的中斷向量號,BSP的config.h中定義其為0x20(十進位制的32),即Pentium CPU 中斷向量號使用者定義區的起始編號。
  • IVector:中斷向量,是指某中斷的中斷描述符在中斷描述符表中的偏移量。INumber與IVector間的關係可簡單描述為:IVector=INumber*8。可以用ivi86.h中定義的兩個巨集(INUM_TO_IVEC,IVEC_TO_INUM)實施轉換。
  • ILevel:中斷優先順序。由於主從8259都被初始化為固定優先順序,優先順序逐漸遞減,且兩片8259存在級聯關係,所以優先順序關係為IRQ0 > IRQ1> IRQ2[IRQ8>IRQ9>…>IRQ15]>IRQ3>…>IRQ6>IRQ7。

表1列出了IRQ0~IRQ15對應的中斷向量號(INumber)與中斷向量(IVector)。

表1 中斷相關概念對照表
IRQNumber INumber IVector
0 32 0x100
1 33 0x108
2 34 0x110
15 47 0x178
④ 用intConnect掛中斷後,還必須用sysIntEnablePIC使能中斷,sysIntEnablePIC的函式原型在i8259Pic.C中定義,實際上就是針對某個IRQ,置8259中斷遮蔽暫存器中的相應位為允許。sysIntEnablePIC中的基本操作是利用埠讀寫函式sysInByte,sysOutByte讀寫8259的中斷遮蔽暫存器。sysInByte,sysOutByte的函式原型在sysALib.s中定義。
⑤ 關鍵程式碼段可用關中斷intLock和開中斷intUnlock加以保護。語句對intLock與intUnlock在不同的CPU體系架構中實現原理不同。在X86架構中,它們是通過操作EFLAGS中的IF位實現的。反彙編後可觀察它們的彙編形式程式碼。
intLock的反彙編程式碼:
_intLock: PUSHF /*將EFLAGS壓棧*/
_intLock: POP EAX
+0x002: AND EAX,0x200 /*只儲存感興趣的位IF*/
+0x007: CLI /*清IF位*/
+0x008: RET /*EAX作為返回值,即lock-out key */
intUnlock的反彙編程式碼:
_intUnlock: MOV EAX,[ESP+4] /*將lock-out key作為引數傳給EAX */
+0x004: AND EAX,0x200 /*判封鎖中斷前IF位的狀態如何*/
+0x009: JE intUnlock0 /*若封鎖中斷前也是關中斷狀態,則不做操作*/
+0x011: STI /*若封鎖中斷前是開中斷狀態,則置IF位*/
intUnlock0: RET /*返回*/
注意不要在中斷閉鎖期間呼叫Vxworks系統函式,否則有可能意外開啟中斷閉鎖,違反臨界程式碼的設計意圖。intLock可以在ISR或通常的任務中使用,當在任務中使用時,關中斷並不會禁止任務排程,所以,若一個任務關中斷後,又發生了任務排程,則新任務的上下文將被恢復,而EFLAGS是任務上下文的一部分,所以IF位可能會發生變化,中斷遮蔽可能會被解除。為了在關中斷的同時禁止任務排程,可採用如下形式:
if(taskLock()==OK)
{
intLockKey= intLock();
…(critical section)
intUnlock(intLockKey);
taskUnlock();
}
以上介紹了設計中斷應用時在軟體方面要注意的一些問題,再簡單說一下硬體中斷訊號的提供。VxWorks中8259被初始化為上升沿觸發,值得注意的是,外部中斷訊號 須保持為高電平直至第一個INTA訊號的下降沿到來,否則會造成假中斷,觸發IRQ7的中斷服務程式,常用的硬體中斷訊號形式是利用一個負脈衝的後沿(上升沿)。IRQ7是並口使用的中斷號,在除錯過程中,可以在VxWorks中裁減掉並口模組,在IRQ7上掛一個測試用的中斷服務程式,以觀察記錄假中斷。

5 結束語
文中結合工程實踐,以VXWorks與X86架構的嵌入式計算機為軟硬體平臺,較深入地闡述了在實時系統中設計中斷應用時需要考慮的一些問題。由於篇幅所限,一些在其他資料中被廣泛提及的設計要點(如中斷服務程式不能呼叫可能會引起呼叫阻塞的函式)在此不作介紹。