linux-2.6.26内核中ARM中断实现详解(2)
三、中断处理过程
这一节将以S3C2410为例,描述linux-2.6.26内核中,从中断开始,中断是如何一步一步执行到我们注册函数的。
3.1 中断向量表 archarmkernelentry-armv.S
__vectors_STart:
swi SYS_ERROR0
b vector_und + stubs_offset
ldr pc, .LCvswi + stubs_offset
b vector_pa^ + stubs_offset
b vector_da^ + stubs_offset
b vector_addrexcptn + stubs_offset
b vector_IRq + stubs_offset
b vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
中断发生后,跳转到b vector_irq + stubs_offset的位置执行。注意现在的向量表的初始位置是0xffff0000。
3.2 中断跳转的入口位置 archarmkernelentry-armv.S
.globl __stubs_start
__stubs_start:
/*
* Interrupt dispatcher
*/
vector_stub irq, IRQ_MODE, 4 @IRQ_MODE在includeasmptrace.h中定义:0x12
.lONg __irq_usr @ 0 (USR_26 / USR_32)
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
.long __irq_svc @ 3 (SVC_26 / SVC_32)
.long __irq_invalid @ 4
.long __irq_invalid @ 5
.long __irq_invalid @ 6
.long __irq_invalid @ 7
.long __irq_invalid @ 8
.long __irq_invalid @ 9
.long __irq_invalid @ a
.long __irq_invalid @ b
.long __irq_invalid @ c
.long __irq_invalid @ d
.long __irq_invalid @ e
.long __irq_invalid @ f
上面代码中vector_stub宏的定义为:
.macro vector_stub, name, mode, correcTIon=0
.align 5
vector_nAME:
.if correction
sub lr, lr, #correction
.endif
@
@ Save r0, lr_
@ (parent CPSR)
@
stmia sp, {r0, lr} @ save r0, lr
mrs lr, spsr
str lr, [sp, #8] @ save spsr
@
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0, cpsr
eor r0, r0, #(mode ^ SVC_MODE)
msr spsr_cxsf, r0 @为后面进入svc模式做准备
@
@ the branch table must immediately follow this code
@
and lr, lr, #0x0f @进入中断前的mode的后4位
@#define USR_MODE 0x00000010
@#define FIQ_MODE 0x00000011
@#define IRQ_MODE 0x00000012
@#define SVC_MODE 0x00000013
@#define ABT_MODE 0x00000017
@#define UND_MODE 0x0000001b
@#define SYSTEM_MODE 0x0000001f
mov r0, sp
ldr lr, [pc, lr, lsl #2] @如果进入中断前是usr,则取出PC+4*0的内容,即__irq_usr @如果进入中断前是svc,则取出PC+4*3的内容,即__irq_svc
movs pc, lr @ 当指令的目标寄存器是PC,且指令以S结束,则它会把@ spsr的值恢复给cpsr branch to handler in SVC mode
.endm
.globl __stubs_start
__stubs_start:
/*
* Interrupt dispatcher
*/
vector_stub irq, IRQ_MODE, 4
.long __irq_usr @ 0 (USR_26 / USR_32)
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
.long __irq_svc @ 3 (SVC_26 / SVC_32)
用“irq, IRQ_MODE, 4”代替宏vector_stub中的“name, mode, correction”,找到了我们中断处理的入口位置为vector_irq(宏里面的vector_name)。
从上面代码中的注释可以看出,根据进入中断前的工作模式不同,程序下一步将跳转到_irq_usr 、或__irq_svc等位置。我们先选择__irq_usr作为下一步跟踪的目标。
3.3 __irq_usr的实现 archarmkernelentry-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的值在archarmkernelasm-offsets.c
@ 中定义 DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));实
实现 详解 中断 ARM 内核 linux-2 6 26 相关文章:
- 3DES算法的FPGA高速实现(06-21)
- 基于DSP的Max-Log-MAP算法实现与优化(05-27)
- DSP中DMA操作的无阻塞请求实现(06-18)
- 二维DCT编码的DSP实现与优化(09-08)
- 基于DSP处理器上并行实现ATR算法(01-29)
- 基于DSP的H.324终端设计(05-27)