注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

小白的博客

嵌入式爱好者

 
 
 

日志

 
 

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

2012-09-10 00:24:06|  分类: 韦东山视频第二轮 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
__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 + 0x200, __stubs_start, __stubs_end - __stubs_start);
综上来看,其实代码的目的是跳转到vector_irq标号处执行,但为什么要加上一个偏移地址呢?这是因为b是相对跳转指令,b vector_irq会用当前pc值加上当前pc地址与vector_irq的偏移量来进行跳转!而这个偏移量是编译链接的时候就确定好的,换句话说这个偏移量是重定位之前的偏移量,不是重定位之后的偏移量,所以如果我们仍然使用vector_irq将不能跳转到vector_irq标号处,因为偏移量已经改变了!而b vector_irq + stubs_offset这条指令为分析方便起见我们可以将其分为两步,首先执行:vector_irq,然后跳转到:pc+stubs_offset地址处。也就是说在之前偏移量的基础上又增加了一个偏移量:stubs_offset。下面就是如何计算增加的这个偏移量的问题了,为了分析清楚,我们采用图解的方式。在分析在分析之前,我们需要重申一下,重定位后的代码的地址是链接地址,这是在编译连接时确定的,并不对应重定位后的真实地址,也就是说重定位后的代码,其地址仍然是重定位之前的地址,这也是为什么之前不用绝对跳转指令的原因。下面开始分析:

linux-3.4.2中断机制分析——中断入口代码分析 - 小白 - 小白的博客
 
 由于我们用的是相对跳转指令,所以姑且认为__vectors_start与__vectors_end之间的代码没有重定位,而__stubs_start与__stubs_end之间的代码拷贝到了__vectors_start + 200地址处!我们要做的就是计算出_stubs_start' - _stubs_start的值:
_stubs_start' - _vectors_start=200;所以stubs_start' - _stubs_start=200 + _vectors_start - _stubs_start由此可以知道为什么stubs_offset = __vectors_start + 0x200 - __stubs_start。
 
下面我们需要找到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  处执行了,下一节继续!
  评论这张
 
阅读(1383)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017