Linux中的中断处理系统非常依赖于体系结构,依赖于处理器、所使用的中断控制器(PIC--- programmable interrupt controller)、体系结构和机器本身。
1. 中断处理机制如下图所示:
设备产生中断,通过总线将电信号发送给中断控制器。如果中断号是激活的(中断号是允许被屏蔽的),那么中断控制器就会把中断发给处理器。
除非处理器上禁止了该中断号,否则处理器会立即停止它正在做的事,关闭中断系统,然后跳到内存中预定义的位置,开始执行那里的代码。
这个预定义的位置由内核设置,是中断处理程序的入口点。
对于每个中断号,处理器都跳到对应的一个(也是唯一)的位置。
2. 这时, 内核会调用函数: do_IRQ():
处理IRQ: 不同平台,有不同的处理IRQ程序实现:
1. 中断处理机制如下图所示:
设备产生中断,通过总线将电信号发送给中断控制器。如果中断号是激活的(中断号是允许被屏蔽的),那么中断控制器就会把中断发给处理器。
除非处理器上禁止了该中断号,否则处理器会立即停止它正在做的事,关闭中断系统,然后跳到内存中预定义的位置,开始执行那里的代码。
这个预定义的位置由内核设置,是中断处理程序的入口点。
对于每个中断号,处理器都跳到对应的一个(也是唯一)的位置。
2. 这时, 内核会调用函数: do_IRQ():
处理IRQ: 不同平台,有不同的处理IRQ程序实现:
void do_IRQ(struct pt_regs *regs);
void do_IRQ(int irq, struct pt_regs *regs);
pt_regs 是用于保存内核使用的寄存器的集合。各个平台的寄存器情况又各不相同。所以pt_regs 内容也不一样。
计算出中断号后,do_IRQ()会对所接收的中断进行应答,并禁止该中断号上的中断传递。
do_IRQ()需要确保在这条中断线上有一个有效的处理程序,这里do_IRQ()就调用了handle_IRQ_event(), 用来运行这个中断号上所安装的中断处理程序。
3. handle_IRQ_event(): 定义于<kernel/irq/handler.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;
do {
trace_irq_handler_entry(irq, action);
ret = action->handler(irq, action->dev_id);
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(); //最后禁止中断, do_IRQ()期望中断一直是禁止的。
return retval;
}
注意该函数参数:
一个是中断号,一个就是中断处理函数。
handle_IRQ_event()函数作用: 就是用来运行一个中断号对应的中断处理函数。