根据各种网上的资料,自己做个理解总结。
说起中断首先讲到的就是中断向量表:
arch/arm/kernel/entry-armv.S中的一个表,表内每一项都指示了相应类型中断的入口地址:
__vectors_start:
ARM( swi SYS_ERROR0 )
THUMB( svc #0 )
THUMB( nop )
W(b) vector_und + stubs_offset--->
未定义指令异常
W(ldr) pc, .LCvswi + stubs_offset--->系统调用
W(b) vector_pabt + stubs_offset--->指令预取终止异常
W(b)
vector_dabt + stubs_offset--->Data abort异常
W(b) vector_addrexcptn + stubs_offset--->Address exception地址异常,说是32位上不会发生的
W(b) vector_irq + stubs_offset--->普通中断
W(b) vector_fiq + stubs_offset--->外部快速中断
vector_und ,LCvswi , vector_dabt ,vector_addrexcptn ,
vector_irq ,
vector_fiq 的定义的话我们同样可以在
arch/arm/kernel/entry-armv.S中找到,大概内容都差不多
如:
vector_fiq:
disable_fiq
subs pc, lr, #4
那就是啥都没做,disable一下就回去了。
如:
.globl __stubs_start
__stubs_start:
/*
* Interrupt dispatcher
*/
vector_stub irq, IRQ_MODE, 4---》vector_stub 是一个宏,接受参数后将第一个字段和vector拼接,也就是说这里是vector_irq:....当然宏展开还有其他内容么
.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
这就是一个中断分派表了。中断来了之后,首先是去找__stubs_start,然后根据中断类型以及当时的工具模式找到对应的entry,看到这里只定义了__irq_usr 和__irq_svc。
我们拿__irq_svc来说,就是这个中断来的时候当前CPU在执行内核太代码啦。
.align 5
__irq_svc:
svc_entry
#ifdef CONFIG_PREEMPT
get_thread_info tsk
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
add r7, r8, #1 @ increment it
str r7, [tsk, #TI_PREEMPT]
#endif
irq_handler
#ifdef CONFIG_PREEMPT
str r8, [tsk, #TI_PREEMPT] @ restore preempt count
ldr r0, [tsk, #TI_FLAGS] @ get flags
teq r8, #0 @ if preempt count != 0
movne r0, #0 @ force flags to 0
tst r0, #_TIF_NEED_RESCHED
blne svc_preempt
#endif
ldr r4, [sp, #S_PSR] @ irqs are already disabled
#ifdef CONFIG_TRACE_IRQFLAGS
tst r4, #PSR_I_BIT
bleq trace_hardirqs_on
#endif
svc_exit r4 @ return from exception
UNWIND(.fnend )
ENDPROC(__irq_svc)
前后反正就是中断进出过程中搞来搞去的一些事,高亮的才是核心
irq_handle其实他就是个宏,那么它只做什么的呢,我们看它的代码
.macro irq_handler
get_irqnr_preamble r5, lr
1: get_irqnr_and_base r0, r6, r5, lr
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, BSYM(1b)
bne asm_do_IRQ
#ifdef CONFIG_SMP
/*
* XXX
*
* this macro assumes that irqstat (r6) and base (r5) are
* preserved from get_irqnr_and_base above
*/
test_for_ipi r0, r6, r5, lr
movne r0, sp
adrne lr, BSYM(1b)
bne do_IPI
#ifdef CONFIG_LOCAL_TIMERS
test_for_ltirq r0, r6, r5, lr
movne r0, sp
adrne lr, BSYM(1b)
bne do_local_timer
#endif
#endif
.endm
红色大字大家就熟悉了吧,终于到C代码了。这样,我们就知道怎么的中断就搞到那几个中断处理函数上来了。
这个表我们讲完了。现在有个疑问,这个表是放什么地方的呢?
我们不管内核把他放在了zImage的什么地方了,(只要能找到代码在什么地方就好了)因为那没有意义,还是要看最终在什么地方,这就要看这个函数了:
setup_arch()-》early_trap_init
void __init early_trap_init(void)
{
....
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
....
}
这里三句memcpy起到了关键作用,分别把中断中出现过的几个部件放到了想要的位置,这个位置的起始点就是vectors,这个值是在这个函数一开始的地方赋值的
unsigned long vectors = CONFIG_VECTORS_BASE;
说明了一点,这个地址是可以配的,根据soc的情况不同可能不同,但大量的文件都把这个值设为0xffff0000,这个原因么,不知道。
阅读(505) | 评论(0) | 转发(0) |