linux 2.6代码分析,linux-2.6.38中断机制分析—中断入口代码分析

linux-2.6.38中断机制分析—中断入口代码分析

__vectors_start:

ARM( swi

SYS_ERROR0 )

THUMB( svc

#0 )

THUMB(

nop )

W(b)

vector_und + stubs_offset

W(ldr) pc,

.LCvswi +

stubs_offset

W(b)

vector_pabt + stubs_offset

W(b)

vector_dabt + stubs_offset

W(b)

vector_addrexcptn + stubs_offset

W(b)

vector_irq + stubs_offset

W(b)

vector_fiq + stubs_offset

.globl

__vectors_end

__vectors_end:

比如一旦发生中断就会跳转到:W(b)

vector_irq + stubs_offset

其中:.equ stubs_offset, __vectors_start +

0x200 - __stubs_start

之前有如下拷贝命令:

memcpy((void *)vectors,

__vectors_start, __vectors_end - __vectors_start);

memcpy((void *)vectors +

0x200, __stubs_start, __stubs_end - __stubs_start);

上述拷贝是将中断向量表和中断向量表跳转的目的代码拷贝到新的位置(0xffff0000和0xffff0000+0x200处)

关于stubs_offset的取值是怎么来的,在网上搜了很多,但都差不多,各种解释让人难以理解,一方面是思维方式不同造成的,同时很多存在一些错误,以下给出本人的想法:

为什么要stubs_offset呢?

1.

对于B跳转指令的执行,由于是相对地址,即偏移地址,在重定位后,由于跳转指令所在位置与将要跳转到的目的位置的偏移量发生了变化,故要加一个偏移量

2.

对于W(ldr) pc, .LCvswi +

stubs_offset,为绝对地址跳转,跳转到的目的地址也并没有被重定位,故不会因此而需要偏移地址。之所以有偏移,是由于LCvswi地址被重定位了,定义如下

. LCvswi:

.word vector_swi

故也需要一个地址偏移

stubs_offset的计算:

首先我们要知道,上面重定位的两部分代码,在重定位前后,其每部分内部的相对位置是没有发生变化的,只是两部分之间的部分偏移发生了变化。如下图所示:

(irq_entry - _vectors_start)

= (irq_entry’ - _vectors_start’) =

V1

中断向量表

(vector_irq - _stubs_start) = (vector_irq’ - _stubs_start’) =

V2 目的代码

重定位前:

irq_entry = _vectors_start +

V1 IRQ向量表地址

vector_irq

= _stubs_start + V2

IRQ跳转目的地址

跳转地址与目的地址间的偏移(相对地址):

P1 = (vector_irq -

irq_entry) =(_stubs_start - _vectors_start)

+ ( V2 - V1)

重定位后:

irq_entry’ = _vectors_start’

+

V1 IRQ向量表地址

vector_irq’

= _stubs_start’ + V2

IRQ跳转目的地址

跳转地址与目的地址间的偏移(重定位后相对地址):

P2 = (vector_irq’ -

irq_entry’) =(_stubs_start’ - _vectors_start’)

+ ( V2 - V1)

由此可得出重定位后的相对地址和重定位前的相对地址变化量:

P = P2 – P1

= ((_stubs_start’ - _vectors_start’)

+ ( V2 - V1)) –

((_stubs_start -

_vectors_start)

+ ( V2 - V1))

= 0x200 -

(_stubs_start -

_vectors_start)

= __vectors_start + 0x200 -

__stubs_start

a4c26d1e5885305701be709a3d33442f.png

下面我们需要找到vector_irq的位置。

我们可以看到如下代码:

vector_stub irq, IRQ_MODE,

4

这其实是个宏:

.macro

vector_stub, name, mode, correction=0

.align

5

vector_\name:

.if

\correction

sub lr,

lr, #\correction

.endif

stmia sp,

{r0, lr}

mrs lr,

spsr

str lr,

[sp, #8]

mrs r0,

cpsr

eor r0,

r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)

msr

spsr_cxsf, r0

and lr,

lr, #0x0f

THUMB( adr

r0, 1f )

THUMB( ldr

lr, [r0, lr, lsl #2] )

mov r0,

sp

ARM( ldr

lr, [pc, lr, lsl #2] )

movs pc,

lr

ENDPROC(vector_\name)

.align

2

1:

.endm

我们试着将其展开:

vector_irq:

stmia sp,

{r0, lr}

mrs lr,

spsr  @lr=spsr

str lr,

[sp, #8]

mrs r0,

cpsr

eor r0,

r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)

msr

spsr_cxsf, r0

and lr,

lr, #0x0f  @取lr的最后四位,其标志进入中断之前处于什么模式

THUMB( adr

r0, 1f )

THUMB( ldr

lr, [r0, lr, lsl #2] )

mov r0,

sp

ARM( ldr

lr, [pc, lr, lsl #2] )

@lr=pc+lr*4

movs pc,

lr @pc=lr

ENDPROC(vector_irq)

.align

2

1:

.endm

接下来的代码是:

.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

会根据进入中断之前所在的模式不同而跳转到不同的位置,不如之前处于用户模式,则lr=0,所以会跳转到:

.long __irq_usr

处,我们就以这个为例继续分析:

__irq_usr

irq_handler

这是一个宏,我们看它的定义:

.macro

irq_handler

#ifdef

CONFIG_MULTI_IRQ_HANDLER

ldr r1,

=handle_arch_irq

mov r0,

sp

adr lr,

BSYM(9997f)

ldr pc,

[r1]

#else

arch_irq_handler_default

#endif

9997:

.endm

由于没有定义:CONFIG_MULTI_IRQ_HANDLER,所以简化下就是执行:arch_irq_handler_default,这也是一个宏,我们看它的定义:

.macro

arch_irq_handler_default

get_irqnr_preamble r6, lr

1: get_irqnr_and_base r0,

r2, r6, lr

movne r1,

sp

adrne lr,

BSYM(1b)

bne

asm_do_IRQ  @这就是我们的曙光了

9997:

.endm

接着就跳转到asm_do_IRQ处执行了,下一节继续!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值