日期:2014-05-16  浏览次数:20744 次

细说Linux内核中断架构

中断和异常

一、什么是中断?

        中断通常被定义为一个事件,该事件改变处理器执行的指令顺序。这样的事件与CPU芯片内外部硬件电路产生的电信号相对应。

        中断通常分为同步中断和异步中断:

2  同步中断是当指令执行时由CPU控制单元产生的,之所以称为同步,是因为只有在一条指令终止执行后CPU才会发出中断。

        ◎ 异步中断是由其他硬件设备依照CPU时钟信号随机产生的。

        在Intel微处理器手册中:

        ◎ 把同步中断称为异常(exception

        ◎ 把异步中断称为中断(interrupt

        这两类中断的共同特点是什么?如果CPU当前不处于核心态,则发起从用户态到核心态的切换。接下来,在内核中执行一个专门的例程,称为中断服务例程(interrupt service routine)。或中断处理程序(interrupthandler)

        另一方面,异常是由程序的错误产生的,或者是由内核必须处理的异常条件产生的。第一种情况下,内核通过发送一个每个Unix/Linux程序员都熟悉的信号来处理异常。第二种情况下,内核执行恢复异常需要的所有步骤,例如缺页异常等。

二、中断信号的作用

        中断信号提供了一种特殊的方式,使处理器转而去运行正常控制流之外的代码。当一个中断信号达到时,CPU必须停止它当前正在做的事情,并且切换到一个新的活动。为了这做到这一点,就要在内核态堆栈保存程序计数器的当前值(即EIP和CS寄存器的内容),并把与中断类型相关的一个地址放进程序计数器。

        这可能会让我们想起系统调度的进程切换,发生在内核用一个进程替换另一个进程时。但是中断处理与进程切换有一个明显的差异:由中断或异常处理程序执行的代码不是一个进程。更准确的说,它是一个内核控制路径,代表中断发生时正在运行的进程执行。作为一个内核控制路径,中断处理程序比一个进程要“轻”(中断的上下文很少,建立或终止中断处理需要的时间也很少)

        中断处理是由内核执行的最敏感的任务之一,因为它必须满足下列约束:

        ◎ 当内核正打算去完成一些别的事情时,中断随时会到来。因此,内核的目标就是让中断尽可能快地处理完,尽其所能把更多的处理向后推迟。因此,内核响应中断后需要进行的操作分为两部分:关键而紧急的部分,内核立即执行;其余推迟的部分,内核随后执行。

        ◎ 因为中断随时会到来,所以内核可能正在处理其中的一个中断时,另一个不同类型的中断又发生了。内核应该尽可能地允许这种情况发生,因为这能维持更多的I/O设备得到处理的机会。因此,中断处理程序必须编写成使相应的内核控制路径能以嵌套的方式执行。当最后一个内核控制路径终止时,内核必须能恢复被中断进程的执行,或者,如果中断信号已导致了重新调度,内核也应能切换到另外的进程。

        ◎ 尽管内核在处理前一个中断时可以接受一个新的中断,但在内核代码中还是存在一些临界区,在临界区中,中断必须被禁止。必须尽可能地限制这样的临界区,因为根据以前的要求,内核,尤其是中断处理程序,应该在大部分时间内以开中断的方式运行。

三、IRQ和中断

        中断这个名词使用得并不是很谨慎,为什么?由于中断是用来表示由CPU和外部硬件发出的信号所产生的。但是中断不能由处理器外部的外设直接产生,而必须借助于一个称为可编程中断控制器(programmable interrupt controller)的标准组件来请求,该组件存在于每个系统中。

        外部设备,会有电路连接到用于向中断控制器发送中断请求的组件。控制器在执行了各种电工任务之后,将中断请求转发到CPU的中断输入中。因为外部设备不能直接发出中断,而必须通过中断控制器的标准组件来请求中断,所以这种请求更正确的叫法是IRQ,或中断请求(Interrupt Request)。

每个能够发出中断请求的硬件设备控制器都有这么一条名为IRQ的输出线。所有现有的IRQ线都会与这个中断控制器(PIC)的硬件电路的输入引脚相连。下面来看看这种中断控制器执行下列动作: