<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > WindowsCE異常和中斷服務(wù)程序初探

          WindowsCE異常和中斷服務(wù)程序初探

          作者: 時(shí)間:2011-02-25 來源:網(wǎng)絡(luò) 收藏

          文摘出處:http://www.bitscn.com/hack/article/200607/42636.html

          Nasiry

          1。中斷/異常相量的裝入和執(zhí)行方式。
          中斷和異常都是異步發(fā)生的事件,當(dāng)該事件發(fā)生,系統(tǒng)將停止目前正在執(zhí)行的代碼轉(zhuǎn)而執(zhí)行事件響應(yīng)的服務(wù)程序。而事件服務(wù)程序的入口點(diǎn)就是中斷/異常向量所在的位置。arm的中斷向量可以是0x0開始的低地址向量,也可以是在FFFF0000位置的高向量地址。winCE下使用高地址作為trap區(qū),所以在CE下arm使用高地址向量。下面我們來了解一下中斷/異常向量的安裝和執(zhí)行過程。
          在kernelStart的過程中通過程序?qū)⑷缦麓a復(fù)制到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ù),每一項(xiàng)(32bit)對應(yīng)一個(gè)異常的跳轉(zhuǎn)地址也就是winCE的異常/中斷向量跳轉(zhuǎn)表。該表項(xiàng)的內(nèi)容就是發(fā)生異常后將要執(zhí)行的服務(wù)程序的入口地址。具體如下。
          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ā)一個(gè)異常就自動(dòng)運(yùn)行到相應(yīng)跳轉(zhuǎn)表項(xiàng)所對應(yīng)的地址執(zhí)行。

          2.異常/中斷服務(wù)程序
          在arm下,由于有7種異常狀態(tài)包括reset、Undef exception、software interrupt(swi)、Prefech Abort、DataAbort、IRQ、FIQ七種異常/中斷。reset僅在復(fù)位時(shí)發(fā)生,其他6種都是在系統(tǒng)運(yùn)行時(shí)發(fā)生。當(dāng)任何一個(gè)異常發(fā)生并得到響應(yīng)時(shí),ARM 內(nèi)核自動(dòng)完成以下動(dòng)作:
          拷貝 CPSR 到 SPSR_mode>
          設(shè)置適當(dāng)?shù)?CPSR 位:
          改變處理器狀態(tài)進(jìn)入 ARM 狀態(tài)
          改變處理器模式進(jìn)入相應(yīng)的異常模式
          設(shè)置中斷禁止位禁止相應(yīng)中斷
          更新 LR_mode>
          設(shè)置 PC 到相應(yīng)的異常向量
          同時(shí)不管異常發(fā)生在ARM 還是Thumb 狀態(tài)下,處理器都將自動(dòng)進(jìn)入ARM 狀態(tài)。并且中斷使能會(huì)自動(dòng)被關(guān)閉。在這個(gè)時(shí)候由于部分通用寄存器是不同模式公用的,所以還需要保存這些將會(huì)被破壞的寄存器,待到處理完成的時(shí)候恢復(fù)這些寄存器被中斷前的狀態(tài)。另外在進(jìn)入異常模式后,lr的值不一定就是我們所需恢復(fù)執(zhí)行的位置,該位置受到異常類型和流水線誤差的影響。在SWI模式下,LR就是返回值。在IRQ和FIQ中LR=LR-4,DataAbort下LR=LR-8;具體原因我們就不討論了,有興趣可以參看基于ARM 的程序開發(fā)要點(diǎn)>一文。下面分別對這些服務(wù)程序進(jìn)行分析。

          2-1.undef exception服務(wù)程序

          undef exception在執(zhí)行到過非法的指令時(shí)產(chǎn)生,通常來模擬一些處理器不支持的功能,如浮點(diǎn)運(yùn)算。簡單說一下undef exception的過程:當(dāng)當(dāng)前指令為一條處理器不支持的指令時(shí),處理器會(huì)自動(dòng)動(dòng)將該指令送交各協(xié)處理器(如MMU、FPU)處理,如果這些協(xié)處理器都無法識(shí)別這條指令的時(shí)候,就產(chǎn)生該異常。下面開始看相應(yīng)的代碼。
          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的服務(wù)程序的入口處(已經(jīng)將不參與編譯和Thumb模式下的代碼去掉),通過lr-=4計(jì)算出觸發(fā)異常前的指令地址,同時(shí)保存r0-r3和lr入undef_exception stack用于最后恢復(fù)現(xiàn)場和取得異常指令本身,隨后進(jìn)入分發(fā)程序CommonHandler.CommonHandler是一個(gè)公共的異常服務(wù)程序,它通過不同的傳入?yún)?shù)來進(jìn)行處理,在這里mov r1,#ID_UNDEF_INSTR就是指定異常模式為undef Exception.

          2-2.swi服務(wù)程序

          按在ARM處理器的設(shè)計(jì)意圖,系統(tǒng)軟件的系統(tǒng)調(diào)用(SystemCalls)都是通過SWI指令完成。SWI相當(dāng)于一個(gè)中斷指令,不同的是SWI不是由外部中斷源產(chǎn)生的,同時(shí)對應(yīng)于SWI的異常向量位于0xc的位置或0xffff 000c的位置。也就是說當(dāng)執(zhí)行一個(gè)swi指令后,當(dāng)前程序流中斷,并轉(zhuǎn)入0xc或0xffff000c執(zhí)行,同時(shí)將CPSR_mode(當(dāng)前程序狀態(tài)寄存器)復(fù)制入SPSR_svc,轉(zhuǎn)入SVC模式運(yùn)行(使用特權(quán)模式的寄存器組)。也就是說系統(tǒng)通過執(zhí)行SWI引發(fā)系統(tǒng)swi異常后切換入特權(quán)模式,系統(tǒng)調(diào)用功能號由swi xx后的xx決定,在運(yùn)行完指定功能的代碼后返回異常時(shí)的地址并恢復(fù)用戶模式。我們看看,Wince中這部分代碼是如何實(shí)現(xiàn)的。
          DCD SWIHandler ; SVC--------------------------SWI入口點(diǎn)。

          LEAF_ENTRY SWIHandler
          IF {FALSE}
          ...
          ENDIF
          movs pc, lr
          ENTRY_END SWIHandler
          上面IF {FALSE}到ENDIF之間的代碼在編譯的時(shí)候是得不到編譯的(事實(shí)上這部分代碼是用于開發(fā)中調(diào)試使用的,針對特殊的硬件平臺(tái),一般與我們使用的硬件平臺(tái)無關(guān)。所以下面摘抄的代碼都不將不參與編譯的內(nèi)容寫入),因此SWI服務(wù)程序就是一句話。movs pc, lr也就是直接回到SWI的地方,同時(shí)將SPSR_svc恢復(fù)到CPSR_mode中。這個(gè)過程中并沒有進(jìn)行在系統(tǒng)態(tài)執(zhí)行特定系統(tǒng)指令序的工作,而僅僅是簡單的返回,所以這不是系統(tǒng)調(diào)用,系統(tǒng)調(diào)用還需要根據(jù)調(diào)用號的不同運(yùn)行指定的核心態(tài)代碼。也就是說Wince的系統(tǒng)調(diào)用不是通過SWI來完成的,而是通過其他的異常處理手段達(dá)成的。


          2-3 中斷服務(wù)程序

          IRQ(大概是最熟悉的異常方式了)在外部中斷源在需要向處理器請求服務(wù)時(shí)發(fā)生,比如:時(shí)鐘、外圍器件FIFO上/下溢出、按鍵等等。IRQHandler就是中斷的處理句柄,下面我們來具體看看。
          ----------------------------------------------------------------------------------
          NESTED_ENTRY IRQHandler
          sub lr, lr, #4 ; fix return address
          stmfd sp!, {r0-r3, r12, lr} ;保存將要用到的寄存器和lr壓入stack_irq
          PROLOG_END
          和上面一樣,服務(wù)程序的入口處都是例行公事的計(jì)算返回位置以抵消流水線誤差。再將要用到的寄存器壓入STACK_IRQ,這樣,準(zhǔn)備工作就做完了。
          ; 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)于互鎖的檢測,由于如信號量這些同步手段都必須作為原子操作進(jìn)行,不允許打斷。所以如果中斷發(fā)生在互鎖API的執(zhí)行過程中,就需要專門的處理了。這些API都是放在INTERLOCKED_START和INTERLOCKED_END之間的,通過LR很容易就檢查出是否是INTERLOCKEDXXX的過程中。這里并不關(guān)心互鎖的實(shí)現(xiàn)就繞開這部分代碼繼續(xù)往下看,當(dāng)作中斷沒有發(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 ;->時(shí)間片已到,進(jìn)行調(diào)度
          beq

          linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)


          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();