ARM Linux中断源码分析(2)——中断处理流程.docx
《ARM Linux中断源码分析(2)——中断处理流程.docx》由会员分享,可在线阅读,更多相关《ARM Linux中断源码分析(2)——中断处理流程.docx(98页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、Four short words sum up what has lifted most successful individuals above the crowd: a little bit more.-author-dateARM Linux中断源码分析(2)中断处理流程ARM Linux中断源码分析(2)中断处理流程ARM Linux中断源码分析(2)中断处理流程ARM支持7类异常中断,所以中断向量表设8个条目,每个条目4字节,共32字节。异常名称中断向量异常中断模式优先级复位0x0特权模式1未定义的指令0x4未定义指令中止模式6软件中断0x8特权模式6指令预取中止0x0c中止模式5数
2、据访问中止0x10中止模式2保留0x14外部中断请求IRQ0x18IRQ模式4快速中断请求FIQ0x1cFIQ模式3回顾第一节所讲的内容,当一个异常或中断发生时,处理器会将PC设置为特定地址,从而跳转到已经初始化好的异常向量表。因此,要理清中断处理流程,先从异常向量表开始。对于ARM Linux而言,异常向量表和异常处理程序都存在arch/arm/kernel/entry_armv.S汇编文件中。vector异常向量表点击(此处)折叠或打开1. .globl_vectors_start2. _vectors_start:3. swiSYS_ERROR04. bvector_und+stubs_
3、offset5. ldrpc,.LCvswi+stubs_offset6. bvector_pabt+stubs_offset7. bvector_dabt+stubs_offset8. bvector_addrexcptn+stubs_offset9. bvector_irq+stubs_offset 中断入口,vector_irq10. bvector_fiq+stubs_offset11.12. .globl_vectors_end13. _vectors_end:vector_irq+stubs_offset为中断的入口点,此处之所以要加上stubs_offset,是为了实现位置无关编
4、程。首先分析一下stubs_offset(宏)是如何计算的:.equstubs_offset, _vectors_start + 0x200 - _stubs_start在第3节中已经提到,内核启动时会将异常向量表拷贝到 0xFFFF_0000,将异常向量处理程序的 stub 拷贝到 0xFFFF_0200。图5-1描述了异常向量表和异常处理程序搬移前后的内存布局。图5-1异常向量表和异常处理程序搬移前后对比当汇编器看到B指令后会把要跳转的标签转化为相对于当前PC的偏移量(32M)写入指令码。由于内核启动时中断向量表和stubs都发生了代码搬移,所以如果中断向量表中仍然写成b vector_i
5、rq,那么实际执行的时候就无法跳转到搬移后的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 - _stub
6、s_start= vector_irq + (_vectors_start + 0x200 - _stubs_start) - irq_PC令stubs_offset = _vectors_start + 0x200 - _stubs_start则offset = vector_irq + stubs_offset - irq_PC,所以中断入口点为“bvector_irq + stubs_offset”,其中减去irq_PC是由汇编器在编译时完成的。vector_irq处理函数在分析vector_irq处理函数之前,先了解一下当一个异常或中断导致处理器模式改变时,ARM处理器内核的处理流程如
7、下图所示: 中断刚发生时,处理器处于irq模式。在_stubs_start和_stubs_end之间找到vector_irq处理函数的定义vector_stub irq, IRQ_MODE, 4,其中vector_stub是一个宏(在arch/arm/kernel/entry_armv.S中定义),为了分析更直观,我们将vector_stub宏展开如下:1. /*2. *Interrupt dispatcher3. */4. vector_irq:5. .if46. sublr,lr,#4在中断发生时,lr指向最后执行的指令地址加上8。只有在当前指令执行完毕后,才进入中断处理,所以返回地址应指
8、向下一条指令,即(lr-4)处。7. .endif8.9. 10. Save r0,lr_(parent PC)andspsr_11. (parent CPSR)12. 13. stmiasp,r0,lr 保存r0,lr到irq模式下的栈中14. mrslr,spsr15. strlr,sp,#8保存spsr到irq模式下的栈中16.17. 18. PrepareforSVC32 mode.IRQs remain disabled.19. 20. mrsr0,cpsr21. eorr0,r0,#(IRQ_MODE SVC_MODE)设置成SVC模式,但未切换22. msrspsr_cxsf,r
9、0 保存到spsr_irq中23.24. 25. the branch table must immediately followthiscode26. 27. andlr,lr,#0x0f lr存储着上一个处理器模式的cpsr值,lr=lr & 0x0f取出用于判断发生中断前是用户态还是核心态的信息,该值用于下面跳转表的索引。28. movr0,sp 将irq模式下的sp保存到r0,作为参数传递给即将调用的_irq_usr或_irq_svc29. ldrlr,pc,lr,lsl#2pc指向当前执行指令地址加8,即跳转表的基址。lr作为索引,由于是4字节对齐,所以lr=lr2.30. movs
10、pc,lr branch to handlerinSVC mode31. 当mov指令后加“s”且目标寄存器为pc时,当前模式下的spsr会被复制到cpsr,从而完成模式切换(从irq模式切换到svc模式)并且跳转到pc指向的指令继续执行32. ENDPROC(vector_irq)33.34. .long_irq_usr 0(USR_26 / USR_32)35. .long_irq_invalid 1(FIQ_26 / FIQ_32)36. .long_irq_invalid 2(IRQ_26 / IRQ_32)37. .long_irq_svc 3(SVC_26 / SVC_32)38.
11、 .long_irq_invalid 439. .long_irq_invalid 540. .long_irq_invalid 641. .long_irq_invalid 742. .long_irq_invalid 843. .long_irq_invalid 944. .long_irq_invalid a45. .long_irq_invalid b46. .long_irq_invalid c47. .long_irq_invalid d48. .long_irq_invalid e49. .long_irq_invalid f_irq_usr如果发生中断前处于用户态则进入_irq
12、_usr,其定义如下(arch/arm/kernel/entry_armv.S):1. .align52. _irq_usr:3. usr_entry 保存中断上下文,稍后分析4. kuser_cmpxchg_check5. #ifdef CONFIG_TRACE_IRQFLAGS6. bltrace_hardirqs_off7. #endif8. get_thread_info tsk 获取当前进程的进程描述符中的成员变量thread_info的地址,并将该地址保存到寄存器tsk(r9)(在entry-header.S中定义)9. #ifdef CONFIG_PREEMPT 如果定义了抢占,
13、增加抢占数值10. ldrr8,tsk,#TI_PREEMPT 获取preempt计数器值11. addr7,r8,#1 preempt加1,标识禁止抢占12. strr7,tsk,#TI_PREEMPT将加1后的结果写入进程内核栈的变量中13. #endif14. irq_handler 调用中断处理程序,稍后分析15. #ifdef CONFIG_PREEMPT16. ldrr0,tsk,#TI_PREEMPT获取preempt计数器值17. strr8,tsk,#TI_PREEMPT将preempt恢复到中断前的值18. teqr0,r7 比较中断前后preempt是否相等19. str
14、ner0,r0,-r0如果不等,则产生异常(向地址0写入数据)?20. #endif21. #ifdef CONFIG_TRACE_IRQFLAGS22. bltrace_hardirqs_on23. #endif24. movwhy,#0 r8=025. bret_to_user 中断处理完成,恢复中断上下文并返回中断产生的位置,稍后分析26. UNWIND(.fnend)27. ENDPROC(_irq_usr)宏定义usr_entry(保护上下文到栈)上面代码中的usr_entry是一个宏定义,主要用于保护上下文到栈中:1. .macrousr_entry2. UNWIND(.fnsta
15、rt)3. UNWIND(.cantunwind) dont unwind the user space4. subsp,sp,#S_FRAME_SIZE ATPCS中,堆栈被定义为递减式满堆栈,所以首先让sp向下移动#S_FRAME_SIZE(pt_regs结构体size),准备向栈中存放数据。此处的sp是svc模式下的栈指针。5. stmibsp,r1-r126.7. ldmiar0,r1-r38. addr0,sp,#S_PC hereforinterlock avoidance9. movr4,#-110.11. strr1,sp save therealr0 copied12. fr
16、om the exception stack13.14. 15. We are now ready to fillinthe remaining blanks on the stack:16. 17. r2-lr_,already fixed upforcorrect return/restart18. r3-spsr_19. r4-orig_r0(see pt_regs definitioninptrace.h)20. 21. Also,separately save sp_usrandlr_usr22. 23. stmiar0,r2-r424. stmdbr0,sp,lr 将user模式下
17、的sp和lr保存到svc模式的栈中25.26. 27. Enable the alignment trapwhileinkernel mode28. 29. alignment_trap r030.31. 32. Clear FP to mark the first stack frame33. 34. zero_fp35. .endm上面的这段代码主要是在填充结构体pt_regs ,在include/asm/ptrace.h中定义:1. structpt_regs 2. long uregs18;3. ;4.5. #define ARM_cpsruregs166. #define ARM_p
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ARM Linux中断源码分析2中断处理流程 Linux 中断 源码 分析 处理 流程
限制150内