中斷和異常是異步事件。當該事件發生時,系統將停止當前正在執行的代碼,並執行服務程序來響應該事件。事件服務程序的入口點是中斷/異常向量所在的位置。arm的中斷向量可以是從0x0開始的低位地址向量,也可以是FFFF0000處的高位地址向量。在winCE下,高位地址作為陷阱區,所以在CE下,arm使用高位地址向量。讓我們來看看中斷/異常向量的安裝和執行過程。
在kernelStart期間,通過程序將下面的代碼復制到ffff0000的位置。
向量指令
ldr pc,[pc,# 0x3e 0-8];重置
ldr pc,[pc,# 0x3e 0-8];未定義指令
ldr pc,[pc,# 0x3e 0-8];交換虛擬電路
ldr pc,[pc,# 0x3e 0-8];預取中止
ldr pc,[pc,# 0x3e 0-8];數據中止
ldr pc,[pc,# 0x3e 0-8];未使用的向量位置
ldr pc,[pc,# 0x3e 0-8];伊拉克
ldr pc,[pc,# 0x3e 0-8];FIQ
並把下面的數據放到ffff03e0的位置,每壹項(32bit)對應壹個異常跳轉地址,這是winCE的異常/中斷向量跳轉表。這個條目的內容是異常發生後要執行的服務程序的入口地址。具體如下。
可轉向的
DCD-1;重置
DCD無壹例外;未定義指令
DCD·斯威漢德勒;交換虛擬電路
DCD省;預取中止
IF :DEF:ARMV4T :LOR: :DEF:ARMV4I
DCD·奧姆達圖·阿伯森德勒;數據中止
其他
DCD·達博唐德勒;數據中止
ENDIF
DCD-1;未使用的向量
DCD·伊克漢德勒;伊拉克
DCD·菲克漢德勒;FIQ
上述代碼/數據按照上述要求放入內存空間後,每次觸發異常,都會自動運行到對應跳轉表項對應的地址執行。
2.異常/中斷服務程序
在arm下,有七種異常狀態,包括reset和Undef異常。七種異常/中斷:軟件中斷(swi)、預取中止、數據中止、IRQ和FIQ。復位只發生在復位時,其他六個發生在系統運行時。當任何異常發生並得到響應時,ARM內核自動完成以下動作:
將CPSR復制到spsr _
設置適當的CPSR位:
更改處理器狀態以進入待命狀態。
改變處理器模式,進入相應的異常模式。
設置中斷禁用位以禁用相應的中斷。
更新lr _
將PC設置為相應的異常向量。
同時,無論異常發生在ARM還是Thumb狀態,處理器都會自動進入ARM狀態。並且中斷使能被自動關閉。此時,由於有些通用寄存器是不同模式共享的,所以需要保存這些將要銷毀的寄存器,直到處理完成,才能恢復這些寄存器被中斷前的狀態。另外,進入異常模式後,lr的值不壹定是我們需要恢復執行的位置,這是受異常類型和流水線錯誤影響的。在SWI模式下,LR是返回值。IRQ和FIQ中Lr = lr-4,dataabort中LR = LR-8;具體原因我們就不討論了。有興趣的可以參考:壹分錢。以下是對這些服務的分析。
2-1.無異常服務程序
UndefeException是在執行非法指令時產生的,通常用來模擬壹些處理器不支持的功能,比如浮點運算。簡單描述壹下undef異常的過程:當當前指令是處理器不支持的指令時,處理器會自動將該指令發送到協處理器(如MMU、FPU)進行處理,如果這些協處理器無法識別該指令,就會產生異常。讓我們開始查看相應的代碼。
NESTED _ ENTRY UndefException
左後,左後,# 4;(lr) =未定義指令的地址
stmdb sp,{r0-r3,lr}
mov r1,#ID_UNDEF_INSTR
b CommonHandler
ENTRY _ END UndefException
以上是undef異常的服務程序入口(不參與編譯和Thumb模式的代碼已被移除),異常觸發前的指令地址由lr-=4計算,r0-r3和lr保存在undef_exception堆棧中,用於最終恢復站點和獲取異常指令本身。然後它進入分發服務器CommonHandler。CommonHandler是壹個公共的* * *異常服務程序,由不同的傳入參數處理,其中MOV R 1和# ID _ UNDEF _ INSTR只是將異常模式指定為undef Exception。
2-2.swi服務程序
根據ARM處理器的設計意圖,系統軟件的系統調用全部由SWI指令完成。SWI相當於壹個中斷指令,只不過SWI不是由外部中斷源產生的,SWI對應的異常向量位於0xc或0xffff 000c。也就是說,當執行壹條swi指令時,當前程序流被中斷,轉到0xc或0xffff000c執行。同時將CPSR _模式(當前程序狀態寄存器)復制到SPSR_svc中,並轉入svc模式運行(使用特權模式下的寄存器組)。也就是說,系統執行swi後切換到特權模式,swi xx後系統調用的函數號由xx決定。運行指定函數的代碼後,它返回異常的地址並恢復用戶模式。我們來看看Wince中的這部分代碼是如何實現的。
DCD·斯威漢德勒;SVC & lt& lt- swi入口點。
LEAF_ENTRY SWIHandler
如果{FALSE}
...
ENDIF
movs pc,lr
ENTRY_END SWIHandler
上面IF {FALSE}和ENDIF之間的代碼在編譯時是無法編譯的(其實這部分代碼是開發中調試用的,針對的是特殊的硬件平臺,壹般和我們使用的硬件平臺無關。所以下面摘錄的代碼不會寫入不參與編譯的內容),所以SWI服務程序就是壹句話。Movs pc,lr是直接返回SWI的地方,同時將SPSR_svc還原為CPSR_mode。在這個過程中,具體的系統指令序列並不是在系統狀態下執行的,只是簡單的返回,所以這不是系統調用,系統調用也需要根據調用號的不同運行指定的核心狀態代碼。也就是說,Wince的系統調用不是通過SWI完成的,而是通過其他異常處理方法完成的。
2-3中斷服務程序
IRQ(可能是最常見的異常)發生在外部中斷源需要向處理器請求服務時,例如時鐘、外設FIFO溢出、按鍵等等。IRQHandler是中斷處理程序。下面我們來詳細了解壹下。
-
嵌套條目IRQHandler
左後,左後,# 4;固定回郵地址
stmfd sp!,{r0-r3,r12,lr };保存要使用的寄存器,並將lr壓入stack_irq。
序言_結束
如上所述,服務程序的入口是計算返回位置以抵消流水線誤差的例行程序。然後把要使用的寄存器壓入STACK_IRQ,準備工作完成。
;測試聯鎖API狀態。
;聯鎖_啟動EQU用戶_KPAGE+0x380
;互鎖_最終EQU用戶_KPAGE+0x400
子r0,lr,#聯鎖_啟動
cmp r0,#互鎖_結束-互鎖_開始
bllo CheckInterlockedRestart
以上部分是關於聯鎖的檢測,因為信號量等同步手段必須作為原子操作來執行,不允許中斷。因此,如果中斷發生在聯鎖API的執行過程中,就需要特殊處理。這些API放在INTERLOCKED_START和INTERLOCKED_END之間,很容易通過LR檢查是否是INTERLOCKEDXXX。這裏不關心互鎖的實現,所以繞過這部分代碼,繼續往下看,好像互鎖過程中沒有發生中斷壹樣。
;
;小心點。堆棧框架在這裏被改變。沒關系,因為
;唯壹依賴於此的程序是聯鎖檢查。註意到
;我們將LR重新推到堆棧上,以便傳入的參數區域
;OEMInterruptHandler將是正確的。
;
mrs r1,spsr(r1) =保存的狀態寄存器
stmfd sp!,{ r 1 };將SPSR保存到IRQ堆棧中
mov r0,lr;OEMInterruptHandler的參數
msr cpsr_c,# SVC _ MODE:OR:0x 80;切換到管理員模式,禁用IRQ
stmfd sp!,{ lr };將LR保存到SVC堆棧上
stmfd sp!,{ r0 };將IRQ LR(在R0中)保存到SVC堆棧(參數)
;
;現在我們調用OEM的中斷處理程序代碼。應該由他們來決定
;如果需要,啟用中斷。我們不能為他們這樣做,因為
;只有壹個中斷,它們還沒有定義它們的嵌套。
;
調用OEMInterruptHandler
ldmfd sp!,{ r 1 };虛擬彈出(參數)
ldmfd sp!,{ lr };從SVC堆棧恢復SVC LR
msr cpsr_c,# IRQ _ MODE:OR:0x 80;切換回IRQ模式,禁用IRQ
;從堆棧中恢復保存的程序狀態寄存器。
;
ldmfd sp!,{ r 1 };從IRQ堆棧中恢復IRQ SPSR
msr spsr,r 1;(r1) =保存的狀態寄存器
ldr lr,= KData(lr) = ptr至KDataStruct
cmp r0,# SYSINTR _ RESCHED-& gt;時間片到了,排班執行。
beq %F10
;SYSINTR _ DEVICES EQU 8;設備是否中斷,中斷號是否有效。
;SYSINTR_MAX_DEVICES EQU 32
sub r0,r0,#SYSINTR_DEVICES
cmp r0,#SYSINTR_MAX_DEVICES
;可以看出,windowsCE的系統中斷數最多支持9到40的32種類型。
;其中No.16 (24)定義為SYSINTR_FIRMWARE。
;如果不是設備請求(並且不是SYSINTR_RESCHED)
ldrhsb r0,[lr,# bResched];(r0) =重新計劃標誌
bhs % F20不是設備請求
;未決事件EQU 0x 340;aInfo的偏移量0x10*sizeof(DWORD)
;設備中斷
ldr r2,[lr,# pend events];(r2) =掛起中斷事件屏蔽
mov r1,#1
奧爾r2,r2,r1,LSL r0;(r2) =新的待定掩碼
str r2,[lr,# pend events];保存
;* pend events = * pend events |(1 & lt;& lt中斷no);
;
;標記需要重新計劃
;案例1:r0 = sys intr _ rescued = 1。
;情況二:r0 = r0-sys intr _ devices >;=系統最大設備
10 ldrb r0,[lr,# bResched];(r0) =重新計劃標誌
orr r0,r0,# 1;設置“重新計劃需要的位”
strb r0,[lr,# bResched];更新標誌
20 mrs r1,spsr(r1) =保存的狀態寄存器值
以及r1,r1,# 0x 1F;(r1) =中斷模式
cmp r1,# USER _ MODE用戶模式前情提要?
cmpne r1,# SYSTEM _ MODE如果不是,是系統模式嗎?
cmpeq r0,# 1;用戶或系統:被撤銷== 1
;if(系統模式(spsr)| |用戶模式(spsr))& amp;& ampr0!=1)返回;
ldmnefd sp!,{r0-r3,r12,pc}^;現在不能重新安排,所以返回
*************************************************************************************
左後,左後,#4
ldmfd sp!,{r0-r3,r12}
stmdb lr,{r0-r3}
ldmfd sp!,{r0}
str r0,[lr];保存簡歷地址
mov r1,# ID _ RESCHEDULE(r1) =異常ID
b CommonHandler
ENTRY_END IRQHandler
將spsr_irq壓入irq堆棧進行保存。準備調用OEMInterruptHandler。(通常中斷處理程序切換到系統模式執行的目的是為了避免在終端模式下使用寄存器,從而實現終端嵌套。這裏,當切換到系統模式時,終端使能被關閉,我對模式切換的原因感到困惑。)OEMInterrupt需要在特權模式下執行,所以這裏增加了切換到特權(SVC)模式的內容。接下來,保存要使用的寄存器和傳遞的參數。設置傳入參數,r0可以開始調用OEMInterruptHandler。這裏的調用規則遵循的是windowsCE的規範,而不是ATPCS。具體流程參考ARM參數傳遞@msdn。下面是函數的原型。int OEMInterruptHandler(無符號int ra);這裏傳入的參數是上面的r0。其實r0代表的參數ra在這裏並沒有實質性的作用,只是形式上的實現。但是,這裏可以看出,這個進來的ra實際上是中斷的地址。如果需要知道中斷的位置,可以通過ra查詢,msdn上說這個參數是保留的。返回的參數也存儲在r0中。其中返回值是系統中斷類型。SYSINTR_RESCHED是系統時鐘中斷。每次時間片用完,時鐘都會產生壹個中斷,將kData結構的bResched位置位,進入調度進程。如果中斷類型是系統設備中斷,則設置PendEvents,以便在再次調度時處理中斷。所以OEMInterruptHandler必須提前對中斷做出響應,並為中斷源設置屏蔽,防止同壹中斷在進程中連續發生,導致中斷飽和影響程序流的執行,等中斷處理真正完成後再重新打開中斷的屏蔽。這裏還可以看到,系統設備中斷號的範圍是從SYSINTR_DEVICES到SYSINTR_MAX_DEVICES,即從9到40到***32個設備中斷號,其中SYSINTR_FIRMWARE是8+16,這是寫OAL中斷服務程序時要註意的。如果當前返回值既不是設備中斷號也不是調度中斷號,讀取當前調度標誌,根據標誌判斷是調度還是返回。如果進入調度進程,恢復初始寄存器狀態,然後按照CommonHandler的要求保存寄存器。進入CommonHandler,等待分發。
2-3 FIQ服務計劃
照常看節目
NESTED_ENTRY FIQHandler
左後,左後,# 4;固定回郵地址
stmfd sp!,{r0-r3,r12,lr}
序言_結束
調用OEMInterruptHandlerFIQ
ldmfd sp!,{r0-r3,r12,pc}^;恢復註冊表& amp返回NOP
ENTRY_END FIQHandler
LTORG
FIQ是arm系統中特有的異常模式,工作過程類似於IRQ,由外部引腳觸發,但設計目的不同。IRQ用於處理通常的外部中斷源,作為與外部設備交互的統壹通用手段,而IRQ只用於處理周期短且快的情況,觸發的事件源通常來自這個外部FIQ中斷。例如電池更換和數據傳輸。可想而知,FIQ講究的是速度快,能力強。因此,FIQ服務程序通常不是分布式的,而是只針對單個作業,以保證實時處理。所以FIQ的處理比IRQ簡單很多,直接調用。
OEMInterruptHandlerFIQ對其進行處理並返回以完成整個FIQ服務程序。