日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

windowsCE异常和中断服务程序初探(-)

發(fā)布時間:2023/12/10 windows 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 windowsCE异常和中断服务程序初探(-) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1。中斷/異常相量的裝入和執(zhí)行方式。???????

????? 中斷和異常都是異步發(fā)生的事件,當該事件發(fā)生,系統(tǒng)將停止目前正在執(zhí)行的代碼轉(zhuǎn)而執(zhí)行事件響應的服務程序。而事件服務程序的入口點就是中斷/異常向量所在的位置。arm的中斷向量可以是0x0開始的低地址向量,也可以是在FFFF0000位置的高向量地址。winCE下使用高地址作為trap區(qū),所以在CE下arm使用高地址向量。下面我們來了解一下中斷/異常向量的安裝和執(zhí)行過程。?
?在kernelStart的過程中通過程序?qū)⑷缦麓a復制到ffff0000的位置.?
VectorInstructions?
??????? ldr???? pc, [pc, #0x3E0-8]????????????? ; reset?
??????? ldr???? pc, [pc, #0x3E0-8]????????????? ; undefined instruction?
??????? ldr???? pc, [pc, #0x3E0-8]????????????? ; SVC?
??????? ldr???? pc, [pc, #0x3E0-8]????????????? ; Prefetch abort?
??????? ldr???? pc, [pc, #0x3E0-8]????????????? ; data abort?
??????? ldr???? pc, [pc, #0x3E0-8]????????????? ; unused vector location?
??????? ldr???? pc, [pc, #0x3E0-8]????????????? ; IRQ?
??????? ldr???? pc, [pc, #0x3E0-8]????????????? ; FIQ

??而在ffff03e0的位置放上如下的數(shù)據(jù),每一項(32bit)對應一個異常的跳轉(zhuǎn)地址也就是winCE的異常/中斷向量跳轉(zhuǎn)表。該表項的內(nèi)容就是發(fā)生異常后將要執(zhí)行的服務程序的入口地址。具體如下。?
VectorTable?
??????? DCD???? -1????????????????????????????? ; reset?
??????? DCD???? UndefException????????????????? ; undefined instruction?
??????? DCD???? SWIHandler????????????????????? ; SVC?
??????? DCD???? PrefetchAbort?????????????????? ; Prefetch abort

??????? IF :DEF:ARMV4T :LOR: :DEF:ARMV4I?
??????? DCD???? OEMDataAbortHandler???????????? ; data abort?
??????? ELSE?
??????? DCD???? DataAbortHandler??????????????? ; data abort?
??????? ENDIF

??????? DCD???? -1????????????????????????????? ; unused vector?
??????? DCD???? IRQHandler????????????????????? ; IRQ?
??????? DCD???? FIQHandler????????????????????? ; FIQ?
????? 在上面的這些代碼/數(shù)據(jù)在內(nèi)存空間上按照上述要求放置好以后,每次觸發(fā)一個異常就自動運行到相應跳轉(zhuǎn)表項所對應的地址執(zhí)行。?
??
2.異常/中斷服務程序?
??在arm下,由于有7種異常狀態(tài)包括reset、Undef exception、software interrupt(swi)、Prefech Abort、DataAbort、IRQ、FIQ七種異常/中斷。reset僅在復位時發(fā)生,其他6種都是在系統(tǒng)運行時發(fā)生。當任何一個異常發(fā)生并得到響應時,ARM 內(nèi)核自動完成以下動作:?
?拷貝 CPSR 到 SPSR_<mode>?
?設置適當?shù)?CPSR 位:?
?改變處理器狀態(tài)進入 ARM 狀態(tài)?
?改變處理器模式進入相應的異常模式?
?設置中斷禁止位禁止相應中斷?
?更新 LR_<mode>?
?設置 PC 到相應的異常向量?
?同時不管異常發(fā)生在ARM 還是Thumb 狀態(tài)下,處理器都將自動進入ARM 狀態(tài)。并且中斷使能會自動被關(guān)閉。在這個時候由于部分通用寄存器是不同模式公用的,所以還需要保存這些將會被破壞的寄存器,待到處理完成的時候恢復這些寄存器被中斷前的狀態(tài)。另外在進入異常模式后,lr的值不一定就是我們所需恢復執(zhí)行的位置,該位置受到異常類型和流水線誤差的影響。在SWI模式下,LR就是返回值。在IRQ和FIQ中LR=LR-4,DataAbort下LR=LR-8;具體原因我們就不討論了,有興趣可以參看<基于ARM 的嵌入式程序開發(fā)要點>一文。下面分別對這些服務程序進行分析。?
???
2-1.undef exception服務程序?
??????
undef exception在執(zhí)行到過非法的指令時產(chǎn)生,通常來模擬一些處理器不支持的功能,如浮點運算。簡單說一下undef exception的過程:當當前指令為一條處理器不支持的指令時,處理器會自動動將該指令送交各協(xié)處理器(如MMU、FPU)處理,如果這些協(xié)處理器都無法識別這條指令的時候,就產(chǎn)生該異常。下面開始看相應的代碼。?
??????? NESTED_ENTRY??? UndefException?
??????? sub???? lr, lr, #4????????????????????? ; (lr) = address of undefined instruction?
??????? stmdb?? sp, {r0-r3, lr}?
??????? mov???? r1, #ID_UNDEF_INSTR?
??????? b?????? CommonHandler?
??????? ENTRY_END UndefException

上面就是undef Exception的服務程序的入口處(已經(jīng)將不參與編譯和Thumb模式下的代碼去掉),通過lr-=4計算出觸發(fā)異常前的指令地址,同時保存r0-r3和lr入undef_exception stack用于最后恢復現(xiàn)場和取得異常指令本身,隨后進入分發(fā)程序CommonHandler.CommonHandler是一個公共的異常服務程序,它通過不同的傳入?yún)?shù)來進行處理,在這里mov r1,#ID_UNDEF_INSTR就是指定異常模式為undef Exception.?
??
2-2.swi服務程序?
??????
????? 按在ARM處理器的設計意圖,系統(tǒng)軟件的系統(tǒng)調(diào)用(SystemCalls)都是通過SWI指令完成。SWI相當于一個中斷指令,不同的是SWI不是由外部中斷源產(chǎn)生的,同時對應于SWI的異常向量位于0xc的位置或0xffff 000c的位置。也就是說當執(zhí)行一個swi指令后,當前程序流中斷,并轉(zhuǎn)入0xc或0xffff000c執(zhí)行,同時將CPSR_mode(當前程序狀態(tài)寄存器)復制入SPSR_svc,轉(zhuǎn)入SVC模式運行(使用特權(quán)模式的寄存器組)。也就是說系統(tǒng)通過執(zhí)行SWI引發(fā)系統(tǒng)swi異常后切換入特權(quán)模式,系統(tǒng)調(diào)用功能號由swi xx后的xx決定,在運行完指定功能的代碼后返回異常時的地址并恢復用戶模式。我們看看,Wince中這部分代碼是如何實現(xiàn)的。?
?????? ?DCD???? SWIHandler????????????????????? ; SVC<<--------------------------SWI入口點。?
?????? ??
???? LEAF_ENTRY SWIHandler?
? IF {FALSE}????????????????
??...?
? ENDIF?
??????? movs??? pc, lr?
??????? ENTRY_END SWIHandler?
??????? 上面IF {FALSE}到ENDIF之間的代碼在編譯的時候是得不到編譯的(事實上這部分代碼是用于開發(fā)中調(diào)試使用的,針對特殊的硬件平臺,一般與我們使用的硬件平臺無關(guān)。所以下面摘抄的代碼都不將不參與編譯的內(nèi)容寫入),因此SWI服務程序就是一句話。movs??? pc, lr也就是直接回到SWI的地方,同時將SPSR_svc恢復到CPSR_mode中。這個過程中并沒有進行在系統(tǒng)態(tài)執(zhí)行特定系統(tǒng)指令序的工作,而僅僅是簡單的返回,所以這不是系統(tǒng)調(diào)用,系統(tǒng)調(diào)用還需要根據(jù)調(diào)用號的不同運行指定的核心態(tài)代碼。也就是說Wince的系統(tǒng)調(diào)用不是通過SWI來完成的,而是通過其他的異常處理手段達成的。


2-3 中斷服務程序

IRQ(大概是最熟悉的異常方式了)在外部中斷源在需要向處理器請求服務時發(fā)生,比如:時鐘、外圍器件FIFO上/下溢出、按鍵等等。IRQHandler就是中斷的處理句柄,下面我們來具體看看。?
----------------------------------------------------------------------------------?????
????NESTED_ENTRY IRQHandler?
??????? sub???? lr, lr, #4????????????????????? ; fix return address?
??????? stmfd?? sp!, {r0-r3, r12, lr}? ?????;保存將要用到的寄存器和lr壓入stack_irq?
??????? PROLOG_END?
?????? ?和上面一樣,服務程序的入口處都是例行公事的計算返回位置以抵消流水線誤差。再將要用到的寄存器壓入STACK_IRQ,這樣,準備工作就做完了。?
??????? ; Test interlocked API status.????????
??????? ;INTERLOCKED_START EQU USER_KPAGE+0x380?
????;INTERLOCKED_END EQU USER_KPAGE+0x400?
??????? sub???? r0, lr, #INTERLOCKED_START?
??????? cmp???? r0, #INTERLOCKED_END-INTERLOCKED_START?
??????? bllo??? CheckInterlockedRestart?
??????? 上面這部分的內(nèi)容是關(guān)于互鎖的檢測,由于如信號量這些同步手段都必須作為原子操作進行,不允許打斷。所以如果中斷發(fā)生在互鎖API的執(zhí)行過程中,就需要專門的處理了。這些API都是放在INTERLOCKED_START和INTERLOCKED_END之間的,通過LR很容易就檢查出是否是INTERLOCKEDXXX的過程中。這里并不關(guān)心互鎖的實現(xiàn)就繞開這部分代碼繼續(xù)往下看,當作中斷沒有發(fā)生在interlock過程處理。?
??????? ;?
??????? ; CAREFUL! The stack frame is being altered here. It's ok since?
??????? ; the only routine relying on this was the Interlock Check. Note that?
??????? ; we re-push LR onto the stack so that the incoming argument area to?
??????? ; OEMInterruptHandler will be correct.?
??????? ;?
??????? mrs???? r1, spsr??????????????????????? ; (r1) = saved status reg?
??????? stmfd?? sp!, {r1}?????????????????????? ; save SPSR onto the IRQ stack????
??????? mov???? r0,lr?????????????????????????? ; parameter to OEMInterruptHandler?
???? msr???? cpsr_c, #SVC_MODE:OR:0x80?????? ; switch to supervisor mode w/IRQs disabled?
??????? stmfd?? sp!, {lr}?????????????????????? ; save LR onto the SVC stack????????
??????? stmfd?? sp!, {r0}?????????????????????? ; save IRQ LR (in R0) onto the SVC stack (param)?
??????? ;?
??????? ; Now we call the OEM's interrupt handler code. It is up to them to?
??????? ; enable interrupts if they so desire. We can't do it for them since?
??????? ; there's only on interrupt and they haven't yet defined their nesting.?
??????? ;

??????? CALL??? OEMInterruptHandler?
??????? ldmfd?? sp!, {r1}?????????????????????? ; dummy pop (parameter)?
??????? ldmfd?? sp!, {lr}?????????????????????? ; restore SVC LR from the SVC stack?
??????? msr???? cpsr_c, #IRQ_MODE:OR:0x80?????? ; switch back to IRQ mode w/IRQs disabled?
????; Restore the saved program status register from the stack.?
??????? ;?
??????? ldmfd?? sp!, {r1}?????????????????????? ; restore IRQ SPSR from the IRQ stack?
??????? msr???? spsr, r1??????????????????????? ; (r1) = saved status reg?
??????? ldr???? lr, =KData????????????????????? ; (lr) = ptr to KDataStruct?
????????
????????
??????? cmp???? r0, #SYSINTR_RESCHED??????;->時間片已到,進行調(diào)度?
??????? beq???? %F10????????????
??????? ;SYSINTR_DEVICES EQU 8?????????;是否設備中斷,中斷號是否有效?
????;SYSINTR_MAX_DEVICES EQU 32????
??????? sub???? r0, r0, #SYSINTR_DEVICES?
??????? cmp???? r0, #SYSINTR_MAX_DEVICES?
??????????????????????????? ;由此可以看出windowsCE的系統(tǒng)中斷號最大支持32種從9-40.?
??????????????????????????? ;其中第16號(24)被定義為SYSINTR_FIRMWARE?
??????? ; If not a device request (and not SYSINTR_RESCHED)?
????????
??????? ldrhsb? r0, [lr, #bResched]???????????? ; (r0) = reschedule flag?
??????? bhs???? %F20??????????????????????????? ; not a device request?
????????
??????? ;PendEvents? EQU 0x340???? ??????? ; offset 0x10*sizeof(DWORD) of aInfo?
????? ????????????????????? ;device 中斷?
??????? ldr???? r2, [lr, #PendEvents]?????????? ; (r2) = pending interrupt event mask?
??????? mov???? r1, #1?
??????? orr???? r2, r2, r1, LSL r0????????????? ; (r2) = new pending mask?
??????? str???? r2, [lr, #PendEvents]?????????? ; save it?
????;*PendEvents = *PendEvents|(1<<InterruptNO);?
??????? ;?
??????? ; mark reschedule needed?
??????????????????????????? ;情況1:r0=SYSINTR_RESCHED=1?
??????????????????????????? ;情況2: r0 =r0-SYSINTR_DEVICES>=SYSINTR_MAX_DEVICES????????
10????? ldrb??? r0, [lr, #bResched]???????????? ; (r0) = reschedule flag?
??????? orr???? r0, r0, #1????????????????????? ; set "reschedule needed bit"?
??????? strb??? r0, [lr, #bResched]???????????? ; update flag

20????? mrs???? r1, spsr??????????????????????? ; (r1) = saved status register value?
??????? and???? r1, r1, #0x1F?????????????????? ; (r1) = interrupted mode?
??????? cmp???? r1, #USER_MODE????????????????? ; previously in user mode??
??????? cmpne?? r1, #SYSTEM_MODE??????????????? ; if not, was it system mode??
??????? cmpeq?? r0, #1????????????????????????? ; user or system: is resched == 1?
??????? ;if(SytemMode(spsr)||UserMode(spsr))&&r0!=1) return;?
??????? ldmnefd sp!, {r0-r3, r12, pc}^????????? ; can't reschedule right now so return?
? *************************************************************************************?
??????? sub???? lr, lr, #4?
??????? ldmfd?? sp!, {r0-r3, r12}?
??????? stmdb?? lr, {r0-r3}?
??????? ldmfd?? sp!, {r0}?
??????? str???? r0, [lr]??????????????????????? ; save resume address?
??????? mov???? r1, #ID_RESCHEDULE????????????? ; (r1) = exception ID?
??????? b?????? CommonHandler?
??????? ENTRY_END IRQHandler?
??? 將spsr_irq壓入IRQ堆棧保存。為調(diào)用OEMInterruptHandler作準備。(通常中斷處理程序切換入系統(tǒng)態(tài)執(zhí)行的目的在于避免使用終端模式下的寄存器,以方便是實現(xiàn)終端套嵌,這兒切入系統(tǒng)態(tài)時終端使能是關(guān)閉的,對于模態(tài)切換的原因我很迷惑。)OEMInterrupt需要在特權(quán)模式下執(zhí)行,所以這里增加了切換入特權(quán)(SVC)模式的內(nèi)容。緊接著將要用與傳遞參數(shù)的寄存器保存。設定傳入?yún)?shù),r0就可以開始調(diào)用OEMInterruptHandler了,這里的調(diào)用規(guī)則遵循windowsCE的規(guī)范而不是ATPCS的規(guī)范。具體過程參考ARM Parameter?Passing@msdn。下面是函數(shù)原形。int OEMInterruptHandler(unsigned int ra);這里傳入的參數(shù)就是上面的r0,事實上r0代表的參數(shù)ra并沒有實質(zhì)的作用在這里僅僅是形式上的實現(xiàn)一下而已,不過在這兒可以看到這個傳入的ra實際上就是被中斷的地址,如果需要知道被中斷的位置可以通過ra來查詢,而msdn里面說這個參數(shù)是保留的。返回的參數(shù)也是保存在r0中。其中返回值是系統(tǒng)中斷類型。其中SYSINTR_RESCHED為系統(tǒng)時鐘中斷,每次時間片用完,該時鐘便產(chǎn)生中斷,并設置kData結(jié)構(gòu)的bResched位,進入調(diào)度流程。如果中斷類型是系統(tǒng)設備中斷,那就設置PendEvents,待再次調(diào)度的時候處理中斷。所以OEMInterruptHandler必須提前就要對中斷進行響應對該中斷源設置mask,防止在這過程中同一中斷不停發(fā)生,導致中斷飽和影響程序流的執(zhí)行,直道中斷處理真正完成后再次開放該中斷的mask。在這里還可以看到的是系統(tǒng)設備中斷號的范圍是從SYSINTR_DEVICES到SYSINTR_MAX_DEVICES,也就是從9-40一共32個設備中斷號,其中SYSINTR_FIRMWARE為8+16號,這個在編寫OAL的中斷服務程序時需要注意。如果當前的返回值既不是設備中斷號又不是調(diào)度中斷號,則讀出當前調(diào)度標示,根據(jù)該標示進行判斷是否調(diào)度/或返回.如果是進入調(diào)度流程則恢復初始的寄存器狀態(tài),再按CommonHandler的要求保存寄存器。進入CommonHandler,等待分發(fā)。?
????
2-3 FIQ服務程序?
??????? 照例看看程序?
??????? NESTED_ENTRY FIQHandler?
??????? sub???? lr, lr, #4????????????????????? ; fix return address?
??????? stmfd?? sp!, {r0-r3, r12, lr}?
??????? PROLOG_END?
??????? CALL??? OEMInterruptHandlerFIQ?
??????? ldmfd?? sp!, {r0-r3, r12, pc}^????????? ; restore regs & return for NOP?
??????? ENTRY_END FIQHandler?
??????? LTORG

FIQ是arm體系下特有的異常方式,其工作過程與IRQ類似都是由外部引腳觸發(fā)但設計用途不同,IRQ用于通常的外部中斷源的處理,是作為統(tǒng)一、通用的與外部器件交互的手段,而IRQ僅僅用于處理周期短同時又需要快速處理的場合其觸發(fā)的事件源通常也來此外部FIQ中斷。如:更換電池、數(shù)據(jù)傳輸這類工作。可想而知FIQ講究的是快速,精干。因此FIQ服務程序通常沒有分發(fā),而僅僅是針對單一的工作進行處理保證處理的實時性。因此FIQ的處理相對IRQ就簡單很多,直接調(diào)用?
OEMInterruptHandlerFIQ進行處理后返回就完成了整個 FIQ服務程序。

總結(jié)

以上是生活随笔為你收集整理的windowsCE异常和中断服务程序初探(-)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。