linux2.6.26内核中ARM中断实现详解
用“irq, IRQ_MODE, 4”代替宏vector_stub中的“name, mode, correction”,找到了我们中断处理的入口位置为vector_irq(宏里面的vector_\name)。
从上面代码中的注释可以看出,根据进入中断前的工作模式不同,程序下一步将跳转到_irq_usr 、或__irq_svc等位置。我们先选择__irq_usr作为下一步跟踪的目标。
3.3 __irq_usr的实现 arch\arm\kernel\entry-armv.S
__irq_usr:
usr_entry @后面有解释
kuser_cmpxchg_check
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
get_thread_info tsk @获取当前进程的进程描述符中的成员变量thread_info的地址,并将该地址保存到寄存器tsk等于r9(在entry-header.S中定义)
#ifdef CONFIG_PREEMPT//如果定义了抢占,增加抢占数值
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
add r7, r8, #1 @ increment it
str r7, [tsk, #TI_PREEMPT]
#endif
irq_handler @中断处理,我们最关心的地方,3.4节有实现过程。
#ifdef CONFIG_PREEMPT
ldr r0, [tsk, #TI_PREEMPT]
str r8, [tsk, #TI_PREEMPT]
teq r0, r7
strne r0, [r0, -r0]
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
mov why, #0
b ret_to_user @中断处理完成,返回中断产生的位置,3.7节有实现过程
上面代码中的usr_entry是一个宏,主要实现了将usr模式下的寄存器、中断返回地址保存到堆栈中。
.macro usr_entry
sub sp, sp, #S_FRAME_SIZE @ S_FRAME_SIZE的值在arch\arm\kernel\asm-offsets.c
@ 中定义 DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));实际上等于72
stmib sp, {r1 - r12}
ldmia r0, {r1 - r3}
add r0, sp, #S_PC @ here for interlock avoidance
mov r4, #-1 @ "" "" "" ""
str r1, [sp] @ save the "real" r0 copied
@ from the exception stack
@
@ We are now ready to fill in the remaining blanks on the stack:
@
@ r2 - lr_
@ r3 - spsr_
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
@
@ Also, separately save sp_usr and lr_usr
@
stmia r0, {r2 - r4}
stmdb r0, {sp, lr}^
@
@ Enable the alignment trap while in kernel mode
@
alignment_trap r0
@
@ Clear FP to mark the first stack frame
@
zero_fp
.endm
上面的这段代码主要在填充结构体pt_regs ,这里提到的struct pt_regs,在include/asm/ptrace.h中定义。此时sp指向struct pt_regs。
struct pt_regs {
long uregs[18];
};
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
#define ARM_sp uregs[13]
#define ARM_ip uregs[12]
#define ARM_fp uregs[11]
#define ARM_r10 uregs[10]
#define ARM_r9 uregs[9]
#define ARM_r8 uregs[8]
#define ARM_r7 uregs[7]
#define ARM_r6 uregs[6]
#define ARM_r5 uregs[5]
#define ARM_r4 uregs[4]
#define ARM_r3 uregs[3]
#define ARM_r2 uregs[2]
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
3.4 irq_handler的实现过程,arch\arm\kernel\entry-armv.S
.macro irq_handler
get_irqnr_preamble r5, lr
@在include/asm/arch-s3c2410/entry-macro.s中定义了宏get_irqnr_preamble为空操作,什么都不做
1: get_irqnr_and_base r0, r6, r5, lr @判断中断号,通过R0返回,3.5节有实现过程
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, 1b
bne asm_do_IRQ @进入中断处理。
……
.endm
3.5 get_irqnr_and_base中断号判断过程,include/asm/arch-s3c2410/entry-macro.s
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
mov \base, #S3C24XX_VA_IRQ
@@ try the interrupt offset register, since it is there
ldr \irqstat, [ \base, #INTPND ]
teq \irqstat, #0
beq 1002f
ldr \irqnr, [ \base, #INTOFFSET ] @通过判断INTOFFSET寄存器得到中断位置
mov \tmp, #1
tst \irqstat, \tmp, lsl \irqnr
bne 1001f
@@ the number specified is not a valid irq, so try
@@ and work it out for ourselves
mov \irqnr, #0 @@ start here
@@ work out which irq (if any) we got
movs \tmp, \irqstat, lsl#16
addeq \irqnr, \irqnr, #16
moveq \irqstat, \irqstat, lsr#16
tst \irqstat, #0xff
addeq \irqnr, \irqnr, #8
moveq \irqstat, \irqstat, lsr#8
tst \irqstat, #0xf
addeq \irqnr, \irqnr, #4
moveq \irqstat, \irqstat, lsr#4
tst \irqstat, #0x3
addeq \irqnr, \irqnr, #2
moveq \irqstat, \irqstat, lsr#2
tst \irqstat, #0x1
addeq \irqnr, \irqnr, #1
@@ we have the value
1001:
linux2 6 26内核ARM中断实 相关文章:
- Linux2.6.36移植到飞凌S3C6410开发板 步骤(11-23)
- Linux2.6.22内核移植(11-21)
- 基于3c2410的linux2.6.22移植(3)(11-20)
- 基于3c2410的linux2.6.22移植(2)(11-20)
- 基于3c2410的linux2.6.22移植(6)(11-20)
- 基于3c2410的linux2.6.22移植(5)(11-20)