ARMv8 中断机制

1. 中断向量表

arch/arm64/kernel/entry.S

/*
 * Exception vectors.
 */

        .align  11
ENTRY(vectors)
        ventry  el1_sync_invalid                // Synchronous EL1t
        ventry  el1_irq_invalid                 // IRQ EL1t
        ventry  el1_fiq_invalid                 // FIQ EL1t
        ventry  el1_error_invalid               // Error EL1t

        ventry  el1_sync                        // Synchronous EL1h
        ventry  el1_irq                         // IRQ EL1h
        ventry  el1_fiq_invalid                 // FIQ EL1h
        ventry  el1_error_invalid               // Error EL1h

        ventry  el0_sync                        // Synchronous 64-bit EL0
        ventry  el0_irq                         // IRQ 64-bit EL0
        ventry  el0_fiq_invalid                 // FIQ 64-bit EL0
        ventry  el0_error_invalid               // Error 64-bit EL0

#ifdef CONFIG_COMPAT
        ventry  el0_sync_compat                 // Synchronous 32-bit EL0
        ventry  el0_irq_compat                  // IRQ 32-bit EL0
        ventry  el0_fiq_invalid_compat          // FIQ 32-bit EL0
        ventry  el0_error_invalid_compat        // Error 32-bit EL0
#else
        ventry  el0_sync_invalid                // Synchronous 32-bit EL0
        ventry  el0_irq_invalid                 // IRQ 32-bit EL0
        ventry  el0_fiq_invalid                 // FIQ 32-bit EL0
        ventry  el0_error_invalid               // Error 32-bit EL0
#endif
END(vectors)


每个CPU 在初始化是,都会设置中断向量地址。


arch/arm64/kernel/head.S


/*
 * Setup common bits before finally enabling the MMU. Essentially this is just
 * loading the page table pointer and vector base registers.
 *
 * On entry to this code, x0 must contain the SCTLR_EL1 value for turning on
 * the MMU.
 */
__enable_mmu:
        ldr     x5, =vectors
        msr     vbar_el1, x5                     //设置中断向量地址
        msr     ttbr0_el1, x25                  // load TTBR0
        msr     ttbr1_el1, x26                  // load TTBR1
        isb
        b       __turn_mmu_on
ENDPROC(__enable_mmu)


2 中断处理

有中断产生时, GIC会向相应的CPU发出中断信号,CPU检测到中断信号,根据中断向量表,跳转到el1_irq


arch/arm64/kernel/entry.S

el1_irq:
        kernel_entry 1
        enable_dbg
#ifdef CONFIG_TRACE_IRQFLAGS
        bl      trace_hardirqs_off
#endif

        irq_handler

#ifdef CONFIG_PREEMPT
        get_thread_info tsk
        ldr     w24, [tsk, #TI_PREEMPT]         // get preempt count
        cbnz    w24, 1f                         // preempt count != 0
        ldr     x0, [tsk, #TI_FLAGS]            // get flags
        tbz     x0, #TIF_NEED_RESCHED, 1f       // needs rescheduling?
        bl      el1_preempt
1:
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
        bl      trace_hardirqs_on
#endif
        kernel_exit 1
ENDPROC(el1_irq)

/*
 * Interrupt handling.
 */
        .macro  irq_handler
#ifdef CONFIG_STRICT_MEMORY_RWX
        ldr     x1, =handle_arch_irq
        ldr     x1, [x1]
#else
        ldr     x1, handle_arch_irq
#endif
        mov     x0, sp
        blr     x1
        .endm

        .text


arch/arm64/kernel/irq.c


void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
{
        if (handle_arch_irq)
                return;

        handle_arch_irq = handle_irq;
}

http://blog.csdn.net/firefox_1980/article/details/40863107 写到中断控制器初始化时会调用set_handle_irq(gic_handle_irq);


3. gic_handle_irq


static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
        u32 irqstat, irqnr;
        struct gic_chip_data *gic = &gic_data[0];
        void __iomem *cpu_base = gic_data_cpu_base(gic);

        do {
                irqstat = readl_relaxed_no_log(cpu_base + GIC_CPU_INTACK);
                irqnr = irqstat & ~0x1c00;

                if (likely(irqnr > 15 && irqnr < 1021)) {
                        irqnr = irq_find_mapping(gic->domain, irqnr);
                        handle_IRQ(irqnr, regs);   //调用相应的中断处理函数
                        uncached_logk(LOGK_IRQ, (void *)(uintptr_t)irqnr);
                        continue;
                }
                if (irqnr < 16) {
                        writel_relaxed_no_log(irqstat, cpu_base + GIC_CPU_EOI);
#ifdef CONFIG_SMP
                        handle_IPI(irqnr, regs);      //SMP 通信
#endif
                        uncached_logk(LOGK_IRQ, (void *)(uintptr_t)irqnr);
                        continue;
                }
                break;
        } while (1);
}




你可能感兴趣的:(Android,Kernel,arm,v8,arm,exception,kernel)