ARM Linux中断机制分析
@ We are now ready to fill in the remaining blanks on the stack: @ @ r4 - lr_ @ r5 - spsr_ @ r6 - orig_r0 (see pt_regs definition in ptrace.h) @ @ Also, separately save sp_usr and lr_usr @ stmia r0, {r4 - r6}//stmia将svc模式下的寄存器r4-r6保存到ARM_pc,ARM_cpsr和 ARM_ORIG_r0,显然ARM_ORIG_r0保存了-1(r6)这个常量 ARM( stmdb r0, {sp, lr}^ )//stmdb指令的^标志表示存储发生中断的模式下的sp,lr寄存器 到ARM_sp和ARM_lr中。 THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) @ Enable the alignment trap while in kernel mode alignment_trap r0//alignment_trap在配置CONFIG_ALIGNMENT_TRAP时有效,如果开启了该选 //项,中断处理中将支持对齐跟踪 @ Clear FP to mark the first stack frame zero_fp//zero_fp用来设置fp栈帧寄存器为0 #ifdef CONFIG_IRQSOFF_TRACER bl trace_hardirqs_off #endif .endm@usr_entry宏定义结束 |
以上的指令的作用可以总结如下,其中将普通寄存器r1到r12保存到ARM_r1- ARM_r12,这相当于把发生中断时的寄存器r1-r12进行了保存。接下来保存中断发生时的r0,lr_irq和spsr_irq保存到r1-r3,r4赋值为-1,它们接下来将被使用。接下来保存r0到ARM_r0,lr_irq,spsr_irq和-1到ARM_pc ARM_cpsr ARM_ORIG_R0,注意到stmdb指令中的"^",它保存sp_usr和lr_usr分别到ARM_sp和ARM_lr,显然这里将所有中断发生时的寄存器都进行了保存。
图3 保存中断堆栈
2.2.3 get_thread_info
get_thread_info宏用来根据当前的sp值,通过lsr和lsl分别右移左移13位,相当于对sp向下圆整到8K对齐。这里也就是thread_info所在的地址。
arch/arm/kernel/entry-header.S .macroget_thread_info, rd mov \rd, sp, lsr #13 mov \rd, \rd, lsl #13 .endm |
linux/arch/arm/kernel/entry-armv.S /* * Interrupt handling. Preserves r7, r8, r9 */ .macroirq_handler #ifdef CONFIG_MULTI_IRQ_HANDLER ldr r5, =handle_arch_irq mov r0, sp ldr r5, [r5] adr lr, BSYM(9997f) teq r5, #0 movne pc, r5 #endif arch_irq_handler_default 9997: .endm |
linux/arch/arm/kernel/entry-armv.S
/*
* Interrupt handling. Preserves r7, r8, r9
*/
.macroirq_handler
#ifdefCONFIG_MULTI_IRQ_HANDLER
ldr r5,=handle_arch_irq
mov r0,sp
ldr r5,[r5]
adr lr,BSYM(9997f)
teq r5,#0
movne pc,r5
#endif
arch_irq_handler_default
9997:
.endm
2.2.5 arch_irq_handler_default
irq_handler是真正的IRQ中断处理入口,在中断处理中需要预留r7,r8和r9寄存器。它们被用来处理内核抢占。在没有配置MULTI_IRQ_HANDLER 的情况下,irq_handler的逻辑很简单,就是简单的调用arch_irq_handler_default。
如果配置了该选项,平台代码可以修改全局变量:handle_arch_irq,这里只讨论默认实现.
arch/arm/include/asm/entry_macro_multi.S /* * Interrupt handling. Preserves r7, r8, r9 */ .macroarch_irq_handler_default //get_irqnr_preamble用来获取中断状态寄存器基地址 get_irqnr_preamble r5, lr//将中断控制器的状态寄存器的地址存储到r5 1: get_irqnr_and_base r0, r6, r5, lr//判断中断号,通过r0返回 movne r1, sp//如果还存在中断,就将sp作为第二个参数,调用asm_do_IRQ。sp目前指向pt_regs @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ adrne lr, BSYM(1b)//这里将lr设置为get_irqnr_and_base的第二条指令,因为第二次循环时,不必执行其第一条指令(加载寄存器基址) bne asm_do_IRQ //将中断号、pt_regs(中断前的寄存器现场)传递给asm_do_IRQ。asm_do_IRQ返回时, //会返回到get_irqnr_and_base处,直到所有中断都已经处理完毕才退出循环。 #ifdef CONFIG_SMP//针对SMP |
ARMLinux中断机 相关文章:
- ARM Linux中断机制之中断的初始化(11-10)
- ARM Linux中断机制之中断的申请(11-10)
- ARM Linux中断机制之中断处理(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)