新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > WindowsCE異常和中斷服務程序初探

        WindowsCE異常和中斷服務程序初探

        作者: 時間:2011-02-25 來源:網絡 收藏

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

        Nasiry

        1。中斷/異常相量的裝入和執行方式。
        中斷和異常都是異步發生的事件,當該事件發生,系統將停止目前正在執行的代碼轉而執行事件響應的服務程序。而事件服務程序的入口點就是中斷/異常向量所在的位置。arm的中斷向量可以是0x0開始的低地址向量,也可以是在FFFF0000位置的高向量地址。winCE下使用高地址作為trap區,所以在CE下arm使用高地址向量。下面我們來了解一下中斷/異常向量的安裝和執行過程。
        在kernelStart的過程中通過程序將如下代碼復制到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的位置放上如下的數據,每一項(32bit)對應一個異常的跳轉地址也就是winCE的異常/中斷向量跳轉表。該表項的內容就是發生異常后將要執行的服務程序的入口地址。具體如下。
        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
        在上面的這些代碼/數據在內存空間上按照上述要求放置好以后,每次觸發一個異常就自動運行到相應跳轉表項所對應的地址執行。

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

        2-1.undef exception服務程序

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

        2-2.swi服務程序

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

        LEAF_ENTRY SWIHandler
        IF {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就是中斷的處理句柄,下面我們來具體看看。
        ----------------------------------------------------------------------------------
        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
        上面這部分的內容是關于互鎖的檢測,由于如信號量這些同步手段都必須作為原子操作進行,不允許打斷。所以如果中斷發生在互鎖API的執行過程中,就需要專門的處理了。這些API都是放在INTERLOCKED_START和INTERLOCKED_END之間的,通過LR很容易就檢查出是否是INTERLOCKEDXXX的過程中。這里并不關心互鎖的實現就繞開這部分代碼繼續往下看,當作中斷沒有發生在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 ;->時間片已到,進行調度
        beq

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


        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 荃湾区| 华阴市| 新蔡县| 法库县| 马公市| 三门县| 石泉县| 慈溪市| 红安县| 新兴县| 伽师县| 凉城县| 嘉兴市| 新宁县| 宝应县| 常州市| 自治县| 花莲市| 乌什县| 金门县| 潍坊市| 石林| 深泽县| 泾阳县| 芦溪县| 集贤县| 库车县| 青岛市| 读书| 万宁市| 佛学| 乳山市| 余姚市| 衡阳市| 吉木乃县| 吉林市| 江西省| 丰都县| 青海省| 江孜县| 临漳县|