linux arm 中断映射表,ARM Linux 中断向量表建立流程

Linux Version : 2.6.29

1. start_kernel-->setup_arch-->early_trap_init

1:

memcpy((void

*)vectors, __vectors_start, __vectors_end - __vectors_start);

2:

memcpy((void

*)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);

3:

memcpy((void

*)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

对于第一行:

__vectors_start 和 __vectors_end 定义在 arch/arm/kernel/entry-armv.S  , 它们之间保存了中断向量表。

1:

.globl __vectors_start

2:

__vectors_start:

3:

swi SYS_ERROR0

4:

b vector_und + stubs_offset

5:

ldr pc, .LCvswi + stubs_offset

6:

b vector_pabt + stubs_offset

7:

b vector_dabt + stubs_offset

8:

b vector_addrexcptn + stubs_offset

9:

b vector_irq + stubs_offset

10:

b vector_fiq + stubs_offset

11:

12:

.globl __vectors_end

13:

__vectors_end:

vectors 的地址为CONFIG_VECTORS_BASE , 在.config中定义为0xffff0000

所以 第1行就是把中断向量表拷贝到0xffff0000

对于第二行:

vector_stub是一个带参数的宏,第一个是name,第二个是arm excepiton mode,第三个是为了得到返回地址,lr需要减去的偏移

1:

.macro vector_stub, name, mode, correction=0

2:

.align 5

3:

4:

vector_/name:

5:

.if

/correction

6:

sub lr, lr, #/correction @得到正确的返回地址

7:

.endif

8:

9:

@

10:

@ Save r0, lr_(parent PC) and spsr_

11:

@ (parent CPSR)

12:

@

13:

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

14:

mrs lr, spsr

15:

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

16:

17:

@

18:

@ Prepare for

SVC32 mode. IRQs remain disabled.

19:

@

20:

mrs r0, cpsr

21:

eor r0, r0, #(/mode ^ SVC_MODE) @把cpsr内容与(mode^SVC_mode)异或,即r0里为SVC_MODE

22:

msr spsr_cxsf, r0 @把r0的值写入整个spsr寄存器(cxsf表示要往哪个字节写入)

23:

24:

@

25:

@ the branch table must immediately follow this

code

26:

@

27:

and lr, lr, #0x0f  @lr为spsr_的值,此语句取到进入异常前的mode

28:

mov r0, sp @

29:

ldr lr, [pc, lr, lsl #2] @lr=pc+mode*4,其中pc为紧接着30的指令,即vector_stub后的第一条指令

30:

movs pc, lr @ movs会把spsr的值赋给cpsr,所以branch to handler in

SVC mode

31:

ENDPROC(vector_/name)

32:

.endm

再来看下vector 跳转表

1:

.long

__irq_usr @ 0 (USR_26 / USR_32)

2:

.long

__irq_invalid @ 1 (FIQ_26 / FIQ_32)

3:

.long

__irq_invalid @ 2 (IRQ_26 / IRQ_32)

4:

.long

__irq_svc @ 3 (SVC_26 / SVC_32)

5:

.long

__irq_invalid @ 4

6:

.long

__irq_invalid @ 5

7:

.long

__irq_invalid @ 6

8:

.long

__irq_invalid @ 7

9:

.long

__irq_invalid @ 8

10:

.long

__irq_invalid @ 9

11:

.long

__irq_invalid @ a

12:

.long

__irq_invalid @ b

13:

.long

__irq_invalid @ c

14:

.long

__irq_invalid @ d

15:

.long

__irq_invalid @ e

16:

.long

__irq_invalid @ f

这里只有usr 和svc 有入口,而其他都是invalid ,是因为linux只会从usr(application) 和svc(kernel)两种mode跳转到exception来

__stubs_start 和 __stubs_end 之间的代码简化后为:

1:

__stubs_start:

2:

vector_irq: @vector_stub irq, IRQ_MODE, 4

3:

vector_dabt:   @vector_stub dabt, ABT_MODE, 8

4:

vector_pabt: @vector_stub pabt, ABT_MODE, 4

5:

vector_und:    @vector_stub und, UND_MODE

6:

vector_fiq:

7:

vector_addrexcptn:

8:

.LCvswi:

9:

__stubs_end:

由此可以知道 __stubs_start 和 __stubs_end 之间定义了各种异常的入口

我们再来看为什么异常入口是“b vector_und + stubs_offset”, 同时为什么stubs_offset 的定义如下

.equ stubs_offset, __vectors_start + 0x200 - __stubs_start

arm 的跳转指令b 是跳转到相对于PC的一个偏移地址( offset ),汇编器在编译时会对label 减去PC 得到offset,同时vector 拷贝后是如下排列的

__vectors_start

B vector_

__vectors_end

+0x200

__stubs_start

vector_

__stubs_end

因此,"b vector_"  的label –PC =  offset, 而offset 为 b 指令与vector的offset,即

vector_-__stubs_start + ( 0x200 – ( PC_old – __vectors_start ) )

= vector_+ __vectors_start + 0x200 – __stubs_start – PC_old

所以异常入口为“b vector_und + stubs_offset”, 同时stubs_offset= __vectors_start + 0x200 – __stubs_start

我们可以通过objdump反汇编来验证:

00000060 :

.globl    __stubs_start

__stubs_start: /*

* Interrupt dispatcher

*/

vector_stub    irq, IRQ_MODE, 4

60 :    e24ee004     sub    lr, lr, #4    ; 0x4

64:    e88d4001     stm    sp, {r0, lr}

1d4:    e1a00000     .word    0xe1a00000

1d8:    e1a00000     .word    0xe1a00000

1dc:    e1a00000     .word    0xe1a00000

000001e0 :

/*

* Undef instr entry dispatcher

* Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC

*/

__vectors_start:

swi    SYS_ERROR0

284:    ef9f0000     svc    0x009f0000

b    vector_und + stubs_offset

288:    ea0000dd     b    604 ldr    pc, .LCvswi + stubs_offset

28c:    e59ff410     ldr    pc, [pc, #1040]    ; 6a4 b    vector_pabt + stubs_offset

290:    ea0000bb     b    584 b    vector_dabt + stubs_offset

294:    ea00009a     b    504 b    vector_addrexcptn + stubs_offset

298:    ea0000fa     b    688 b    vector_irq + stubs_offset

29c:    ea000078     b    484 b    vector_fiq + stubs_offset

2a0:    ea0000f7     b    684

0x1e0 – 0x60 + 0x200 – ( 0x288 + 8 ) – 0x284 = 0xdd*4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值