现在的位置: 首页 > 综合 > 正文

中断五

2013年03月25日 ⁄ 综合 ⁄ 共 11046字 ⁄ 字号 评论关闭

其实废话一点都不想说,网上有人写了一大堆,搜搜一大把,想想还是写点自己的东西吧,可以熟悉一下,方便以后查阅

贴一下之前有分析过的一段代码

 

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;
}

 

 

 

 

 

 

 

 

 

 

 

 

抱歉!评论已关闭.