arch/arm/kernel/entry-v7m.S
ENTRY(vector_table)
.long 0 @ 0 - Reset stack pointer
.long __invalid_entry @ 1 - Reset
.long __invalid_entry @ 2 - NMI
.long __hardfault_entry @ 3 - HardFault
#ifdef CONFIG_MPU
.long __memmanage_entry @ 4 - MemManage
#else
.long __invalid_entry @ 4 - MemManage
#endif
.long __busfault_entry @ 5 - BusFault
.long __usagefault_entry @ 6 - UsageFault
.long __invalid_entry @ 7 - Reserved
.long __invalid_entry @ 8 - Reserved
.long __invalid_entry @ 9 - Reserved
.long __invalid_entry @ 10 - Reserved
.long vector_swi @ 11 - SVCall
.long __invalid_entry @ 12 - Debug Monitor
.long __invalid_entry @ 13 - Reserved
.long __pendsv_entry @ 14 - PendSV
.long __invalid_entry @ 15 - SysTick
.rept NR_IRQS
.long __irq_entry @ 16.. - NR_IRQS External Interrupts
.endr
#if defined(CONFIG_ARM_CORTEXM3)
ENTRY(vector_table_end)
由于在uclinux里面没有使用nvic中断控制器直接跳转,所以全部的常规中断都归于一个入口__irq_entry, 这里有NR_IRQS个中断
__irq_entry:
v7m_exception_entry
@
@ Invoke the IRQ handler
@
mrs r0, ipsr
and r0, #0xff
sub r0, #16 @ IRQ number
mov r1, sp
@ routine called with r0 = irq number, r1 = struct pt_regs *
bl asm_do_IRQ
@
@ Check for any pending work if returning to user
@
ldr lr, [sp, #S_EXC_LR]
cmp lr, #0xfffffffd @ check the return stack
bne 2f @ returning to kernel
get_thread_info tsk
ldr r1, [tsk, #TI_FLAGS]
tst r1, #_TIF_WORK_MASK
beq 2f @ no work pending
ldr r1, =0xe000ed04 @ ICSR
mov r0, #1 << 28 @ ICSR.PENDSVSET
str r0, [r1] @ raise PendSV
当中断发生的时候,就直接跳转到了__irq_entry,然后通过asm_do_IRQ进入c代码中断
arch/arm/kernel/irq.c
/*
* do_IRQ handles all hardware IRQ's. Decoded IRQs should not
* come via this function. Instead, they should provide their
* own 'handler'
*/
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);
irq_exit();
set_irq_regs(old_regs);
}
然后就进入generic_handle_irq(irq)程序
这个定义是在include/linux/irq.h里面
static inline void generic_handle_irq(unsigned int irq)
{
generic_handle_irq_desc(irq, irq_to_desc(irq));
}
generic_handle_irq_desc函数也在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);
#endif
}
struct irq_desc也是在include/linux/irq.h中定义的。
/**
* struct irq_desc - interrupt descriptor
* @irq: interrupt number for this descriptor
* @timer_rand_state: pointer to timer rand state struct
* @kstat_irqs: irq stats per cpu
* @irq_2_iommu: iommu with this irq
* @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]
* @chip: low level interrupt hardware access
* @msi_desc: MSI descriptor
* @handler_data: per-IRQ data for the irq_chip methods
* @chip_data: platform-specific per-chip private data for the chip
* methods, to allow shared chip implementations
* @action: the irq action chain
* @status: status information
* @depth: disable-depth, for nested irq_disable() calls
* @wake_depth: enable depth, for multiple set_irq_wake() callers
* @irq_count: stats field to detect stalled irqs
* @last_unhandled: aging timer for unhandled count
* @irqs_unhandled: stats field for spurious unhandled interrupts
* @lock: locking for SMP
* @affinity: IRQ affinity on SMP
* @node: node index useful for balancing
* @pending_mask: pending rebalanced interrupts
* @threads_active: number of irqaction threads currently running
* @wait_for_threads: wait queue for sync_irq to wait for threaded handlers
* @dir: /proc/irq/ procfs entry
* @name: flow handler name for /proc/interrupts output
*/
struct irq_desc {
unsigned int irq;
struct timer_rand_state *timer_rand_state;
unsigned int *kstat_irqs;
#ifdef CONFIG_INTR_REMAP
struct irq_2_iommu *irq_2_iommu;
#endif
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
struct msi_desc *msi_desc;
void *handler_data;
void *chip_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */
unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned long last_unhandled; /* Aging timer for unhandled count */
unsigned int irqs_unhandled;
raw_spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_var_t affinity;
unsigned int node;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_t pending_mask;
#endif
#endif
atomic_t threads_active;
wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
const char *name;
} ____cacheline_internodealigned_in_smp;
handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]
handle_irq是一个函数指针,在下贴分析