我只知道这Interrupt
是hardware signal assertion
处理器引脚造成的。但我想知道Linux操作系统如何处理它。
中断发生时会发生什么?
答案1
这是低级处理的高级视图。我正在描述一个简单的典型架构,真实的架构可能更复杂,或者在方式上有所不同,但在这个细节级别上并不重要。
当打断发生时,处理器会检查中断是否被屏蔽。如果是的话,在揭开面具之前什么也不会发生。当中断未被屏蔽时,如果有任何待处理的中断,处理器会选择一个。
然后处理器通过分支到内存中的特定地址来执行中断。该地址处的代码称为中断处理程序。当处理器在那里分支时,它会屏蔽中断(因此中断处理程序具有独占控制权)并将某些寄存器的内容保存在某个地方(通常是其他寄存器)。
中断处理程序执行其必须执行的操作,通常是通过与触发中断的外设通信来发送或接收数据。如果中断是由计时器引发的,则处理程序可能会触发操作系统调度程序,以切换到不同的线程。当处理程序完成执行时,它会执行一条特殊的中断返回指令,该指令恢复保存的寄存器并取消屏蔽中断。
中断处理程序必须快速运行,因为它会阻止任何其他中断运行。在Linux内核中,中断处理分为两部分:
- “上半部分”是中断处理程序。它执行最少的必要操作,通常与硬件通信并在内核内存中的某个位置设置一个标志。
- “下半部分”执行任何其他必要的处理,例如将数据复制到进程内存、更新内核数据结构等。它可能会花费一些时间,甚至会阻塞等待系统的其他部分,因为它在启用中断的情况下运行。
像往常一样,有关此主题的更多信息,请阅读Linux 设备驱动程序;第10章是关于中断的。
答案2
吉尔斯已经描述中断的一般情况,以下内容专门适用于 Intel 架构上的 Linux 2.6(部分也基于 Intel 的规范)。
中断是改变处理器执行指令顺序的事件。
有两种不同类型的中断:
- 同步中断(例外)CPU在处理指令时产生的
- 异步中断(中断)由其他硬件设备发出
异常是由编程错误引起的(fe除法误差,页面错误,溢出)必须由内核处理。他向程序发送信号并尝试从错误中恢复。
以下两种例外情况被分类:
- 处理器检测到的异常由 CPU 在检测到异常情况时生成;分为三组:故障一般可以纠正,陷阱报告执行情况,中止都是严重错误。
- 程序化异常由程序员请求,像陷阱一样处理。
中断可以由 I/O 设备(键盘、网络适配器等)、间隔定时器和(在多处理器系统上)其他 CPU 发出。当中断发生时,CPU必须停止当前的指令并执行新到达的中断。他需要保存旧的中断进程状态,以便(可能)在处理中断后恢复它。
处理中断是一项敏感任务:
- 中断随时可能发生,内核会尝试尽快将其排除
- 一个中断可以被另一个中断打断
- 内核中有一些区域绝对不能被中断
定义了两种不同的中断级别:
- 可屏蔽中断由I/O设备发出;可以处于两种状态,屏蔽或未屏蔽。仅处理未屏蔽的中断。
- 不可屏蔽中断;严重故障(例如硬件故障);始终由CPU处理。
每个硬件设备都有自己的中断请求(IRQ)线。 IRQ 从 0 开始编号。所有 IRQ 线都连接到可编程中断控制器 (PIC)。 PIC 侦听 IRQ 并将其分配给 CPU。也可以禁用特定的 IRQ 线。
现代多处理 Linux 系统通常包括较新的高级 PIC (APIC),它在 CPU 之间平均分配 IRQ 请求。
中断或异常及其处理之间的中间步骤是中断描述符表 (IDT)。该表将每个中断或异常向量(一个数字)与指定的处理程序(fe除法误差由函数处理divide_error()
)。
通过IDT,内核确切地知道如何处理发生的中断或异常。
那么,当中断发生时内核会做什么呢?
- CPU 在执行每条指令后检查是否有来自 (A)PIC 的 IRQ
- 如果是,则查阅 IDT 将接收到的向量映射到函数
- 检查中断是否由授权源发出
- 保存被中断进程的寄存器
- 调用相应的函数来处理中断
- 加载最近保存的中断进程的寄存器并尝试恢复它
答案3
首先参与中断处理的参与者是外围硬件设备、中断控制器、CPU、操作系统内核和驱动程序。外围硬件设备负责中断产生。当它们需要操作系统内核的注意时,它们会断言中断请求线。这些信号由中断控制器复用,负责中断信号的采集。它还负责确定中断信号传递到 CPU 的顺序。中断控制器能够暂时禁用特定中断请求线 (IRQL) 并再次重新启用它(IRQL 屏蔽)。中断控制器将收集到的中断请求依次传递给CPU。每条指令执行完成后,CPU 会检查是否有来自中断控制器的等待中断请求。如果CPU发现有等待请求并且内部CPU控制寄存器中设置了中断允许标志,则CPU开始中断处理。可以看到,Linux内核通过对CPU中中断标志的操作以及与中断控制器的通信来控制中断的接受。例如,Linux 可以禁止接受来自特定设备的中断,或者根本禁止接受中断。
当处理器收到中断请求时会发生什么?首先,CPU通过重置中断标志来自动禁用中断。一旦中断处理完成,它们将被重新启用。同时,CPU 完成将 CPU 从用户模式切换到内核模式所需的最小工作量,从而允许它恢复执行中断的代码。 CPU 参考 Linux 内核填充的特殊 CPU 控制结构来查找控制权将传递到的代码地址。该地址是中断处理程序的第一条指令的地址,它是Linux内核的一部分。
作为中断处理的第一步,内核识别接收到的中断向量,以识别系统中发生了哪种事件。中断向量定义了Linux将采取什么行动来处理它。第二步,Linux 保存其余的 CPU 寄存器(CPU 不会自动保存),这些寄存器可能会被中断的程序使用。这是非常重要的动作,因为它允许Linux对于被中断的程序透明地处理中断。第三步,Linux通过设置内核环境和设置其所需的CPU状态来完成向内核模式的切换。最后,调用与向量相关的中断处理程序。 (您可以查看 arch\x86\kernel\entry_32.S 中的 BUILD_INTERRUPT3 宏来获取 x86 架构相关示例的其他详细信息)对于外围设备,这是一个 do_IRQ() 例程。 (查看arch\x86\kernel\irq.c)
向量相关的中断处理程序通常通过调用 irq_enter() 和 irq_exit() 来包装。包含在这些函数对内的代码区域相对于任何其他此类区域是原子的,并且相对于 cli/sti 对也是原子的。 irq_enter() 和 irq_exit() 还捕获一些与中断处理相关的统计信息。最后,内核查看vector_irq表以找到分配给接收到的中断向量的irq号,并调用handle_irq()(来自arch\x86\kernel\irq_32.c)。
此时,Linux 中中断处理的公共部分结束,因为内核将设备驱动程序安装的设备相关中断处理程序例程视为 irq 描述符的一部分并调用它。如果驱动程序没有安装这样的处理程序,内核只会在中断控制器上确认中断并从通用中断处理程序中退出。
中断处理结束后,内核恢复先前被中断的程序的状态并恢复该程序的执行。