ARMLinux中断源码分析2中断处理流程.docx

上传人:小飞机 文档编号:4882987 上传时间:2023-05-21 格式:DOCX 页数:50 大小:226.98KB
返回 下载 相关 举报
ARMLinux中断源码分析2中断处理流程.docx_第1页
第1页 / 共50页
ARMLinux中断源码分析2中断处理流程.docx_第2页
第2页 / 共50页
ARMLinux中断源码分析2中断处理流程.docx_第3页
第3页 / 共50页
ARMLinux中断源码分析2中断处理流程.docx_第4页
第4页 / 共50页
ARMLinux中断源码分析2中断处理流程.docx_第5页
第5页 / 共50页
亲,该文档总共50页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《ARMLinux中断源码分析2中断处理流程.docx》由会员分享,可在线阅读,更多相关《ARMLinux中断源码分析2中断处理流程.docx(50页珍藏版)》请在三一办公上搜索。

1、ARM Linux中断源码分析(2 )中断处理流程ARM支持7类异常中断,所以中断向量表设8个条目,每个条目4字 节,共32字节。异常名称中断向量异常中断模式优先级复位0x0特权模式1未定义的指令0x4未定义指令中止模式6软件中断0x8特权模式6指令预取中止0x0c中止模式5数据访问中止0x10中止模式2保留0x14外部中断请求IRQ0x18IRQ模式4快速中断请求FIQ0x1cFIQ模式3回顾第一节所讲的内容,当一个异常或中断发生时,处理器会将PC设置为特定地址,从而跳转到已经初始化好的异常向量表。因此,要理清中断处理流程,先从异常向量表开始。对于ARM Linux而言,异常向量表和异常处理

2、程序都存在arch/arm/kernel/entry_armv.S 汇编文件中。vector异常向量表点击(此处)折叠或打开1 .globl_.vectors_start vectors start: 2.3swi3.SYS_ERROR04.bvector_und + stubs_offset5ldr5.pc, .LCvswi + stubs_offset6.bvector_pabt + stubs_offset7.bvector_dabt + stubs_offset8.bvector_addrexcptn + stubs_offset9.bctor_irqvector_irq + stub

3、s_offset 中断入口,veb10.11.vector_fiq + stubs_offset12. globl-L vectors end:13._vectors_endvector_irq+stubs_offset为中断的入口点,此处之所以要加上stubs_offset,是为了实现位置无关编程。首先分析一下.equ stubs_offset, _vectors_start + 0x200 - _stubs_start在第3节中已经提到,内核启动时会将异常向量表拷贝到0xFFFF_0000,将异常向量处理程序的stub拷贝到0xFFFF_0200。图5-1描述了异常向量表和异常处理程序搬移

4、前后的内存布局。搬移后vectors itart X图5-1异常向量表和异常处理程序搬移前后对比当汇编器看到B指令后会把要跳转的标签转化为相对于当前PC 的偏移量(32M)写入指令码。由于内核启动时中断向量表和 stubs都发生了代码搬移,所以如果中断向量表中仍然写成b vector_irq,那么实际执行的时候就无法跳转到搬移后的 vector_irq处,因为指令码里写的是原来的偏移量,所以需要把指 令码中的偏移量写成搬移后的。设搬移后的偏移量为offset,如图 5-1所示,offset = L1+L2=0x200 - (irq_PC_X - vectors_start_X) + (vect

5、or_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贝U offset = vector_irq + stubs_offset - irq_

6、PC,所以中断 入口点为 “bvector_irq + stubs_offset”,其中减去irq_PC是由汇编器在编译时完成的。vector_irq处理函数在分析vector_irq处理函数之前,先了解一下当一个异常或中 断导致处理器模式改变时,ARM处理器内核的处理流程如下图所 示:R14_tior_made return link= CPSRCPSR4;0J = exception rode numberCPSR5 m 0卜 Execute in ASM state */if = Res.et or FIQ tlienCPSRL& * 1/* Oisable fast interrupt

7、s/* else CPSS6 is unthariged */CPSR7J = 1h Msabk fiorm-al interrupts */If cexception_niode != UNDEF or 5WI tlienCPSRSJ,1h sable Imprecise aborts W6 otil/) 7/A else CPSRS is unchanged +/CPSR93 = CPlregLEEbit/* Endianness on exception entryPC = exception vector address中断刚发生时,处理器处于irq模式。在stubs_start和st

8、ubs_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.6.sublr, lr, #4 在中断发生时,lr指向最后.if 4执行的指令地址加上8。只有在当前指令执行完毕后,才进入中断 处理,所以返回地址应指向下一条指令,即(lr-4)处。7.endif9.10. Save r0,lr

9、_ (parent PC)and spsr_11. (parentCPSR)13.stmiasp, r0, lr保存r0,lr到irq模式下的栈中14.mrslr, spsr15.strlr, sp, #8保存spsr到irq模式下的栈中16.17.18. Preparefor SVC32 mode. IRQsremain disabled.19.20.mrsr0, cpsr21.eorr0, r0, #( IRQ_MODE八 SVC_MODE) 设12.但未切换置成SVC模式,22.msrspsr_cxsf, r0 保存到spsr_irq 中23.24.25.branch table mus

10、t immediately follow thicode26.27.andlr, lr, #0x0f lr存储着上一个处理器模式的cpsr值,lr = lr & 0x0f取出用于判断发生中断前是用户 态还是核心态的信息,该值用于下面跳转表的索引。28.29.movr0, sp 将irq模式下的sp保存到r0,作为参数传递给即将调用的irq_usr或_irq_svcldrlr, pc, lr, lsl #2 pc 指向当前执行指令地址加8,即跳转表的基址。lr作为索引,由于是4字节对 齐,所以 lr = lr 2.30.31.movspc, lr branch to handler in SVC

11、 mode当mov指令后加“s”且 目标寄存器为pc时,当前模式下的spsr会被复制到cpsr,从而 完成模式切换(从irq模式切换到svc模式)并且跳转到pc指向 的指令继续执行32.33.34.35.36.ENDPROC(vector_irq).longirq_usr0 (USR_26 / USR_32).longirq_invalid 1 (FIQ_26 / FIQ_32).longirq_invalid 2 (IRQ_26 / IRQ_32)irq_svc3 (SVC_26 / SVC_32)38.longirq_invalid 439.longirq_invalid 540.long

12、irq_invalid 641.longirq_invalid 742.longirq_invalid 843.longirq_invalid 944.longirq_invalid a45.longirq_invalid b46.longirq_invalid c47.long_irq_invalid d49.longirq_invaliirq_invali_irq_usr 如果发生中断前处于用户态则进入irq_usr,其定义如下(arch/arm/kernel/entry_armv.S):1.align2.irq_usr:3.usr_entry 保存中断上下文,稍后分析4.kuser_cm

13、pxchg_check5.6.bltrace_hardirqs_off7.#endif#ifdef CONFIG_TRACE_IRQFLAGS8.9.10.ldrr8, tsk, #TI_PREEMPT获取preempt计数器值get_thread_info tsk 获取当前进程的进程描述符中的成员变量thread_info的地址,并将该地址保存到寄存器tsk(r 9)(在 entry-header.S 中定义) #ifdef CONFIG_PREEMPT 如果定义了抢占,增加抢占数值11.addr7, r8, #1reempt加1,标识禁止抢占12.strr7, tsk, #TI_PREEM

14、PT 将加 1 后的结果写入进程内核栈的变量中13 #endif ID.14.irq_handler 调用中断处理程序,稍后分析15. #ifdef CONFIG_PREEMPT16.ldrr0,tsk, #TI_PREEMPT 获取 preempt计数器值17.strr8,tsk, #TI_PREEMPT 将 preempt 恢复到中断前的值18.teqr0,r7 比较中断前后preempt是否相等19.strner0,r0, -r0 如果不等,则产生异常(向地址0写入数据)?20. #endif21 #ifdefCONFIG_TRACE_IRQFLAGS22.bltrace_hardirq

15、s_on23 #endif 3.24.movwhy, #0 r8=025.ret_to_user 中断处理完成,恢复中断上下文并返回中断产生的位置,稍后分析26.UNWIND(.fnend27. ENDPROC(irq_usr)宏定义usr_entry(保护上下文到栈)上面代码中的usr_entry是一个宏定义,主要用于保护上下文到栈中:1.macrousr_entry2.UNWIND(.fnstart3.UNWIND(.cantunwind dont unwind the use4.spacesubsp,sp, #S_FRAME_SIZE ATPCS 中,堆栈被定义为递减式满堆栈,所以首先让

16、sp向下移动#S_FRAME_SIZE(pt_regs 结构体 size),准备向栈中存放数据。此处的sp是sv5.6.stmibsp,r1 - r127.ldmiar0,r1 - r38.addr0,sp, #S_PCefor interlockavoidance9.movr4,#-110.11.strr1,spealr0 copiedc模式下的栈指针。 save the r12. from the exception stack13.14.15.ks on16. We arethe stack:now ready to fill in the remaining blan17. r2 -l

17、r_, already fixed up for correct return/restart18. r3 -spsr_19. r4 -orig_r0 (see pt_regs definition in ptrace.h)20.21. Also,separately save sp_usr and lr_usr22.23.stmiar0,r2 - r424.stmdbr0, sp, lr厂将user模式下的sp和lr保存到svc模式的栈中25.26.27. Enablethe alignment trap while in kernel mode28.29.alignment_trap r0

18、30.31.32. Clear FP to mark the first stack frame33.34.zero_fp35.endm上面的这段代码主要是在填充结构体pt_regs,在include/asm/ptrace.h 中定义:i.structpt_regs 2.long uregs18;3.;4.5.#define6.#define7.#define8.#define9.#define10 #define11 #define12 #define13 #defineARM_cpsruregs16ARM_pcuregs15ARM_lruregs14ARM_spuregs13ARM_ipu

19、regs12ARM_fpuregs11ARM_r10uregs10ARM_r9uregs9ARM_r8uregs8#define ARM_r7uregs7#define ARM_r6uregs6#define ARM_r5uregs5#define ARM_r4uregs4#define ARM_r3uregs3#define ARM_r2uregs2#define ARM_r1uregs1#define ARM_r0uregs0#define ARM_ORIG_r0uregs1714.15.16.17.18.19.20.21.22.usr_entry宏填充pt_regs结构体的过程如图5-2

20、所示,先将 r1r12保存到ARM_r1ARM_ip (绿色部分),然后将产生中断时 的r0寄存器内容保存到ARM_r0 (蓝色部分),接下来将产生中断 时的下一条指令地址lr_irq、spsr_irq和r4保存到ARM_pc、 ARM_cpsr和ARM_ORIG_r0 (红色部分),最后将用户模式下的sp和 lr保存到ARM_sp 和ARM_lr 中。i.2.3.4.5.6.7.173 (发生中断时的卬51内容jr2(中断六的F -条指令地址)irq模式下的栈内容呼 l()Veg+ b IQA r ch i H4UR i Xtirq_svcARM_IrARM_&PARM ipARM_fpAR

21、M.rlOARM_r9ARM_r8ARM_r7ARM_r6ARM_r5ARM_r4ARM_r3ARM_r2ARMrlrOOf图5-2 usr_entry宏填充pt_regs结构体一 &p + 电 PCsub平FRAME 1strnib冲(rl rl2)园IdmiarO. (rl -或.add也 sp,再S_PCmovr% #-lstrspstmia。(r2 -r4.stmdb一 sprO1射如果发生中断前处于核心态则进入irq_svc,其定义如下(arch/arm/kernel/entry_armv.S):.alignirq_svc:svc_entry 保存中断上下文#ifdef CONFIG

22、_TRACE_IRQFLAGS#endifbltrace_hardirqs_off#ifdef CONFIG_PREEMPT9.get_thread_info tsk10.ldrr8, tsk, #TI_PREEMP11.Tadd获取preempt计数器值r7, r8, #1reempt加1,标识禁止抢占12.strr7, tsk,#TI_PREEMPT 将加1后的结15.16. #ifdefCONFIGPREEMPT17.strr8, tsk, #TI_PREEMP18.Tldr恢复中断前的preempt计数器r0, tsk,#TI_FLAGS果写入进程内核栈的变量中13 #endif ID

23、.14.irq_handler 调用中断处理程序,稍后分析获取flags19.teqr8,#判断preempt是否等于020.movner0,#如果preempt不等于0, r0=021.tstr0, #_TIF.NEEDRESCHED 将 r0 及#_TIF_NEED_RESCHED 做“及操作”22.blnesvc_preempt 如果不等于0,说明发生内核抢占,需要重新调度。23 #endif .24.25.ldrr0, sp, #S_PSR26.s are alreadydisabledmsrspsr_cxsf, r027. #ifdef CONFIG_TRACE_IRQFLAGS28

24、.tstr0, #PSR_I_BIT29.bleqtrace_hardirqs_on#endif 30.31.svcexitr4恢复中断上下文,稍后分析。32 UNWIND(.fnend .33. ENDPROC(irq_svc)宏定义svc_entry(保护中断上下文到栈)其中svc_entry是一个宏定义,主要用于保护中断上下文到栈中。svc_entry主要是在当前堆栈上分配一个pt_regs结构,把r0-r15以及cpsr等保存到这个结构中,在进入irq_handler时,sp指向pt_regs 底端:svc_entry, stack_hole=02.UNWIND(.fnstart3 U

25、NWIND(.save r0 .-pc)4sub.sp, sp, #(S_FRAME_SIZE + stack_hole)5. SPFIX(tstsp, #4)6 SPFIX(bicnesp, sp, #4)7stmibsp, r1 - r128.ldmia9.r0,r1 - r3add10.r5, sp, #S_SP here for interlockavoidance11mov11.r4, #-1 eal r0 copied15. from the exception stack16.17movr1, lr.18.19.12.addr0, sp, #(S_FRAME_SIZE + sta

26、ck_hol13.14.e)SPFIX(addnestrr1, spr0, r0, #4) save the rARM Linux中断源码分析(2)中断处理流程20. We are now ready to fill in the remaining blanks onthe stack:21.22. r0 - sp_svc23. r1 - lr_svc24. r2 - lr_, already fixed up for correct return/restart25. r3 - spsr_26. r4 - orig_r0 (see pt_regs definition in ptrace.

27、h)27.28.stmiar5,r0 - r429.endmsvc_entry宏填充pt_regs结构体的过程如图5-2所示,先将r1 r12保存到ARM_r1ARM_ip (绿色部分),然后将产生中断时的r0 寄存器内容保存到ARM_r0 (蓝色部分),由于是在svc模式下产生 的中断,所以最后将 sp_svc、lr_svc、lr_irq、spsr_irq 和 r4 保 存到 ARM_sp、ARM_lr、ARM_pc、ARM_cpsr 和 ARM_ORIG_r0 (红色部 分)。ARMr3 (宏*不断时西中*丙猝 淳中断应的下一藐布感地址ARM_fpARM_r7AftM_r6ARM_r4AR

28、M_r3rl(rO)iq模式卜的栈内容wluvt? blu尺.chinaun i x. ?ie tARMr2ARhOlsub5比 sp, ff(5_FRAME_5IZE f st3ck_hstmibsp. (rl -13宙 d*l 蝌。 衅1Stsl-dl:Titj, ri - r ijJr5. Sp,帕_SPmov叫#-laddrOF $pF #(S_FRAIV1F_SIZE + stack_hstrL spmovrijrstmiasp + its. 5P叩图5-3 svc_entry宏填充pt_regs结构体上述的中断上下文保存过程共涉及了3种栈指针,分别是:用户 空间栈指针sp_usr,

29、内核空间栈指针sp_svc和irq模式下的栈栈 指针sp_irq。sp_usr指向在setup_arg_pages函数中创建的用户空 间栈。sp_svc指向在alloc_thread_info函数中创建的内核空间 栈。sp_irq在cpu_init函数中被赋值,指向全局变量 stacks.irq0。附录1, arm体系下pt_regs结构struct pt_regs long uregs18;uregs0 - uregs17分别对应,r0 - r15, cpsr, ORIG_r0附录1,irq中断时堆栈的变化spsrlr,中断返回地址,修正后的r0-进入irq_svc之前,sp的值,也是r0的

30、值pt_regs-进入 svc_entry 后,sp 的值irq_handler(中断处理程序)保存中断上下文后则进入中断处理程序irq_handler,定义在 arch/arm/kernel/entry_armv.S 文件中:1.2.3.4.macroirq_handlerget_irqnr_preamble r5, lr1:get_irqnr_and_base r0,r6,r5, lr 获取中断号,存到r0中,稍后分析movner1, sp 如果中断号不等于0,将r1=sp,即pt_regs结构体首地址5.6.7.8.9.10.11. routine called with r0 = ir

31、q number, r1 = s truct pt_regs *adrnelr, 1b 如果r0(中断号)不等于0, lr(返回地址)等于标号1处,即get_irqnr_and_base r0,r6, r5, lr的那行,即循环处理所有的中断。bneasm_do_IRQ 进入中断处理,稍后分析。.endmget_irqnr_and_base用于判断当前发生的中断号(及CPU紧密 相关),此处不再分析。如果获取的中断号不等于0,则将中断号 存入r0寄存器作为第一个参数,pt_regs结构体地址存入r1寄存 器作为第二个参数,跳转到c语言函数asm_do_IRQ做进一步处理。 为了不让大家在汇编语

32、言和C语言之间来回切换,还是先把最后一 点汇编语言代码(中断返回汇编代码)分析了再去分析asm_do_IRQ 吧。回看irq_usr和irq_svc标号处的代码,在完成了 irq_handler中断处理函数后,要完成从中断异常处理程序返回到 中断点的工作。如果中断产生于用户空间,则调用ret_to_user来恢复中断现场并 返回用户空间继续运行:1.arch/arm/kernel/entry_armv.S2.ENTRY(ret_to_user)3.ret_slow_syscall:4.disable_irq disable interrupts, 此处不明白,disable_irq应该接受ir

33、q中断号作为参数,来禁止指定的irq号中断线。但是此处调用disable_irq之前并没有将irq中断号存入r0寄存器这是为什么?5.ldrr1,tsk, #TI_FLAGS 获取 thread_info-flags6.tstr1,#_TIF_WORK_MASK 判断是否有待处理的 work7.bneworkpending 如果有,则进入 work_pending进一步处理,主要是完成用户进程抢占相关处理。8.场,返回用户空间。no_work_pending: 如果没有work待处理,则准备恢复中断现9.serreturn */* perform architecture specific a

34、ctions before u10.arch_ret_to_user r1, lr 调用体系结构相关的代码11.12.15.16.macrorestore_user_regs, fast0, offse17.ldrr1, sp, #offsetS_PSRrestore_user_regs fast = 0, offset = 0 调用restore_user_regs13 ENDPROC(ret_to_user)14.以下是恢复中断现场寄存器的宏,就是将发生中断时保存在内核空 间堆栈上的寄存器还原,可以对照图5-2所示的内核空间堆栈保存 的内容来理解下面代码:从内核栈中获取发生中断时的cpsr

35、值18.ldrlr, sp, #offsetS_PC!从内核栈中获取发生中断时的下一条指令地址19.msrspsr_cxsf, r1将r1保存到spsr_svc20. #if defined(CONFIG_CPU_32v6K)21.clrexclear the exclusive monitor22. #elif defined (CONFIG_CPU_V6)23.strexr1,r2, sp clear the exclusive monitor24 #endif25.26.27.28.29.30.31.32.1.2.3.4.5.iffastldmdbsp,(r1 - Ir厂 get cal

36、ling r1 - Ir.elseldmdbsp, (r0 - lr厂存在,所以将内核栈保存的内容恢复到用户空间的r0lr寄存器.endifaddsp, sp, #S_FRAME_SIZE - S_PCmovs pc, lr将发生中断时的下一条指令地址存入pc,从而返回中断点继续执行,并且将发生中断时的c psr内容恢复到cpsr寄存器中(开启中断)。.endmsvc_exit如果中断产生于内核空间,则调用svc_exit来恢复中断现场:arch/arm/kernel/ entry-header.S.macrosvc_exit, rpsrmsrspsr_cxsf, rpsr#if define

37、d(CONFIG_CPU_32v6K)clrex clear the exclusive monitor6.Idmiasp,r0 - pc. load r0 - pc, cpsr,7#elif defined(CONFIGCPUV6)7.8.Idrr0,sp9.strexr1,r2, sp clear the exclusive monitor10.Idmibsp,(r1 - pc. load r1 - pc, cpsr11.#else12.Idmiasp,r0 - pc八返回内核空间时,恢复中断现场比较简单,就是将r0-pc以及cpsr恢复即可,同时中断也被开启。13 #endif3.14.

38、endmasm_do_IRQ 函数ok,分析完所有及中断相关的汇编语言代码后,下面开始分析C语言代码:在 arch/arm/kernel/irq.c 文件中找到 asm_do_IRQ 函数定义:1 asmlinkage void _exception asm_do_IRQ(unsigned int ir .q, struct pt_regs *regs)2.3./*保存新的寄存器集合指针到全局cpu变量,方便后续处理程序访问寄存器集合。*/4.struct pt_regs *old_regs = set_irq_regs(reg5.6.irq_enter();7.s);8.9.s.Rather/* Some hardware gives randomly wrong interrupt10.11.12.if(unlikely(irq = NR_IRQS) /判断中断号13.if (printk_ratelimit()* than crashing, do something sensible.*/14.printk(KERN_WARNING Bad IRQ%unirq);15.ack_bad_irq(irq);16.17.else 18.19.20./*AT91 specific

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

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号