在内核中,中断的旅程开始于预定义入口点,这类似于系统调用通过预定义的异常句柄进入内核。对应每条中断线,处理器都会跳到对应的一个唯一的位置。这样,内核就可以知道所接收中断的IRQ号了。初始入口点只是在栈中保存这个号,并存放当前寄存器的值(这些值属于被中断的任务);然后,内核调用函数do_IRQ()。
下面的代码在/arch/i386/kernel/Irq.c中:
- /*
- * do_IRQ handles all normal device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- */
- fastcall unsigned int do_IRQ(struct pt_regs *regs)
- {
- struct pt_regs *old_regs;
- /* high bit used in ret_from_ code */
- int irq = ~regs->orig_eax;
- struct irq_desc *desc = irq_desc + irq;
- #ifdef CONFIG_4KSTACKS
- union irq_ctx *curctx, *irqctx;
- u32 *isp;
- #endif
- if (unlikely((unsigned)irq >= NR_IRQS)) {
- printk(KERN_EMERG "%s: cannot handle IRQ %d/n",
- __FUNCTION__, irq);
- BUG();
- }
- old_regs = set_irq_regs(regs);
- irq_enter();
- #ifdef CONFIG_DEBUG_STACKOVERFLOW
- /* Debugging check for stack overflow: is there less than 1KB free? */
- {
- long esp;
- __asm__ __volatile__("andl %%esp,%0" :
- "=r" (esp) : "0" (THREAD_SIZE - 1));
- if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {
- printk("do_IRQ: stack overflow: %ld/n",
- esp - sizeof(struct thread_info));
- dump_stack();
- }
- }
- #endif
- #ifdef CONFIG_4KSTACKS
- curctx = (union irq_ctx *) current_thread_info();
- irqctx = hardirq_ctx[smp_processor_id()];
- /*
- * this is where we switch to the IRQ stack. However, if we are
- * already using the IRQ stack (because we interrupted a hardirq
- * handler) we can't do that and just have to keep using the
- * current stack (which is the irq stack already after all)
- */
- if (curctx != irqctx) {
- int arg1, arg2, ebx;
- /* build the stack frame on the IRQ stack */
- isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
- irqctx->tinfo.task = curctx->tinfo.task;
- irqctx->tinfo.previous_esp = current_stack_pointer;
- /*
- * Copy the softirq bits in preempt_count so that the
- * softirq checks work in the hardirq context.
- */
- irqctx->tinfo.preempt_count =
- (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
- (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
- asm volatile(
- " xchgl %%ebx,%%esp /n"
- " call *%%edi /n"
- " movl %%ebx,%%esp /n"
- : "=a" (arg1), "=d" (arg2), "=b" (ebx)
- : "0" (irq), "1" (desc), "2" (isp),
- "D" (desc->handle_irq)
- : "memory", "cc"
- );
- } else
- #endif
- desc->handle_irq(irq, desc);
- irq_exit();
- set_irq_regs(old_regs);
- return 1;
- }
struct pt_regs结构
- struct pt_regs {
- unsigned long r15;
- unsigned long r14;
- unsigned long r13;
- unsigned long r12;
- unsigned long rbp;
- unsigned long rbx;
- /* arguments: non interrupts/non tracing syscalls only save upto here*/
- unsigned long r11;
- unsigned long r10;
- unsigned long r9;
- unsigned long r8;
- unsigned long rax;
- unsigned long rcx;
- unsigned long rdx;
- unsigned long rsi;
- unsigned long rdi;
- unsigned long orig_rax;
- /* end of arguments */
- /* cpu exception frame or undefined */
- unsigned long rip;
- unsigned long cs;
- unsigned long eflags;
- unsigned long rsp;
- unsigned long ss;
- /* top of stack page */
- };
handle_IRQ_event()函数
- /**
- * 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;
- handle_dynamic_tick(action);
- if (!(action->flags & IRQF_DISABLED))
- local_irq_enable_in_hardirq();
-
- /**
- * 如果这条中断线是共享的,每个潜在的处理程序在循环中依次执行
- * 如果这条中断线不是共享的,第一次执行后就退出循环
- */
- do {
- ret = action->handler(irq, action->dev_id);
- if (ret == IRQ_HANDLED)
- status |= action->flags;
- retval |= ret;
- action = action->next;
- } while (action);
-
- /**
- * 如果在注册期间指定了SA_SAMPLE_RANDOM标志
- * 还要为随机数产生器产生熵
- */
- if (status & IRQF_SAMPLE_RANDOM)
- add_interrupt_randomness(irq); //该函数使用中断间隔时间为随机数产生器产生熵
- local_irq_disable();
- return retval;
- }
struct irqaction 结构
- typedef irqreturn_t (*irq_handler_t)(int, void *);
- struct irqaction {
- irq_handler_t handler;
- unsigned long flags;
- cpumask_t mask;
- const char *name;
- void *dev_id;
- struct irqaction *next;
- int irq;
- struct proc_dir_entry *dir;
- };
local_irq_enable_in_hardirq()宏
- #ifdef CONFIG_LOCKDEP
- # define local_irq_enable_in_hardirq() do { } while (0)
- #else
- # define local_irq_enable_in_hardirq() local_irq_enable()
- #endif
- static inline void local_irq_enable(void)
- {
- unsigned long flags;
- __asm__ __volatile__ ("rsil %0, 0" : "=a" (flags) :: "memory");
- }
handle_dynamic_tick(action)宏
- #ifndef handle_dynamic_tick
- # define handle_dynamic_tick(a) do { } while (0)
- #endif