ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx

上传人:b****6 文档编号:19683650 上传时间:2023-01-08 格式:DOCX 页数:25 大小:99.70KB
下载 相关 举报
ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx_第1页
第1页 / 共25页
ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx_第2页
第2页 / 共25页
ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx_第3页
第3页 / 共25页
ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx_第4页
第4页 / 共25页
ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx

《ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx(25页珍藏版)》请在冰豆网上搜索。

ARMLinux中断源码分析2中断处理流程Word格式文档下载.docx

2.__vectors_start:

3. 

swi 

SYS_ERROR0

4. 

vector_und 

stubs_offset

5. 

ldr 

pc, 

.LCvswi 

6. 

vector_pabt 

7. 

vector_dabt 

8. 

vector_addrexcptn 

9. 

vector_irq 

stubs_offset@中断入口,vector_irq

10. 

vector_fiq 

11.

12. 

.globl 

__vectors_end

13.__vectors_end:

vector_irq+stubs_offset为中断的入口点,此处之所以要加上stubs_offset,是为了实现位置无关编程。

首先分析一下stubs_offset(宏是如何计算的:

.equ 

stubs_offset,__vectors_start+0x200-__stubs_start

在第3节中已经提到,内核启动时会将异常向量表拷贝到0xFFFF_0000,将异常向量处理程序的stub拷贝到0xFFFF_0200。

图5-1描述了异常向量表和异常处理程序搬移前后的内存布局。

图5-1 

异常向量表和异常处理程序搬移前后对比

当汇编器看到B指令后会把要跳转的标签转化为相对于当前PC的偏移量(±

32M)写入指令码。

由于内核启动时中断向量表和stubs都发生了代码搬移,所以如果中断向量表中仍然写成bvector_irq,那么实际执行的时候就无法跳转到搬移后的vector_irq处,因为指令码里写的是原来的偏移量,所以需要把指令码中的偏移量写成搬移后的。

设搬移后的偏移量为offset,如图5-1所示,

offset=L1+L2

=[0x200-(irq_PC_X-__vectors_start_X]+(vector_irq_X-__stubs_start_X

=[0x200-(irq_PC-__vectors_start]+(vector_irq-__stubs_start

=0x200-irq_PC+__vectors_start+vector_irq-__stubs_start

=vector_irq+(__vectors_start+0x200-__stubs_start-irq_PC

令stubs_offset=__vectors_start+0x200-__stubs_start

则offset=vector_irq+stubs_offset-irq_PC,所以中断入口点为“b 

vector_irq+stubs_offset”,其中减去irq_PC是由汇编器在编译时完成的。

vector_irq处理函数

在分析vector_irq处理函数之前,先了解一下当一个异常或中断导致处理器模式改变时,ARM处理器内核的处理流程如下图所示:

 

中断刚发生时,处理器处于irq模式。

在__stubs_start和__stubs_end之间找到vector_irq处理函数的定义vector_stubirq,IRQ_MODE,4,其中vector_stub是一个宏(在arch/arm/kernel/entry_armv.S中定义),为了分析更直观,我们将vector_stub宏展开如下:

1./*

2. 

Interruptdispatcher

*/

vector_irq:

.if 

sub 

lr, 

#4 

@在中断发生时,lr指向最后执行的指令地址加上8。

只有在当前指令执行完毕后,才进入中断处理,所以返回地址应指向下一条指令,即(lr-4)处。

.endif

8.

9.@

@Saver0, 

lr_<

exception>

(parentPC 

and 

spsr_<

11. 

(parentCPSR

@

13. 

stmia 

sp, 

{r0, 

lr} 

@保存r0, 

lr到irq模式下的栈中

14. 

mrs 

spsr

15. 

str 

[sp, 

#8] 

@保存spsr到irq模式下的栈中

16.

17. 

18. 

@Prepare 

for 

SVC32mode. 

IRQsremaindisabled.

19. 

20. 

r0, 

cpsr 

21. 

eor 

#( 

IRQ_MODE^SVC_MODE 

@设置成SVC模式,但未切换

22. 

msr 

spsr_cxsf, 

r0@保存到spsr_irq中

23.

24. 

25. 

@thebranchtablemustimmediatelyfollow 

this 

code

26. 

27. 

#0x0f@lr存储着上一个处理器模式的cpsr值,lr 

lr&

0x0f取出用于判断发生中断前是用户态还是核心态的信息,该值用于下面跳转表的索引。

28. 

mov 

sp@将irq模式下的sp保存到r0,作为参数传递给即将调用的__irq_usr或__irq_svc

29. 

[pc, 

lsl 

#2] 

@pc指向当前执行指令地址加8,即跳转表的基址。

lr作为索引,由于是4字节对齐,所以lr 

lr 

<

2.

30. 

movs 

lr@branchtohandler 

in 

SVCmode

31. 

@当mov指令后加“s”且目标寄存器为pc时,当前模式下的spsr会被复制到cpsr,从而完成模式切换(从irq模式切换到svc模式)并且跳转到pc指向的指令继续执行

32.ENDPROC(vector_irq

33.

34. 

.long 

__irq_usr 

@0 

(USR_26/USR_32

35. 

__irq_invalid 

@1 

(FIQ_26/FIQ_32

36. 

@2 

(IRQ_26/IRQ_32

37. 

__irq_svc 

@3 

(SVC_26/SVC_32

38. 

@4

39. 

@5

40. 

@6

41. 

@7

42. 

@8

43. 

@9

44. 

@a

45. 

@b

46. 

@c

47. 

@d

48. 

@e

49. 

@f

__irq_usr

如果发生中断前处于用户态则进入__irq_usr,其定义如下(arch/arm/kernel/entry_armv.S):

1..align 

2.__irq_usr:

usr_entry@保存中断上下文,稍后分析

kuser_cmpxchg_check

5.#ifdefCONFIG_TRACE_IRQFLAGS

bl 

trace_hardirqs_off

7.#endif

get_thread_infotsk@获取当前进程的进程描述符中的成员变量thread_info的地址,并将该地址保存到寄存器tsk(r9)(在entry-header.S中定义)

9.#ifdefCONFIG_PREEMPT@如果定义了抢占,增加抢占数值

r8, 

[tsk, 

#TI_PREEMPT] 

@获取preempt计数器值

add 

r7, 

#1 

@preempt加1,标识禁止抢占

@将加1后的结果写入进程内核栈的变量中

13.#endif

irq_handler@调用中断处理程序,稍后分析

15.#ifdefCONFIG_PREEMPT

16. 

@获取preempt计数器值

@将preempt恢复到中断前的值

teq 

r7@比较中断前后preempt是否相等

strne 

[r0, 

-r0] 

@如果不等,则产生异常(向地址0写入数据)?

20.#endif

21.#ifdefCONFIG_TRACE_IRQFLAGS

trace_hardirqs_on

23.#endif

why, 

#0@r8=0

ret_to_user@中断处理完成,恢复中断上下文并返回中断产生的位置,稍后分析

UNWIND(.fnend 

27.ENDPROC(__irq_usr

宏定义usr_entry(保护上下文到栈

上面代码中的usr_entry是一个宏定义,主要用于保护上下文到栈中:

1..macro 

usr_entry

UNWIND(.fnstart 

UNWIND(.cantunwind 

@dontunwindtheuserspace

#S_FRAME_SIZE@ATPCS中,堆栈被定义为递减式满堆栈,所以首先让sp向下移动#S_FRAME_SIZE(pt_regs结构体size),准备向栈中存放数据。

此处的sp是svc模式下的栈指针。

stmib 

{r1 

r12}

6.

ldmia 

r3}

#S_PC 

@here 

interlockavoidance

r4, 

#-1 

"

10.

r1, 

[sp] 

@savethe 

real"

r0copied

@fromtheexceptionstack

13.

@Wearenowreadytofill 

theremainingblanksonthestack:

@r2 

 

alreadyfixedup 

correctreturn/restart

@r3 

@r4 

orig_r0 

(seept_regsdefinition 

ptrace.h

@Also, 

separatelysavesp_usr 

lr_usr

23. 

{r2 

r4}

stmdb 

{sp, 

lr}^@将user模式下的sp和lr保存到svc模式的栈中

25.

@Enablethealignmenttrap 

while 

kernelmode

alignment_trapr0

30.

32. 

@ClearFPtomarkthefirststackframe

33. 

zero_fp

.endm

上面的这段代码主要是在填充结构体pt_regs,在include/asm/ptrace.h中定义:

1.struct 

pt_regs{

longuregs[18];

3.};

4.

5.#defineARM_cpsr 

uregs[16]

6.#defineARM_pc 

uregs[15]

7.#defineARM_lr 

uregs[14]

8.#defineARM_sp 

uregs[13]

9.#defineARM_ip 

uregs[12]

10.#defineARM_fp 

uregs[11]

11.#defineARM_r10 

uregs[10]

12.#defineARM_r9 

uregs[9]

13.#defineARM_r8 

uregs[8]

14.#defineARM_r7 

uregs[7]

15.#defineARM_r6 

uregs[6]

16.#defineARM_r5 

uregs[5]

17.#defineARM_r4 

uregs[4]

18.#defineARM_r3 

uregs[3]

19.#defineARM_r2 

uregs[2]

20.#defineARM_r1 

uregs[1]

21.#defineARM_r0 

uregs[0]

22.#defineARM_ORIG_r0 

uregs[17]

usr_entry宏填充pt_regs结构体的过程如图5-2所示,先将r1~r12保存到ARM_r1~ARM_ip(绿色部分),然后将产生中断时的r0寄存器内容保存到ARM_r0(蓝色部分),接下来将产生中断时的下一条指令地址lr_irq、spsr_irq和r4保存到ARM_pc、ARM_cpsr和ARM_ORIG_r0(红色部分),最后将用户模式下的sp和lr保存到ARM_sp 

和ARM_lr 

中。

图5-2usr_entry宏填充pt_regs结构体

__irq_svc

如果发生中断前处于核心态则进入__irq_svc,其定义如下(arch/arm/kernel/entry_armv.S):

2.__irq_svc:

svc_entry@保存中断上下文

8.#ifdefCONFIG_PREEMPT

get_thread_infotsk

14.

16.#ifdefCONFIG_PREEMPT

@恢复中断前的preempt计数器

#TI_FLAGS] 

@获取flags

#0 

@判断preempt是否等于0

movne 

@如果preempt不等于0,r0=0

tst 

#_TIF_NEED_RESCHED@将r0与#_TIF_NEED_RESCHED做“与操作”

blne 

svc_preempt@如果不等于0,说明发生内核抢占,需要重新调度。

24.

#S_PSR] 

@irqsarealreadydisabled

r0

27.#ifdefCONFIG_TRACE_IRQFLAGS

#PSR_I_BIT

bleq 

30.#endif

svc_exitr4 

@恢复中断上下文,稍后分析。

33.ENDPROC(__irq_svc

宏定义svc_entry(保护中断上下文到栈

其中svc_entry是一个宏定义,主要用于保护中断上下文到栈中。

svc_entry主要是在当前堆栈上分配一个pt_regs结构,把r0-r15以及cpsr等保存到这个结构中,在进入irq_handler时,sp指向pt_regs底端:

svc_entry, 

stack_hole=0

UNWIND(.save{r0 

pc} 

#(S_FRAME_SIZE 

\stack_hole

SPFIX( 

bicne 

r5, 

#S_SP 

addne 

lr

18.

@r0 

sp_svc

@r1 

lr_svc

{r0 

svc_entry宏填充pt_regs结构体的过程如图5-2所示,先将r1~r12保存到ARM_r1~ARM_ip(绿色部分),然后将产生中断时的r0寄存器内容保存到ARM_r0(蓝色部分),由于是在

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1