新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > linux-2.6.26內核中ARM中斷實現詳解

        linux-2.6.26內核中ARM中斷實現詳解

        作者: 時間:2012-09-01 來源:網絡 收藏

        三、中斷處理過程

        這一節將以S3C2410為例,描述-2.6.26中,從中斷開始,中斷是如何一步一步執行到我們注冊函數的。

        3.1 中斷向量表 archarmkernelentry-armv.S

        __vectors_STart:

        swi SYS_ERROR0

        b vector_und + stubs_offset

        ldr pc, .LCvswi + stubs_offset

        b vector_pa^ + stubs_offset

        b vector_da^ + stubs_offset

        b vector_addrexcptn + stubs_offset

        b vector_IRq + stubs_offset

        b vector_fiq + stubs_offset

        .globl __vectors_end

        __vectors_end:

        中斷發生后,跳轉到b vector_irq + stubs_offset的位置執行。注意現在的向量表的初始位置是0xffff0000。

        3.2 中斷跳轉的入口位置 archarmkernelentry-armv.S

        .globl __stubs_start

        __stubs_start:

        /*

        * Interrupt dispatcher

        */

        vector_stub irq, IRQ_MODE, 4 @IRQ_MODE在includeasmptrace.h中定義:0x12

        .lONg __irq_usr @ 0 (USR_26 / USR_32)

        .long __irq_invalid @ 1 (FIQ_26 / FIQ_32)

        .long __irq_invalid @ 2 (IRQ_26 / IRQ_32)

        .long __irq_svc @ 3 (SVC_26 / SVC_32)

        .long __irq_invalid @ 4

        .long __irq_invalid @ 5

        .long __irq_invalid @ 6

        .long __irq_invalid @ 7

        .long __irq_invalid @ 8

        .long __irq_invalid @ 9

        .long __irq_invalid @ a

        .long __irq_invalid @ b

        .long __irq_invalid @ c

        .long __irq_invalid @ d

        .long __irq_invalid @ e

        .long __irq_invalid @ f

        上面代碼中vector_stub宏的定義為:

        .macro vector_stub, name, mode, correcTIon=0

        .align 5

        vector_nAME:

        .if correction

        sub lr, lr, #correction

        .endif

        @

        @ Save r0, lr_ (parent PC) and spsr_

        @ (parent CPSR)

        @

        stmia sp, {r0, lr} @ save r0, lr

        mrs lr, spsr

        str lr, [sp, #8] @ save spsr

        @

        @ Prepare for SVC32 mode. IRQs remain disabled.

        @

        mrs r0, cpsr

        eor r0, r0, #(mode ^ SVC_MODE)

        msr spsr_cxsf, r0 @為后面進入svc模式做準備

        @

        @ the branch table must immediately follow this code

        @

        and lr, lr, #0x0f @進入中斷前的mode的后4位

        @#define USR_MODE 0x00000010

        @#define FIQ_MODE 0x00000011

        @#define IRQ_MODE 0x00000012

        @#define SVC_MODE 0x00000013

        @#define ABT_MODE 0x00000017

        @#define UND_MODE 0x0000001b

        @#define SYSTEM_MODE 0x0000001f

        mov r0, sp

        ldr lr, [pc, lr, lsl #2] @如果進入中斷前是usr,則取出PC+4*0的內容,即__irq_usr @如果進入中斷前是svc,則取出PC+4*3的內容,即__irq_svc

        movs pc, lr @ 當指令的目標寄存器是PC,且指令以S結束,則它會把@ spsr的值恢復給cpsr branch to handler in SVC mode

        .endm

        .globl __stubs_start

        __stubs_start:

        /*

        * Interrupt dispatcher

        */

        vector_stub irq, IRQ_MODE, 4

        .long __irq_usr @ 0 (USR_26 / USR_32)

        .long __irq_invalid @ 1 (FIQ_26 / FIQ_32)

        .long __irq_invalid @ 2 (IRQ_26 / IRQ_32)

        .long __irq_svc @ 3 (SVC_26 / SVC_32)

        用“irq, IRQ_MODE, 4”代替宏vector_stub中的“name, mode, correction”,找到了我們中斷處理的入口位置為vector_irq(宏里面的vector_name)。

        從上面代碼中的注釋可以看出,根據進入中斷前的工作模式不同,程序下一步將跳轉到_irq_usr 、或__irq_svc等位置。我們先選擇__irq_usr作為下一步跟蹤的目標。

        3.3 __irq_usr的實現 archarmkernelentry-armv.S

        __irq_usr:

        usr_entry @后面有解釋

        kuser_cmpxchg_check

        #ifdef CONFIG_TRACE_IRQFLAGS

        bl trace_hardirqs_off

        #endif

        get_thread_info tsk @獲取當前進程的進程描述符中的成員變量thread_info的地址,并將該地址保存到寄存器tsk等于r9(在entry-header.S中定義)

        #ifdef CONFIG_PREEMPT//如果定義了搶占,增加搶占數值

        ldr r8, [tsk, #TI_PREEMPT] @ get preempt count

        add r7, r8, #1 @ increment it

        str r7, [tsk, #TI_PREEMPT]

        #endif

        irq_handler @中斷處理,我們最關心的地方,3.4節有實現過程。

        #ifdef CONFIG_PREEMPT

        ldr r0, [tsk, #TI_PREEMPT]

        str r8, [tsk, #TI_PREEMPT]

        teq r0, r7

        strne r0, [r0, -r0]

        #endif

        #ifdef CONFIG_TRACE_IRQFLAGS

        bl trace_hardirqs_on

        #endif

        mov why, #0

        b ret_to_user @中斷處理完成,返回中斷產生的位置,3.7節有實現過程

        上面代碼中的usr_entry是一個宏,主要實現了將usr模式下的寄存器、中斷返回地址保存到堆棧中。

        .macro usr_entry

        sub sp, sp, #S_frame_SIZE @ S_FRAME_SIZE的值在archarmkernelasm-offsets.c

        @ 中定義 DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));實際上等于72

        stmib sp, {r1 - r12}

        ldmia r0, {r1 - r3}

        add r0, sp, #S_PC @ here for interlock avoidance

        mov r4, #-1 @ "" "" "" ""

        str r1, [sp] @ save the "real" r0 copied

        @ from the exception stack

        @

        @ We are now ready to fill in the remaining blanks on the stack:

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


        關鍵詞: linux 內核 ARM中斷

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 建湖县| 墨竹工卡县| 扬州市| 东乌珠穆沁旗| 庄河市| 苏尼特右旗| 海安县| 云安县| 仙游县| 江源县| 象州县| 苏州市| 金坛市| 德保县| 嘉荫县| 白玉县| 锦州市| 荥经县| 房山区| 龙里县| 赞皇县| 临邑县| 通渭县| 洮南市| 安义县| 黄冈市| 榆中县| 中卫市| 合作市| 日喀则市| 鄯善县| 安平县| 龙游县| 北宁市| 利辛县| 汝州市| 二手房| 扶绥县| 泗水县| 体育| 花垣县|