windowsCE异常和中断服务程序初探(=)
繼續(xù)上次的內(nèi)容,在上次的分析中我們已經(jīng)對SWI,FIQ,IRQ的流程有了一個大概的認識,下面繼續(xù)對DataAbort和PrefetchAbort以及公共分發(fā)程序CommonHandler進行一下認識,完整異常處理的流程。?
2-4 DataAbort服務程序?????
?? 由數(shù)據(jù)異常觸發(fā),通常有三種指令引發(fā)數(shù)據(jù)異常,這些指令都是訪存操作,而且都是由MMU的引入后才可能會發(fā)生的情況。1.LDR/STR指令.2.SWAP指令。3.LDM/STM指令。而MMU的失效類型又分為4種:存儲訪問失效、地址對齊失效、地址變換失效、域控制器失效、訪問控制權(quán)限失效.因此當異常發(fā)生后,需要通過訪問CP15來獲知異常的產(chǎn)生具體原因和情況。mfc是微軟的asmarm宏匯編器專用的宏指令,相當于mcr指令。數(shù)據(jù)異常和中斷模式一樣都有可能在互鎖時發(fā)生,所以同樣需要對執(zhí)行互鎖的情形進行處理。正常的情況下在保存完相關(guān)的寄存器后就會讀取CP15的c6,c5,c13三個寄存器。這三個寄存器分別是失效地址寄存器(FAR)、失效狀態(tài)寄存器(FSR)、進程號寄存器(這個翻譯得不好PCP15)然后根據(jù)具體的失效類型來進行處理。在ARM處理器中對于CP15有三種地址類型,VA,PA,MVA。VA(virtual address)也就是我們通常說的虛擬地址或邏輯地址也就是通過CP15按照PT轉(zhuǎn)換后的地址,而PA(physical Address)則是對應于AMBA上的地址,對應的是電氣介質(zhì)也就是物理地址。而MVA(Modified virtual address)則是對應于Cache和TLB中轉(zhuǎn)換地址。?
??????? NESTED_ENTRY??? DataAbortHandler?
??????? sub???? lr, lr, #8????????????????????? ; repair continuation address?
??????? stmfd?? sp!, {r0-r3, r12, lr}?
??????? PROLOG_END
??????? sub???? r0, lr, #INTERLOCKED_START?
??????? cmp???? r0, #INTERLOCKED_END-INTERLOCKED_START?
??????? bllo??? CheckInterlockedRestart?
??????? mfc15?? r0, c6????????????????????????? ; (r0) = FAR????????
??????? mfc15?? r1, c5????????????????????????? ; (r1) = FSR?
??????? mfc15?? r2, c13???????????????????????? ; (r2) = process base address?
????????
??????? ;? FAR=Fault address register?
????;? CP = 15: CRn = 6, CRm = 0, op_1 = 0, op_2 = 0?
??????? ;? FSR=Fault status register?
??????? ;? CP = 15: CRn = 5, CRm = 0, op_1 = 0, op_2 = 0?
??????? ;? PCP15: PID? Process ID register?
????;? CP = 15: CRn = 13, CRm = 0, op_1 = 0, op_2 = 0?
????????
??????? tst???? r0, #0xFE000000???????????????? ; slot 0 reference??
??????? orreq?? r0, r0, r2????????????????????? ; (r0) = process slot based address?
??????? and???? r1, r1, #0x0D?????????????????? ; type of data abort?
??????? cmp???? r1, #0x05?????????????????????? ; translation error??
??????? movne?? r0, #0?
??????? CALLEQ? LoadPageTable?????????????????? ; (r0) = !0 if entry loaded?
??????? tst???? r0, r0?
??????? ldmnefd sp!, {r0-r3, r12, pc}^????????? ; restore regs & continue?
??????? ;*********************************************************************?
??????? ldr???? lr, =KData-4?
??????? ldmfd?? sp!, {r0-r3, r12}?
??????? stmdb?? lr, {r0-r3}?
??????? ldmfd?? sp!, {r0}?
??????? str???? r0, [lr]??????????????????????? ; save resume address?
??????? mov???? r1, #ID_DATA_ABORT????????????? ; (r1) = exception ID?
??????? b?????? CommonHandler
??????? ENTRY_END DataAbortHandler?
在DataAbort發(fā)生后c6中的數(shù)據(jù)保存的就是導致異常的MVA地址,通過windowsCE memory layout可以了解到,當前進程的運行空間是在slot0,也就是0x0-0x1fffffff的位置,事實上這個slot上的數(shù)據(jù)僅僅是實際進程的一個副本所以如果數(shù)據(jù)異常發(fā)生在slot0就需要去找到進程所在的實際slot的存放地址,然后嘗試將內(nèi)核的頁表復制到硬件實際使用的頁表以達到恢復的目的。如果復制動作成功則返回,否則進入異常分發(fā)程序CommonHandler。?
2-5 PrefetchAbort服務程序?
?? 對于ARM處理器來說,由于其內(nèi)部使用了哈佛結(jié)構(gòu)---獨立的數(shù)據(jù)的指令總線因此,在數(shù)據(jù)/指令的讀取過程中產(chǎn)生的異常也就很自然地可以區(qū)分開來,本質(zhì)上而言,這些異常都是同屬于存儲訪問失敗產(chǎn)生的異常,因此這些異常都由MMU相關(guān),在ARM手冊中DataAbort和PrefetchAbort都稱為Memory abort。Prefetch也就是在預取指令的動作后產(chǎn)生的,當處理器運行到這個無效的指令時(這個無效與undefined exception中的不可識別不同,是指不存在或是無法得到)就觸發(fā)該異常。所以不是所有的指令無效都產(chǎn)生異常,例如:一個分支程序指向一個不可訪問的區(qū)域,而之前的分支指向另一個可訪問區(qū)域時。后一個區(qū)域盡管預取無效但是由于該分支并不執(zhí)行所以并不產(chǎn)生異常。所以prefetch的準確定義應該是prefetch and executes Abort:).在ARMV5指令集中BKPT也可以產(chǎn)生預取無效但由于這兒的ARM通常都是ARM9的,也就是使用ARMV4指令所以不討論BKPT的情形。由于數(shù)據(jù)異常和指令異常同屬存儲異常而且兩個異常不可能會相互中斷所以在ARM的設計上這兩個異常使用同一組寄存器abort組。?
??ALTERNATE_ENTRY PrefetchAbort
??????? sub???? lr, lr, #0xF0000004??;考察產(chǎn)生異常的地址是否在0xf0000000-0xf0010400 ??
??????? cmp???? lr, #0x00010400????;之間,如果是進入系統(tǒng)調(diào)用處理?
??????? bhs???? ProcessPrefAbort????? ;->>正常的預取異常 執(zhí)行ProcessPrefAbort?
????...???????
ProcessPrefAbort?
??????? add???? lr, lr, #0xF0000000???????????? ; repair continuation address?
??????? stmfd?? sp!, {r0-r3, r12, lr}?
??
??????? mov???? r0, lr????????????????????????? ; (r0) = faulting address?
??????? mfc15?? r2, c13???????????????????????? ; (r2) = process base address?
??????? tst???? r0, #0xFE000000???????????????? ; slot 0 reference??
??????? orreq?? r0, r0, r2????????????????????? ; (r0) = process slot based address?
??????? CALL??? LoadPageTable?????????????????? ; (r0) = !0 if entry loaded?
??????? tst???? r0, r0?
??????? ldmnefd sp!, {r0-r3, r12, pc}^????????? ; restore regs & continue?
??????? ldmfd?? sp!, {r0-r3, r12}?
??????? ldr???? lr, =KData-4?
??????? stmdb?? lr, {r0-r3}?
??????? ldmfd?? sp!, {r0}?
??????? str???? r0, [lr]??????????????????????? ; save resume address?
??????? mov???? r1, #ID_PREFETCH_ABORT????????? ; (r1) = exception ID?
??????? b?????? CommonHandler
下面來結(jié)合windowsCE的情形。PrefetchAbort就是該服務程序的入口,在程序的一開始將lr,也就是產(chǎn)生異常的地址+4(流水線導致)的地址減掉0xf000 0004并比較是否在0-0x10400之間,這是為什么呢?原來windowsCE除了使用PrefetchAbort服務程序作為正常的異常處理以外還使用這個異常作為系統(tǒng)調(diào)用的手段。通過0xf0000000-0xf0010400這段地址的預取異常來進行系統(tǒng)調(diào)用。我們下面看處理預取失敗的情況,繞開系統(tǒng)調(diào)用的先不管。也就是ProcessPrefAbort的分支。 這個分支的內(nèi)容就與上面DataAbort的內(nèi)容一樣了,我就不再重復了。??
2-6異常分發(fā)?CommonHandler
到此為止我們已經(jīng)了解了windowsCE對各個異常/中斷模式下的處理情況已經(jīng)基本做了一個了解,但是仍然有一些情況是送到CommonHandler來處理的,下面就對這個分發(fā)程序進行分析,完整windowsCE對整個異常流程的處理。?
??
??????? ALTERNATE_ENTRY CommonHandler?
??????? mrs???? r2, spsr?
??????? msr???? cpsr_c, #SVC_MODE:OR:0x80?????? ; switch to Supervisor mode w/IRQs disabled?
??????? ldr???? r3, =KData????????????????????? ; (r3) = ptr to KData page?
在CommonHandler開始系統(tǒng)就轉(zhuǎn)入Supervisor態(tài)來執(zhí)行。?????
; Save the processor state into a thread structure. If the previous state was?
; User or System and the kernel isn't busy, then save the state into the current?
; thread. Otherwise, create a temporary thread structure on the kernel stack.?
;?
;?????? (r1) = exception ID?
;?????? (r2) = SPSR?
;?????? (r3) = ptr to KData page?
;?????? Interrupted r0-r3, and Pc saved at (r3-0x14)?
;?????? In Supervisor Mode.?
??????? ALTERNATE_ENTRY SaveAndReschedule
?????? and???? r0, r2, #0x1f?????????????????? ; (r0) = previous mode?
??????? cmp???? r0, #USER_MODE????????????????? ; 'Z' set if from user mode?
??????? cmpne?? r0, #SYSTEM_MODE??????????????? ; 'Z' set if from System mode?
??????? bne???? %F50??????????????????????????? ; reentering kernel, save state on stack?
????????????????????????; 現(xiàn)場保護分支?
????????????????????????;發(fā)生異常前模態(tài)是否是用戶態(tài)和系統(tǒng)態(tài)。FIQ/IRQ/SVC/Abort/Undef?
??????? ldr???? r0, [r3,#pCurThd]?????????????? ; (r0) = ptr to current thread?
??????? ????????????????????;?r0 =kData+pCurThd????? ?????????????????????
??????? add???? r0, r0, #TcxR4????????????????? ; (r0) = ptr to r4 save?
??????? ????????????????????;?r0 =kData+pCurThd+TcxR4?
??????? ????????????????????;THREAD_CONTEXT_OFFSET后的0x44bytes用于備份寄存器的內(nèi)容?
??????? stmia?? r0, {r4-r14}^?????????????????? ; save User bank registers?????????????????
??????? ****************************************************?
??????? ; Save registers for fault from a non-preemptible state.?
50????? sub???? sp, sp, #TcxSizeof????????????? ; allocate space for temp. thread structure?
??????? cmp???? r0, #SVC_MODE?
??????? bne???? %F55??????????????????????????? ; must mode switch to save state?
??????? add???? r0, sp, #TcxR4????????????????? ; (r0) = ptr to r4 save area?
??????? stmia?? r0, {r4-r14}??????????????????? ; save SVC state registers?
??????? add???? r4, sp, #TcxSizeof????????????? ; (r4) = old SVC stack pointer?
??????? str???? r4, [r0, #TcxSp-TcxR4]????????? ; update stack pointer value?
??????? b?????? %B10
55?
??????? msr???? cpsr, r2??????????????????????? ; switch to mode exception came from
??????? add???? r0, sp, #TcxR4????????????????? ; (r0) = ptr to r4 save area?
??????? stmia?? r0, {r4-r14}??????????????????? ; save mode's register state?
??????? msr???? cpsr_c, #SVC_MODE:OR:0x80?????? ; back to supervisor mode?
??????? b?????? %B10??????????????????????????? ; go save remaining state
在進行統(tǒng)一的處理之前需要保存前態(tài)寄存器組的狀態(tài)以便后面恢復,在用戶態(tài)和系統(tǒng)態(tài)的情況下直接保存用戶態(tài)的寄存器。同時上面可以看到到達50的條件是前一狀態(tài)為FIQ/IRQ/SVC/Abort/Undef,也就是說為異常套嵌的情況,系統(tǒng)套嵌的情形前面已經(jīng)處理過了。這里首先處理的是SVC下被套嵌的情形,上面可以看到SVC模式都是用于異常/中斷后的具體事件處理(eg: HandleException),所以這個流程并不是獨立存在的,因此當前寄存器就是前態(tài)寄存器,所以到這里需要重新計算stack指針的位置。而另外的FIQ/IRQ/Abort/Undef模式下的寄存器的保存則需要切換當前狀態(tài)來進行,所以在進入真正的處理程序之前需要不同的分支來保存前態(tài)寄存器狀態(tài)。可為什么前后都看不到System模式下的寄存器保存呢?這是因為系統(tǒng)態(tài)和用戶態(tài)使用同一組寄存器所以保存用戶態(tài)寄存器組就達到了現(xiàn)場保護了。這種設計完全是因為ARM分組寄存器的架構(gòu)決定的,所以需要不同的處理。通過上面的處理所有的情況都已經(jīng)統(tǒng)一的完成了現(xiàn)場保護的動作,下面就需要進一步處理這些異常了。?
10????? ldmdb?? r3, {r3-r7}???????????????????? ; load saved r0-r3 & Pc?
????????????????????????;KData之前的16byte用作傳遞參數(shù)用?
????????????????????????;所以每個異常句柄最后都由將r0-r3和PC送到這個位置。????????????????
??????? stmdb?? r0!, {r2-r6}??????????????????? ; save Psr, r0-r3?
??????? sub???? r0, r0, #THREAD_CONTEXT_OFFSET? ; (r0) = ptr to Thread struct?
??????? str???? r7, [r0,#TcxPc]???????????????? ; save Pc?
??????? mfc15?? r2, c6????????????????????????? ; (r2) = fault address?
??????? mfc15?? r3, c5????????????????????????? ; (r3) = fault status?
????;r0=&Kdata?
????;r1=exception ID?
????;r2=FAR?
????;r3=FSR????
; Process an exception or reschedule request.
FirstSchedule?
20????? msr???? cpsr_c, #SVC_MODE?????????????? ; enable interrupts
??????? CALL??? HandleException?
??????? ldr???? r2, [r0, #TcxPsr]?????????????? ; (r2) = target status?
??????? and???? r1, r2, #0x1f?????????????????? ; (r1) = target mode?
??????? cmp???? r1, #USER_MODE?
??????? cmpne?? r1, #SYSTEM_MODE?
??????? bne???? %F30??????????????????????????? ; not going back to user or system mode?
??????? ;System mode and user mode branch?
??????? add???? r0, r0, #TcxR3?
??????? ldmia?? r0, {r3-r14}^?????????????????? ; reload user/system mode registers?
??????? ldr???? r1, =KData?
??????? msr???? cpsr_c, #SVC_MODE:OR:0x80?????? ; disable all interrupts?
??????? ldrb??? r1, [r1, #bResched]???????????? ; (r1) = nest level + reschedule flag?
??????? cmp???? r1, #1?
??????? mov???? r1, #ID_RESCHEDULE?
??????? beq???? %B20??????????????????????????? ; interrupted, reschedule again?
??????? msr???? spsr, r2?
??????? ldr???? lr, [r0, #TcxPc-TcxR3]?
??????? ldmdb?? r0, {r0-r2}?
??????? movs??? pc, lr????????????????????????? ; return to user or system mode
HandleException是實際進行異常處理的函數(shù),針對上面沒有處理完的異常進一步分析并進行處理。這個函數(shù)是沒有公開代碼的,所以沒有辦法進一步深入下去。由于處理的異常類型比較多所以這個異常處理函數(shù)的代碼量是相當大的,因此會耗費相對比較多的時鐘周期,在之前的代碼中我們都是在關(guān)閉中斷的情況下進行異常處理,如果在這里還不打開中斷的話整個異常處理過程會相當?shù)拈L,這樣會很大程度上影響系統(tǒng)的實時性,所以在這里調(diào)用HandleException之前是將中斷重新打開的,待到處理完成再將中斷關(guān)閉。對于這些異常,如果不能處理就只有兩種情況:1.結(jié)束該進程/線程。2.掛起系統(tǒng).第二種情況下掛起系統(tǒng)HandleException是不會返回的。因此,只有異常處理正常流程和結(jié)束線程的可能。對于返回的情況,這個時候如果返回觸發(fā)異常的地址繼續(xù)運行的話,仍然會導致異常,所以結(jié)束進程/線程都需要重新調(diào)度才能完成了。對于異常處理成功的情形,就不必調(diào)度了,直接就可以返回產(chǎn)生異常的地方繼續(xù)執(zhí)行。在這里還要考慮套嵌(這里僅僅是指系統(tǒng)模式和兼管模式的異常套嵌)的情形,也就是中斷/異常已經(jīng)進入調(diào)度狀態(tài)又再次產(chǎn)生中斷/異常,這個時候就強行取消上一次調(diào)度,進而重新調(diào)度.這用于調(diào)度過程中遇到異常恢復和剝奪的情況,如果不屬于這種情況的話就直接恢復寄存器狀態(tài)并且返回中斷點繼續(xù)執(zhí)行。
; Return to a non-preemptible privileged mode.?
;?
;?????? (r0) = ptr to THREAD structure?
;?????? (r2) = target mode
30??? msr???? cpsr, r2??????????????????????? ; switch to target mode?
??????? add???? r0, r0, #TcxR0?
??????? ldmia?? r0, {r0-r15}??????????????????? ; reload all registers & return?
通過HandleException處理以后,已經(jīng)完成了所有異常的處理,所以這里只是考慮反回的情況,由于這里不包含用戶模式下的處理,所以這里處理的都是特權(quán)模式,完全可以訪問kdata區(qū)域,這里就直接利用Kdata區(qū)域中的線程備份來完成恢復寄存器和返回。?
總結(jié)
以上是生活随笔為你收集整理的windowsCE异常和中断服务程序初探(=)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用卡密码函可以丢吗
- 下一篇: 操作系统真实的虚拟内存是什么样的