Interrupts

来自osdev
跳到导航 跳到搜索

“Interrupts 中断” 是从设备 (例如键盘或硬盘驱动器) 到CPU的信号,告诉CPU应当立即停止当前正在执行的操作并去执行其他操作。 例如,键盘控制器可以在按下字符键时发送中断。 然后,操作系统可以立即在屏幕上显示该字符,即使CPU之前正在做完全不相关的事情,然后CPU可以再返回到本来要做的事情。 当出现特定中断时,CPU会从操作系统提供的表中查找该特定中断的条目。 在 x86保护模式 中,该表称为 中断描述符表 (Interrupt Descriptor Table),最多可以有256个条目(Entry),但是该表的名称和它可以拥有的最大条目数可能会因CPU架构而异。 CPU找到中断的条目后,跳转到条目指向的代码。 响应中断而运行的此代码称为 中断服务例程 (ISR) 或中断处理程序

中断的类型

在大多数平台上,通常有三类中断:

  • Exceptions: 这些是由CPU内部生成的,用于向正在运行的内核发出需要其注意的事件或情况的警报。 在x86 cpu上,这些包括双重故障(Double Fault)、页面故障(Page Fault)、通用保护故障(General Protection)等异常条件。
  • Interrupt Request (IRQ) 或 Hardware Interrupt: 这种类型的中断由芯片组外部产生,并通过锁存到目前CPU的#INTR引脚或等效信号来发出信号。 现今常用的IRQ有两种。
    • IRQ Lines, 或 Pin-based IRQs: 这些通常在芯片组上静态路由。 设备上的芯片通过连线或电路将信号发送到IRQ控制器,该控制器将设备发送的中断请求串行化,并将它们逐个发送到CPU以防止信号冲突。 在许多情况下,IRQ控制器会根据设备的优先级一次向CPU发送多个IRQ。 一个非常著名的IRQ控制器的例子是 Intel 8259 控制器链,它存在于所有IBM-PC兼容的芯片组上,将两个控制器链接在一起,每个控制器提供8个输入引脚,用于传统IBM-PC上总共16个可用的IRQ信号引脚。
    • Message Signaled Interrupts: 消息信号中断通过将值写入为关于中断设备、中断本身和向量信息的保留存储器位置来直接发出信号。(译者注:本文的“向量-vector”愿意指的是某些特殊作用的列表中的独立值,例如这里是一系列中断(编号)中的一个) 设备被通过固件或内核软件分配了写入以上值的位置。 然后,设备使用特定于设备总线的仲裁协议生成IRQ。 PCI总线也是一种提供基于消息的中断功能的总线。
  • Software Interrupt: 这是运行在CPU上的软件发出的中断信号,一般表明软件需要内核做出某些响应。 这些类型的中断一般用于 系统调用。 在x86 CPU上,用于启动软件中断的指令是 “INT” 指令。 由于x86 CPU可以使用256可用的中断向量中的任何一个来进行软件中断,所以内核通常需要先从中选择一个。 例如,许多当代的Unix衍生系统在基于x86的平台上使用向量 0x80。

作为一项规则,当一个CPU给开发人员自由选择哪些向量用于什么 (如在x86上),应该避免在同一向量上有不同类型的中断。 通常的做法是,按照Intel的要求,将前32个向量留给Exceptions。 但是,你对其余向量的划分取决于你。

从键盘的角度来看

基本上,当按键被按下时,键盘控制器会告诉被称为 可编程中断控制器(PIC) 的设备发起中断。 由于键盘和PIC的固有接线方式,IRQ #1是键盘中断,因此当按下一个键时,IRQ 1被发送到PIC。 PIC的作用是决定是否应立即通知CPU该IRQ,并将IRQ数转换为CPU表的 “中断向量” (即0和255之间的数字)。

操作系统应该通过 inout 指令 (或 inportb/outportb) 与键盘通信来处理中断,inportw/outportw,以及在C中使用inportd/outportd ,见 内联汇编示例),询问按下了什么键,再对此做一些工作 (例如在屏幕上显示键,并通知当前应用程序已按下某个键),然后返回到中断进入前正在执行的代码。 实际上,如果无法从缓冲区读取键将阻止键盘的任何后续IRQ。

从PIC的角度来看

实际上,大多数系统上都有两个PIC,每个PIC都有8个不同的输入,外加一个输出信号,用于告诉CPU发生了IRQ。 “从PIC”的输出信号连接到“主PIC”的第三个输入口 (输入 #2); 因此,当“从PIC”想要告诉CPU发生中断时,它实际上先告诉“主PIC”,而由主PIC告诉CPU。 这被称为 “级联”。这种方式下主PIC的第三个输入是为此配置的,而不是配置为普通的IRQ,这意味着IRQ 2不能发生。

设备向PIC芯片发送中断,PIC告诉CPU发生了中断 (直接或间接)。 当CPU确认 “中断发生” 信号时,PIC芯片向CPU发送中断编号 (在00h和FFh之间,或十进制0和255之间)。 系统首次启动时,IRQ 0至7设置为中断08h至0Fh,IRQ 8至15设置为中断70h至77h。 因此,对于IRQ 6,PIC将告诉CPU服务INT 0Eh,该服务应该具有用于与连接到主PIC芯片的 “输入 #6” 的任何设备进行交互的代码。 当然,当两个或多个设备共享一个IRQ时,可能会遇到麻烦; 如果你想知道这是如何工作的,请查看 Plug and Play。 注意,中断按优先级处理: 0、1、2、8、9、10、11、12、13、14、15、3、4、5、6、7。 因此,如果IRQ 8和IRQ 3同时进来,则IRQ 8被发送到CPU。 当CPU处理完中断后,它告诉PIC可以继续发送中断:

mov al,20h
out 20h,al

或者如果中断来自从属PIC:

mov al, 20h
out A0h, al
out 20h, al

PIC发送分配给IRQ 3的中断,CPU处理该中断 (使用IDT查找该中断的处理程序)。

警觉的读者可能会注意到CPU保留了中断0-31,但IRQs 0-7设置为中断08-0fh。 现在,当操作系统必须处理的可怕错误发生时,CPU将调用保留的中断。 当计算机首次启动时,大多数此类错误都不会发生。 但是,当你进入保护模式 (并且每个操作系统都应使用保护模式,实模式已过时) 时,这些错误随时可能发生,并且操作系统需要能够处理它们。 操作系统将如何区分INT 9,异常-协处理器的段超限,和INT 9: IRQ 1之间的区别? 其实这时操作系统可以询问设备是否真的有中断。 但这是缓慢又麻烦的,并不是所有的设备都能够做这种事情。 最好的方法是告诉PIC将IRQ映射到 “不同的” 中断,例如INT 78h-7Fh。 有关此信息,请参阅 PIC的常见问题部分。 请注意,IRQ只能映射到08h: 00h-07h,08h-0Fh,10h-17h,17h-1Fh的倍数的整数。 而且你最好使用20h-27h或更高,因为CPU保留了00h-1Fh。 此外,每个PIC都必须单独编程。 你可以告诉“主PIC”将IRQs 0-7映射到INTs 20h-27h,但是IRQs 8-F仍然是INTs 70h-77h,或者你告诉“从PIC”也把它们也放在其他地方。

有关详细信息,请参阅 对PIC芯片进行编程

从CPU的角度来看

每次CPU执行一条机器指令时,它都会检查PIC的引脚是否已通知中断。 如果是这种情况,它会在堆栈上存储一些当前状态信息(这样,当操作系统完成对INT中断的服务时,它就可以返回到当前正在做的任何事情),并跳转到IDT所指向的位置。 操作系统从这里开始接管工作。 同时,当前程序可以通过“中断标志”(IF状态寄存器)来防止CPU再受到中断的干扰。 只要清除该标志,CPU就会忽略PIC的请求,持续运行当前程序。 汇编指令 clisti 可以控制该标志。

从操作系统的角度来看

当出现中断时,IDT (由操作系统预先设置) 用于跳转到操作系统的相关代码部分,该部分处理中断 (因此称为 “中断处理程序” 或 “中断服务例程”)。 通常,操作系统代码开始与设备交互,完成后通过使用 iret 指令返回到它以前的工作, (该指令告诉CPU从堆栈中加载其保存的状态信息)。 在上面 ret 之前,需要执行以下代码,以告诉PIC可以发送任何新的或挂起的中断,因为当前中断已完成。(译者注:以下代码是给8259a芯片发送EOI命令,通知其一个中断已完成) 在CPU确认中断之前,PIC是不会再发送任何中断的:

mov al,20h
out 20h,al

键盘输入 的情况下,中断处理程序会询问键盘按下了哪个键,对信息执行某些操作,然后确认并返回:

push eax    ;; 确保不损坏当前状态
in al,60h   ;; 从键盘读取信息

mov al,20h
out 20h,al  ;; 确认对PIC的中断
pop eax     ;; 恢复状态
iret        ;; 返回到以前执行的代码。

无论CPU以前做什么,然后都需要重新恢复 (除非PIC在服务这个PIC时接收到另一个INT,在这种情况下,PIC会告诉CPU,并且CPU再次将状态信息保存在堆栈上后,就开始执行一个新的中断处理程序)。

那么我该如何编程实现这些 ?

一步一步来,现在你已经抓住了整个事情的脉络,知道要做什么:

  • 为中断描述符表(IDT)腾出空间
  • 告诉CPU该空间在哪里 (请参阅 GDT教程: lidt 的工作方式与 lgdt 的工作方式非常相同)
  • 告诉PIC你不再要使用BIOS默认值 (请参阅 对PIC芯片进行编程)
  • 为IRQ和异常编写几个ISR处理程序 (请参阅 中断服务例程)
  • 将ISR处理程序的地址放在适当的描述符中 (在 中断描述符表 中)
  • 在 (PIC的) IRQ掩码中启用所有支持的中断

通用IBM-PC兼容中断信息

标准 ISA 中断请求

IRQ 描述
0 可编程中断定时器中断
1 键盘中断
2 级联 (两个芯片内部使用。不会发起)
3 串口COM2 (如果开启)
4 串口COM1 (如果启用)
5 并口LPT2(如果启用)
6 软盘
7 并口LPT1 / 通常是“伪”中断(不可靠)
8 CMOS实时时钟(如果开启)
9 自由外设/legacy SCSI/网卡
10 自由外设/SCSI/网卡
11 自由外设/SCSI/网卡
12 PS2鼠标
13 FPU/协处理器/Inter-processor
14 主ATA硬盘
15 辅ATA硬盘

默认PC中断向量分配

Int 描述
0-31 保护模式异常(Intel保留)
8-15 引导程序中BIOS对IRQ0-7的默认映射
70h-78h 引导时BIOS对IRQ8-15的默认映射

Ports

Port 描述
20h & 21h 主PIC的控制/屏蔽端口
A0h & A1h 从PIC的控制/屏蔽端口
60h 键盘控制器的数据端口
64h 键盘控制器的命令端口-用于启用/禁用kbd中断等。

S390中断

根据指令上下文识别S390体系结构上的异常。

外部中断(External Interrupt)

当CPU计时器或外部设备触发所述中断时,产生外部中断。

主管调用中断(Supervisor Call Interrupt)

主管调用生成一个中断,该中断将当前的 PSW 放入 FLCSOPSW (服务旧PSW)。 然后从 FLCSNPSW (服务新PSW) 加载新的PSW。 SVC代码的位置放在 FLCESICODE

输入/输出中断(Input/Ouput Interrupt)

当设备完成命令程序的执行时,通常会触发此中断。

程序检查异常(Program Check Exception)

当访问无效地址或执行无效指令时,将识别程序异常。

规格例外(Specification Exception)

通常在指令的给定参数或寄存器无效时产生。

机器检查异常(Machine Check Exception)

当部分设备报告故障时产生。 通常意味着所述设备应该被更换,这取决于用户自己。

另见

文章

论坛主题

外部链接