其实废话一点都不想说,网上有人写了一大堆,搜搜一大把,想想还是写点自己的东西吧,可以熟悉一下,方便以后查阅
贴一下之前有分析过的一段代码
arch/arm/kernel/trap.c
void __init early_trap_init(void)
{
unsigned long vectors = CONFIG_VECTORS_BASE;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
extern char __kuser_helper_start[], __kuser_helper_end[];
int kuser_sz = __kuser_helper_end - __kuser_helper_start;
/*
* Copy the vectors, stubs and kuser helpers (in entry-armv.S)
* into the vector page, mapped at 0xffff0000, and ensure these
* are visible to the instruction stream.
*/
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);
/*
* Copy signal return handlers into the vector page, and
* set sigreturn to be a pointer to these.
*/
memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
sizeof(sigreturn_codes));
flush_icache_range(vectors, vectors + PAGE_SIZE);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}
这里的红色部分将中断向量搬掉了啊,他妈的不地道,不管那么多了,心里有数就行了,
arch/arm/kernel/entry-armv.S
1195 .LCvswi:
1196 .word vector_swi
1197
1198 .globl __stubs_end
1199 __stubs_end:
1200
1201 .equ stubs_offset, __vectors_start + 0x200 - __stubs_start
1202
1203 .globl __vectors_start
1204 __vectors_start:
1205 swi SYS_ERROR0
1206 b vector_und + stubs_offset
1207 ldr pc, .LCvswi + stubs_offset
1208 b vector_pabt + stubs_offset
1209 b vector_dabt + stubs_offset
1210 b vector_addrexcptn + stubs_offset
1211 b vector_irq + stubs_offset //直接跳到中断里执行看下面贴的代码
1212 b vector_fiq + stubs_offset
1213
1214 .globl __vectors_end
1215 __vectors_end:
1216
看到上面红色的地方了不,
1069
1070 .globl __stubs_start
1071 __stubs_start:
1072 /*
1073 * Interrupt dispatcher
1074 */
1075 vector_stub irq, IRQ_MODE, 4
1076
1077 .long __irq_usr @ 0 (USR_26 / USR_32)
1078 .long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
1079 .long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
1080 .long __irq_svc @ 3 (SVC_26 / SVC_32)
1081 .long __irq_invalid @ 4
1082 .long __irq_invalid @ 5
1083 .long __irq_invalid @ 6
1084 .long __irq_invalid @ 7
1085 .long __irq_invalid @ 8
1086 .long __irq_invalid @ 9
1087 .long __irq_invalid @ a
1088 .long __irq_invalid @ b
1089 .long __irq_invalid @ c
1090 .long __irq_invalid @ d
1091 .long __irq_invalid @ e
1092 .long __irq_invalid @ f
继续贴
435 .align 5
436 __irq_usr:
437 usr_entry
438 kuser_cmpxchg_check
439
440 #ifdef CONFIG_TRACE_IRQFLAGS
441 bl trace_hardirqs_off
442 #endif
443 get_thread_info tsk
444 #ifdef CONFIG_PREEMPT
445 ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
446 add r7, r8, #1 @ increment it
447 str r7, [tsk, #TI_PREEMPT]
448 #endif
449
450 irq_handler //这里是重头戏
451 #ifdef CONFIG_PREEMPT
452 ldr r0, [tsk, #TI_PREEMPT]
453 str r8, [tsk, #TI_PREEMPT]
454 teq r0, r7
455 strne r0, [r0, -r0]
456 #endif
457 #ifdef CONFIG_TRACE_IRQFLAGS
458 bl trace_hardirqs_on
459 #endif
460
461 mov why, #0
462 b ret_to_user //听说这里是中断返回
463 UNWIND(.fnend )
464 ENDPROC(__irq_usr)
465
466 .ltorg
继续贴irq_handler重头戏的内容
30 .macro irq_handler
31 get_irqnr_preamble r5, lr
32 1: get_irqnr_and_base r0, r6, r5, lr
33 movne r1, sp
34 @
35 @ routine called with r0 = irq number, r1 = struct pt_regs * //看到了吗,这附近看来有东西已经拿到中断号了
36 @
37 adrne lr, 1b
38 bne asm_do_IRQ //看来中断是在这里被调用呀,
39
40 #ifdef CONFIG_SMP
41 /*
42 * XXX
43 *
44 * this macro assumes that irqstat (r6) and base (r5) are
45 * preserved from get_irqnr_and_base above
46 */
47 test_for_ipi r0, r6, r5, lr
48 movne r0, sp
49 adrne lr, 1b
50 bne do_IPI
51
52 #ifdef CONFIG_LOCAL_TIMERS
继续贴asm_do_IRQ代码
arch/arm/kernel/irq.c
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
irq_enter(); //上下文切换
/*
* Some hardware gives randomly wrong interrupts. Rather
* than crashing, do something sensible.
*/
if (unlikely(irq >= NR_IRQS)) {
if (printk_ratelimit())
printk(KERN_WARNING "Bad IRQ%u\n", irq);
ack_bad_irq(irq);
} else {
generic_handle_irq(irq);
}
/* AT91 specific workaround */
irq_finish(irq); //arch/arm/kernel/irq.c什么也没做
irq_exit(); //kernel/softirq.c
set_irq_regs(old_regs);
}
kernel/softirq.c
/*
* Enter an interrupt context.
*/
void irq_enter(void)
{
int cpu = smp_processor_id();
rcu_irq_enter();
if (idle_cpu(cpu) && !in_interrupt()) {
__irq_enter();
tick_check_idle(cpu);
} else
__irq_enter();
}
/include/linux/hardirq.h
#define __irq_enter() \
do { \
account_system_vtime(current); \
add_preempt_count(HARDIRQ_OFFSET); \
trace_hardirq_enter(); \
} while (0)
到这里必须得贴我们伟大的generic_handle_irq了
include/linux/irq.h
/*
* Architectures call this to let the generic IRQ layer
* handle an interrupt. If the descriptor is attached to an
* irqchip-style controller then we call the ->handle_irq() handler,
* and it calls __do_IRQ() if it's attached to an irqtype-style controller.
*/
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
desc->handle_irq(irq, desc);
#else
if (likely(desc->handle_irq))
desc->handle_irq(irq, desc); //看到这里是不是你又傻眼了,这是什么玩意,好吧,哥哥我郑重的告诉你,见下面
else
__do_IRQ(irq); //刚刚分析了一下这里调用的是dest->handle_irq里最终调用的handle_IRQ_event
#endif
}
MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board")
/* Maintainer: Freescale Semiconductor, Inc. */
.phys_io = AIPS1_BASE_ADDR,
.io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
.fixup = fixup_mxc_board,
.map_io = mx5_map_io,
.init_irq = mx5_init_irq,
.init_machine = mxc_board_init,
.timer = &mxc_timer,
MACHINE_END
arch/arm/kernel/irq.c
void __init init_IRQ(void)
{
int irq;
for (irq = 0; irq < NR_IRQS; irq++)
irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;
init_arch_irq(); //分析到处,他妈的又差点把我给骗了此处在start_kernel中的setup_arch里将machine start里的init_irq传递到此的,此为函数指针
}
arch/arm/mach-mx5/device.c
void __init mx5_init_irq(void)
{
。。。。。。。。。。。。。。。。。。
mxc_tzic_init_irq(tzic_addr);
}
arch/arm/plat-mxc/tzic.c
void __init mxc_tzic_init_irq(unsigned long base)
{
....................................
for (i = 0; i < TZIC_NUM_IRQS; i++) {
set_irq_chip(i, &mxc_tzic_chip);
set_irq_handler(i, handle_level_irq); //就是这里有为每个中断描述表的那个玩意赋值了,所以我们要执行那个玩意,而不是__do_IRQ
set_irq_flags(i, IRQF_VALID);
}
printk(KERN_INFO "MXC IRQ initialized\n");
}
既然已经调用了这里的handle_level_irq,那就继续分析他吧,
kernel/irq/chip.c
void
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
struct irqaction *action;
irqreturn_t action_ret;
spin_lock(&desc->lock);
mask_ack_irq(desc, irq);
if (unlikely(desc->status & IRQ_INPROGRESS))
goto out_unlock;
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_incr_irqs_this_cpu(irq, desc);
/*
* If its disabled or no action available
* keep it masked and get out of here
*/
action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED)))
goto out_unlock;
desc->status |= IRQ_INPROGRESS;
spin_unlock(&desc->lock);
action_ret = handle_IRQ_event(irq, action); //看到此处相信你早已乐不合拢了, 这里是柳暗花明啊
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
desc->chip->unmask(irq);
out_unlock:
spin_unlock(&desc->lock);
}
kernel/irq/handle.c
/**
* handle_IRQ_event - irq action chain handler
* @irq: the interrupt number
* @action: the interrupt action chain for this irq
*
* Handles the action chain of an irq event
*/
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;
if (!(action->flags & IRQF_DISABLED))
local_irq_enable_in_hardirq();
do {
trace_irq_handler_entry(irq, action);
ret = action->handler(irq, action->dev_id); //这里调用了用户用request_irq注册的中断了
trace_irq_handler_exit(irq, action, ret);
switch (ret) {
case IRQ_WAKE_THREAD:
/*
* Set result to handled so the spurious check
* does not trigger.
*/
ret = IRQ_HANDLED;
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}
/*
* Wake up the handler thread for this
* action. In case the thread crashed and was
* killed we just pretend that we handled the
* interrupt. The hardirq handler above has
* disabled the device interrupt, so no irq
* storm is lurking.
*/
if (likely(!test_bit(IRQTF_DIED,
&action->thread_flags))) {
set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
wake_up_process(action->thread);
}
/* Fall through to add to randomness */
case IRQ_HANDLED:
status |= action->flags;
break;
default:
break;
}
retval |= ret;
action = action->next;
} while (action);
if (status & IRQF_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
local_irq_disable();
return retval;
}