Linux异常处理体系结构

arm11处理器裸机的异常与中断处理参考:

【OK6410裸机程序】异常处理

【OK6410裸机程序】按键中断

另外参考一篇:Linux中断体系结构

在ARM V4及V4T以后的大部分处理器中,中断向量表的位置可以有两个位置:一个是0,另一个是0xffff0000。可以通过CP15协处理器c1寄存器中V位(bit[13])控制。V和中断向量表的对应关系如下:  [V=0]0x00000000~0x0000001C /[V=1]0xffff0000~0xffff001C  。Linux内核使用0xffff0000。

 

异常向量的代码很简单,只是一些跳转指令。发生异常时,cpu自动执行这些指令,跳转到更复杂得代码。

地址__vectors_start~__vectors_end间的代码就是异常向量,在arch/arm/kernel/entry-armv.S中定义,这些异常向量会被复制到0xffff0000处。

    .globl    __vectors_start
__vectors_start:
    swi    SYS_ERROR0                   //复位时,cpu将执行这条指令
    b    vector_und + stubs_offset    //未定义异常时,cpu执行这条指令
    ldr    pc, .LCvswi + stubs_offset   //swi异常
    b    vector_pabt + stubs_offset   //指令预取终止
    b    vector_dabt + stubs_offset   //数据访问终止
    b    vector_addrexcptn + stubs_offset //没有用到
    b    vector_irq + stubs_offset    //irq异常
    b    vector_fiq + stubs_offset    //fiq异常

    .globl    __vectors_end
__vectors_end:

 “更复杂得代码”在地址__stubs_start~__stubs_end之间,在arch/arm/kernel/entry-armv.S中定义,这些异常向量会被复制到0xffff0200处。

  1     .globl    __stubs_start
  2 __stubs_start:
  3 /*
  4  * Interrupt dispatcher
  5  */
  6     vector_stub    irq, IRQ_MODE, 4
  7 
  8     .long    __irq_usr            @  0  (USR_26 / USR_32)
  9     .long    __irq_invalid            @  1  (FIQ_26 / FIQ_32)
 10     .long    __irq_invalid            @  2  (IRQ_26 / IRQ_32)
 11     .long    __irq_svc            @  3  (SVC_26 / SVC_32)
 12     .long    __irq_invalid            @  4
 13     .long    __irq_invalid            @  5
 14     .long    __irq_invalid            @  6
 15     .long    __irq_invalid            @  7
 16     .long    __irq_invalid            @  8
 17     .long    __irq_invalid            @  9
 18     .long    __irq_invalid            @  a
 19     .long    __irq_invalid            @  b
 20     .long    __irq_invalid            @  c
 21     .long    __irq_invalid            @  d
 22     .long    __irq_invalid            @  e
 23     .long    __irq_invalid            @  f
 24 
 25 /*
 26  * Data abort dispatcher
 27  * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
 28  */
 29     vector_stub    dabt, ABT_MODE, 8
 30 
 31     .long    __dabt_usr            @  0  (USR_26 / USR_32)
 32     .long    __dabt_invalid            @  1  (FIQ_26 / FIQ_32)
 33     .long    __dabt_invalid            @  2  (IRQ_26 / IRQ_32)
 34     .long    __dabt_svc            @  3  (SVC_26 / SVC_32)
 35     .long    __dabt_invalid            @  4
 36     .long    __dabt_invalid            @  5
 37     .long    __dabt_invalid            @  6
 38     .long    __dabt_invalid            @  7
 39     .long    __dabt_invalid            @  8
 40     .long    __dabt_invalid            @  9
 41     .long    __dabt_invalid            @  a
 42     .long    __dabt_invalid            @  b
 43     .long    __dabt_invalid            @  c
 44     .long    __dabt_invalid            @  d
 45     .long    __dabt_invalid            @  e
 46     .long    __dabt_invalid            @  f
 47 
 48 /*
 49  * Prefetch abort dispatcher
 50  * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
 51  */
 52     vector_stub    pabt, ABT_MODE, 4
 53 
 54     .long    __pabt_usr            @  0 (USR_26 / USR_32)
 55     .long    __pabt_invalid            @  1 (FIQ_26 / FIQ_32)
 56     .long    __pabt_invalid            @  2 (IRQ_26 / IRQ_32)
 57     .long    __pabt_svc            @  3 (SVC_26 / SVC_32)
 58     .long    __pabt_invalid            @  4
 59     .long    __pabt_invalid            @  5
 60     .long    __pabt_invalid            @  6
 61     .long    __pabt_invalid            @  7
 62     .long    __pabt_invalid            @  8
 63     .long    __pabt_invalid            @  9
 64     .long    __pabt_invalid            @  a
 65     .long    __pabt_invalid            @  b
 66     .long    __pabt_invalid            @  c
 67     .long    __pabt_invalid            @  d
 68     .long    __pabt_invalid            @  e
 69     .long    __pabt_invalid            @  f
 70 
 71 /*
 72  * Undef instr entry dispatcher
 73  * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
 74  */
 75     vector_stub    und, UND_MODE
 76 
 77     .long    __und_usr            @  0 (USR_26 / USR_32)
 78     .long    __und_invalid            @  1 (FIQ_26 / FIQ_32)
 79     .long    __und_invalid            @  2 (IRQ_26 / IRQ_32)
 80     .long    __und_svc            @  3 (SVC_26 / SVC_32)
 81     .long    __und_invalid            @  4
 82     .long    __und_invalid            @  5
 83     .long    __und_invalid            @  6
 84     .long    __und_invalid            @  7
 85     .long    __und_invalid            @  8
 86     .long    __und_invalid            @  9
 87     .long    __und_invalid            @  a
 88     .long    __und_invalid            @  b
 89     .long    __und_invalid            @  c
 90     .long    __und_invalid            @  d
 91     .long    __und_invalid            @  e
 92     .long    __und_invalid            @  f
 93 
 94     .align    5
 95 
 96 /*=============================================================================
 97  * Undefined FIQs
 98  *-----------------------------------------------------------------------------
 99  * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
100  * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
101  * Basically to switch modes, we *HAVE* to clobber one register...  brain
102  * damage alert!  I don't think that we can execute any code in here in any
103  * other mode than FIQ...  Ok you can switch to another mode, but you can't
104  * get out of that mode without clobbering one register.
105  */
106 vector_fiq:
107     disable_fiq
108     subs    pc, lr, #4
109 
110 /*=============================================================================
111  * Address exception handler
112  *-----------------------------------------------------------------------------
113  * These aren't too critical.
114  * (they're not supposed to happen, and won't happen in 32-bit data mode).
115  */
116 
117 vector_addrexcptn:
118     b    vector_addrexcptn
119 
120 /*
121  * We group all the following data together to optimise
122  * for CPUs with separate I & D caches.
123  */
124     .align    5
125 
126 .LCvswi:
127     .word    vector_swi
128 
129     .globl    __stubs_end
130 __stubs_end:
__stubs_start

关于stubs_offset的值及解析,参考Linux异常体系之stubs_offset

关于__stubs_start~__stubs_end之间的代码解析,参考vector_stub宏解析 。vector_irq、 vector_dabt、vector_pabt、vector_und、vector_fiq都在它们中间。

各种异常的C处理函数分为5类,分布在不同的函数中。

1.中断处理C总入口函数asm_do_IRQ,在linux/arch/arm/kernel/irq.c中。它调用其它文件注册的中断处理函数。

init_IRQ函数被用来初始化中断的处理框架,设置各种中断的默认处理函数。当中断发生时,中断总入口函数asm_do_IRQ就可以调用这些函数坐进一步的处理。

b    vector_irq + stubs_offset
    -->vector_stub    irq, IRQ_MODE, 4
        -->__irq_usr/__irq_svc
            -->void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

2.未定义指令处理C总入口函数do_undefinstr,在linux/arch/arm/kernel/traps.c中。

b    vector_und + stubs_offset
    -->vector_stub    und, UND_MODE
        -->__und_usr/__und_svc
            -->b    do_undefinstr

3.与内存访问相关的异常处理C总入口函数do_DataAbort,do_PrefechAbort,在linux/arch/arm/kernel/fault.c中。

4.swi异常处理函数,在在linux/arch/arm/kernel/calls.S中。swi异常的处理函数指针被组织成一个表格;swi指令机器码的为[23:0]用来作为索引,通过不同的“swi index”指令可以调用不同的swi异常处理函数,也称为系统调用,比如sys_open、sys_read、sys_write等。

5.没有使用的异常,linux中没有使用FIQ异常。

 

posted @ 2017-10-05 19:38  bluebluebluesky  阅读(914)  评论(0编辑  收藏  举报