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

中断处理机制的实现

2014年02月14日 ⁄ 综合 ⁄ 共 4894字 ⁄ 字号 评论关闭

     在内核中,中断的旅程开始于预定义入口点,这类似于系统调用通过预定义的异常句柄进入内核。对应每条中断线,处理器都会跳到对应的一个唯一的位置。这样,内核就可以知道所接收中断的IRQ号了。初始入口点只是在栈中保存这个号,并存放当前寄存器的值(这些值属于被中断的任务);然后,内核调用函数do_IRQ()。

下面的代码在/arch/i386/kernel/Irq.c中:

  1. /*
  2.  * do_IRQ handles all normal device IRQ's (the special
  3.  * SMP cross-CPU interrupts have their own specific
  4.  * handlers).
  5.  */
  6. fastcall unsigned int do_IRQ(struct pt_regs *regs)
  7. {   
  8.     struct pt_regs *old_regs;
  9.     /* high bit used in ret_from_ code */
  10.     int irq = ~regs->orig_eax;
  11.     struct irq_desc *desc = irq_desc + irq;
  12. #ifdef CONFIG_4KSTACKS
  13.     union irq_ctx *curctx, *irqctx;
  14.     u32 *isp;
  15. #endif
  16.     if (unlikely((unsigned)irq >= NR_IRQS)) {
  17.         printk(KERN_EMERG "%s: cannot handle IRQ %d/n",
  18.                     __FUNCTION__, irq);
  19.         BUG();
  20.     }
  21.     old_regs = set_irq_regs(regs);
  22.     irq_enter();
  23. #ifdef CONFIG_DEBUG_STACKOVERFLOW
  24.     /* Debugging check for stack overflow: is there less than 1KB free? */
  25.     {
  26.         long esp;
  27.         __asm__ __volatile__("andl %%esp,%0" :
  28.                     "=r" (esp) : "0" (THREAD_SIZE - 1));
  29.         if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {
  30.             printk("do_IRQ: stack overflow: %ld/n",
  31.                 esp - sizeof(struct thread_info));
  32.             dump_stack();
  33.         }
  34.     }
  35. #endif
  36. #ifdef CONFIG_4KSTACKS
  37.     curctx = (union irq_ctx *) current_thread_info();
  38.     irqctx = hardirq_ctx[smp_processor_id()];
  39.     /*
  40.      * this is where we switch to the IRQ stack. However, if we are
  41.      * already using the IRQ stack (because we interrupted a hardirq
  42.      * handler) we can't do that and just have to keep using the
  43.      * current stack (which is the irq stack already after all)
  44.      */
  45.     if (curctx != irqctx) {
  46.         int arg1, arg2, ebx;
  47.         /* build the stack frame on the IRQ stack */
  48.         isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
  49.         irqctx->tinfo.task = curctx->tinfo.task;
  50.         irqctx->tinfo.previous_esp = current_stack_pointer;
  51.         /*
  52.          * Copy the softirq bits in preempt_count so that the
  53.          * softirq checks work in the hardirq context.
  54.          */
  55.         irqctx->tinfo.preempt_count =
  56.             (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
  57.             (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
  58.         asm volatile(
  59.             "       xchgl  %%ebx,%%esp      /n"
  60.             "       call   *%%edi           /n"
  61.             "       movl   %%ebx,%%esp      /n"
  62.             : "=a" (arg1), "=d" (arg2), "=b" (ebx)
  63.             :  "0" (irq),   "1" (desc),  "2" (isp),
  64.                "D" (desc->handle_irq)
  65.             : "memory""cc"
  66.         );
  67.     } else
  68. #endif
  69.         desc->handle_irq(irq, desc);
  70.     irq_exit();
  71.     set_irq_regs(old_regs);
  72.     return 1;
  73. }

struct pt_regs结构

  1. struct pt_regs {
  2.     unsigned long r15;
  3.     unsigned long r14;
  4.     unsigned long r13;
  5.     unsigned long r12;
  6.     unsigned long rbp;
  7.     unsigned long rbx;
  8. /* arguments: non interrupts/non tracing syscalls only save upto here*/
  9.     unsigned long r11;
  10.     unsigned long r10;
  11.     unsigned long r9;
  12.     unsigned long r8;
  13.     unsigned long rax;
  14.     unsigned long rcx;
  15.     unsigned long rdx;
  16.     unsigned long rsi;
  17.     unsigned long rdi;
  18.     unsigned long orig_rax;
  19. /* end of arguments */
  20. /* cpu exception frame or undefined */
  21.     unsigned long rip;
  22.     unsigned long cs;
  23.     unsigned long eflags;
  24.     unsigned long rsp;
  25.     unsigned long ss;
  26. /* top of stack page */
  27. };

 

handle_IRQ_event()函数

  1. /**
  2.  * handle_IRQ_event - irq action chain handler
  3.  * @irq:    the interrupt number
  4.  * @action: the interrupt action chain for this irq
  5.  *
  6.  * Handles the action chain of an irq event
  7.  */
  8. irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
  9. {
  10.     irqreturn_t ret, retval = IRQ_NONE;
  11.     unsigned int status = 0;
  12.     handle_dynamic_tick(action);
  13.     if (!(action->flags & IRQF_DISABLED))
  14.         local_irq_enable_in_hardirq();
  15. /**
  16.  * 如果这条中断线是共享的,每个潜在的处理程序在循环中依次执行
  17.  * 如果这条中断线不是共享的,第一次执行后就退出循环
  18.  */
  19.     do {
  20.         ret = action->handler(irq, action->dev_id);
  21.         if (ret == IRQ_HANDLED)
  22.             status |= action->flags;
  23.         retval |= ret;
  24.         action = action->next;
  25.     } while (action);
  26. /**
  27.  * 如果在注册期间指定了SA_SAMPLE_RANDOM标志
  28.  * 还要为随机数产生器产生熵
  29.  */
  30.     if (status & IRQF_SAMPLE_RANDOM)
  31.         add_interrupt_randomness(irq);    //该函数使用中断间隔时间为随机数产生器产生熵
  32.     local_irq_disable();
  33.     return retval;
  34. }

struct irqaction 结构

  1. typedef irqreturn_t (*irq_handler_t)(intvoid *);
  2. struct irqaction {
  3.     irq_handler_t handler;
  4.     unsigned long flags;
  5.     cpumask_t mask;
  6.     const char *name;
  7.     void *dev_id;
  8.     struct irqaction *next;
  9.     int irq;
  10.     struct proc_dir_entry *dir;
  11. };

 

local_irq_enable_in_hardirq()宏

  1. #ifdef CONFIG_LOCKDEP
  2. # define local_irq_enable_in_hardirq()  do { } while (0)
  3. #else
  4. # define local_irq_enable_in_hardirq()  local_irq_enable()
  5. #endif
  6. static inline void local_irq_enable(void)
  7. {
  8.     unsigned long flags;
  9.     __asm__ __volatile__ ("rsil %0, 0" : "=a" (flags) :: "memory");
  10. }

handle_dynamic_tick(action)宏

  1. #ifndef handle_dynamic_tick
  2. # define handle_dynamic_tick(a)     do { } while (0)
  3. #endif

 

 

抱歉!评论已关闭.