• IRQ中断处理流程


     基于Linux2.6.30.4分析IRQ中断的处理流程。

    1.中断入口

    /* arch/arm/kenel/entry-armv.S*/
    b    vector_irq + stubs_offset

    2.vector_irq

    vector_stub 宏展开即为vector_irq, 参考Linux异常体系之vector_stub宏解析

    /*
     * 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)

    3.__irq_user

    __irq_usr:
    usr_entry      /*3.1*/
    kuser_cmpxchg_check
    
    #ifdef CONFIG_TRACE_IRQFLAGS
    bl    trace_hardirqs_off          
    #endif
    get_thread_info tsk     /*3.2*/
    
    #ifdef CONFIG_PREEMPT
    /*
    *r8<--old preempt_count
    *r7<--preempt_count+1
    *preempt_count<--r7
    */
    ldr    r8, [tsk, #TI_PREEMPT]    @ get preempt count
    add    r7, r8, #1    @ increment it
    str    r7, [tsk, #TI_PREEMPT]
    #endif
    
    irq_handler     /*3.3*/
    #ifdef CONFIG_PREEMPT
    /*
    *r0<--new preempt_count
    *preempt<--old preempt_count
    */
    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.4*/
    UNWIND(.fnend    )
    ENDPROC(__irq_usr)

     3.1__user_entry 

    .macro    usr_entry
    UNWIND(.fnstart    )
    UNWIND(.cantunwind    )    @ don't unwind the user space
    /* DEFINE(S_FRAME_SIZE,    sizeof(struct pt_regs));*/
    sub    sp, sp, #S_FRAME_SIZE    /**/
    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:
    @
    @ r2 - lr_<exception>, already fixed up for correct return/restart
    @ r3 - spsr_<exception>
    @ r4 - orig_r0 (see pt_regs definition in ptrace.h)
    @
    @ Also, separately save sp_usr and lr_usr
    @
    stmia    r0, {r2 - r4}
    /*“^”符号表示访问user mode的寄存器*/
    stmdb    r0, {sp, lr}^
    
    @
    @ Enable the alignment trap while in kernel mode
    @
    alignment_trap r0
    
    @
    @ Clear FP to mark the first stack frame
    @
    zero_fp
    .endm

     这里面用到pt_regs结构保存栈上的数据,8字节对齐

    /*
     * This struct defines the way the registers are stored on the
     * stack during a system call.  Note that sizeof(struct pt_regs)
     * has to be a multiple of 8.
     */
    struct pt_regs {
        long uregs[18];
    };

    与之相关的宏定义如下

    DEFINE(S_FRAME_SIZE,        sizeof(struct pt_regs));
      
    DEFINE(S_R0,            offsetof(struct pt_regs, ARM_r0));
    DEFINE(S_R1,            offsetof(struct pt_regs, ARM_r1));
    DEFINE(S_R2,            offsetof(struct pt_regs, ARM_r2));
    DEFINE(S_R3,            offsetof(struct pt_regs, ARM_r3));
    DEFINE(S_R4,            offsetof(struct pt_regs, ARM_r4));
    DEFINE(S_R5,            offsetof(struct pt_regs, ARM_r5));
    DEFINE(S_R6,            offsetof(struct pt_regs, ARM_r6));
    DEFINE(S_R7,            offsetof(struct pt_regs, ARM_r7));
    DEFINE(S_R8,            offsetof(struct pt_regs, ARM_r8));
    DEFINE(S_R9,            offsetof(struct pt_regs, ARM_r9));
    DEFINE(S_R10,            offsetof(struct pt_regs, ARM_r10));
    DEFINE(S_FP,            offsetof(struct pt_regs, ARM_fp));
    DEFINE(S_IP,            offsetof(struct pt_regs, ARM_ip));
    DEFINE(S_SP,            offsetof(struct pt_regs, ARM_sp));
    DEFINE(S_LR,            offsetof(struct pt_regs, ARM_lr));
    DEFINE(S_PC,            offsetof(struct pt_regs, ARM_pc));
    DEFINE(S_PSR,            offsetof(struct pt_regs, ARM_cpsr));
    DEFINE(S_OLD_R0,        offsetof(struct pt_regs, ARM_ORIG_r0));
    
    #define ARM_cpsr    uregs[16]
    #define ARM_pc        uregs[15]
    #define ARM_lr        uregs[14]
    #define ARM_sp        uregs[13]
    #define ARM_ip        uregs[12]
    #define ARM_fp        uregs[11]
    #define ARM_r10        uregs[10]
    #define ARM_r9        uregs[9]
    #define ARM_r8        uregs[8]
    #define ARM_r7        uregs[7]
    #define ARM_r6        uregs[6]
    #define ARM_r5        uregs[5]
    #define ARM_r4        uregs[4]
    #define ARM_r3        uregs[3]
    #define ARM_r2        uregs[2]
    #define ARM_r1        uregs[1]
    #define ARM_r0        uregs[0]
    #define ARM_ORIG_r0    uregs[17]
    macos

     3.2 get_thread_info tsk

    tsk即r9寄存器的别名,内核中为寄存器声明的别名如下

    /*
     * These are the registers used in the syscall handler, and allow us to
     * have in theory up to 7 arguments to a function - r0 to r6.
     *
     * r7 is reserved for the system call number for thumb mode.
     *
     * Note that tbl == why is intentional.
     *
     * We must set at least "tsk" and "why" when calling ret_with_reschedule.
     */
    scno    .req    r7        @ syscall number
    tbl    .req    r8        @ syscall table pointer
    why    .req    r8        @ Linux syscall (!= 0)
    tsk    .req    r9        @ current thread_info

    get_thread_info tsk的作用是获取sp地址保存在tsk(r9)中,即r9中保存当前任务的thread_info结构的地址。

    .macro    get_thread_info, rd
    mov    
    d, sp, lsr #13  /*获取sp地址*/
    mov    
    d, 
    d, lsl #13  /*8KBytes对齐*/
    .endm

    3.3 irq_handler

    irq_handler函数调用分析以后再写。

    /*
     * Interrupt handling.  Preserves r7, r8, r9
     */
        .macro    irq_handler
        get_irqnr_preamble r5, lr
    1:    get_irqnr_and_base r0, r6, r5, lr
        movne    r1, sp
        @
        @ routine called with r0 = irq number, r1 = struct pt_regs *
        @
        adrne    lr, 1b
        bne    asm_do_IRQ
    
    #ifdef CONFIG_SMP
        /*
         * XXX
         *
         * this macro assumes that irqstat (r6) and base (r5) are
         * preserved from get_irqnr_and_base above
         */
        test_for_ipi r0, r6, r5, lr
        movne    r0, sp
        adrne    lr, 1b
        bne    do_IPI
    
    #ifdef CONFIG_LOCAL_TIMERS
        test_for_ltirq r0, r6, r5, lr
        movne    r0, sp
        adrne    lr, 1b
        bne    do_local_timer
    #endif
    #endif
    
        .endm

     3.4 ret_to_user

    ret_to_user函数调用分析以后再写。

    /*
     * "slow" syscall return path.  "why" tells us if this was a real syscall.
     */
    ENTRY(ret_to_user)
    ret_slow_syscall:
        disable_irq                @ disable interrupts
        ldr    r1, [tsk, #TI_FLAGS]
        tst    r1, #_TIF_WORK_MASK
        bne    work_pending
    no_work_pending:
        /* perform architecture specific actions before user return */
        arch_ret_to_user r1, lr
    
        @ slow_restore_user_regs
        ldr    r1, [sp, #S_PSR]        @ get calling cpsr
        ldr    lr, [sp, #S_PC]!        @ get pc
        msr    spsr_cxsf, r1            @ save in spsr_svc
        ldmdb    sp, {r0 - lr}^            @ get calling r0 - lr
        mov    r0, r0
        add    sp, sp, #S_FRAME_SIZE - S_PC
        movs    pc, lr                @ return & move spsr_svc into cpsr
    ENDPROC(ret_to_user)
  • 相关阅读:
    2019自我剖析
    jzoj4640. 【GDOI2017模拟7.15】妖怪
    jzoj4649. 【NOIP2016提高A组模拟7.17】项链
    jzoj3171. 【GDOI2013模拟4】重心
    jzoj4673. 【NOIP2016提高A组模拟7.20】LCS again
    学习计算几何基础知识小结
    学习第一类斯特林数小记
    jzoj4213. 对你的爱深不见底
    jzoj4212. 【五校联考1day2】我想大声告诉你
    jzoj3085. 图的计数
  • 原文地址:https://www.cnblogs.com/yangjiguang/p/8128257.html
Copyright © 2020-2023  润新知