文章目录
- 概述
- 中断与异常
- 中断
- 可屏蔽中断与不可屏蔽中断(NMI)
- 异常
- 异常分类
- 中断与异常向量
- 中断描述符表
- 中断描述符
- 中断与异常处理
- 中断与异常处理过程
- 堆栈切换
- 错误码
- 64位模式下的中断异常处理
- 64位中断描述符
- 64位处理器下的堆栈切换
- 相关参考
概述
中断是现代计算机普遍使用的一种机制,主要用于通知系统中出现了某一个事件,该事件需要处理器暂停当前的任务并进行处理。通常,当收到中断时,处理器会自动将当前正在执行的任务挂起,并运行中断处理程序;当处理器程序执行完毕后,处理器恢复并继续执行之前被中断的任务。
中断与异常
Intel处理器提供了两种中断程序执行的机制,分别称为中断和异常:
- 中断:中断发生在程序执行的任意时刻,以响应硬件发出的信号。系统硬件使用中断来处理外部事件,例如要求为外部设备提供服务;
- 异常:异常发生在处理器执行一条指令时,检测到一个出错条件,例如被0除出错时发生。处理器能够检测到各种出错条件,包括违反保护机制、页错误以及内存错误等。
由于中断是其它硬件信号按照处理器时钟信号随机产生的,也称为异步中断;而异常只有在一条指令终止执行后CPU才会发生中断,也称为同步中断。
中断
Intel处理器接收的中断来自于以下两种方式:
- 外部(硬件产生)中断:外部中断通过处理器上的引脚(INTR或NMI)或本地APIC接收;
- 软件中断:
int n
指令允许通过提供中断向量号作为指令操作数从软件内生成中断,典型的用例就是linux的系统调用,其通过指令int $0x80
向用户程序提供访问系统服务的接口。
可屏蔽中断与不可屏蔽中断(NMI)
通过处理器INTR引脚或通过本地APIC传递给处理器的任何外部中断都称为可屏蔽硬件中断,通过配置标志寄存器中IF标志可以实现对这类中断的屏蔽:
- 当IF标志被设置时,传送到INTR或通过本地APIC引脚的中断被处理为正常的外部中断;
- 当IF标志清除时,处理器禁止传送到INTR引脚或通过本地APIC的中断产生内部中断请求。
而对于不可屏蔽中断(NMI)则不受标志寄存器中IF标志影响,其通常来自于以下两种方式:
- 外部硬件通过处理器NMI引脚发送的中断;
- 处理器通过系统总线或者APIC使用NMI模式传递的信息。
另外,使用int n
指令在软件中产生的中断也不能被EFLAGS寄存器中的IF标志屏蔽。
异常
Intel处理器接收的异常来自于以下三种方式:
- 处理器检测到的程序错误异常:处理器在操作系统或应用程序执行期间,如果检测到程序错误,就会生成一个或多个异常;
- 软件生成的异常:INTO、INT 3和BOUND指令允许在软件中生成异常,这些指令会检查指令执行过程中指定点的异常情况,例如,INT 3指令会导致生成断点异常;
- 机器检查异常:当检测到机器检查错误时,处理器会发出机器检查异常信号(向量号18)并返回错误码。
异常分类
根据异常被报告的方式以及触发异常的指令是否能够被重新执行而不会丢失任务的连续性,异常可被细分成故障(Fault)、陷阱(Trap)和中止(Abort):
- Fault:Fault是通常可以被纠正的异常,并且一旦被纠正程序就可以继续执行。当出现Fault时,处理器将机器状态恢复到产生Fault的指令之前的状态,而Fault处理程序的返回地址会指向产生Fault的指令,而不是其后面一条指令,因此返回后Fault指令会被重新执行;
- Trap:Trap是一种引起陷阱的指令被执行后会立即报告的异常。Trap允许继续执行任务或程序而不丢失连续性。Trap处理程序的返回地址指向产生Trap的指令后的下一条指令;
- Abort:Abort是一种不会总是报告导致Abort的指令确切位置的异常,并且不允许导致异常的任务或程序重新继续执行。Abort用于报告严重错误,例如硬件错误以及系统表中的不一致或非法值。
中断与异常向量
Intel处理器将每个需要被处理器进行特殊处理的异常和中断条件都赋予了一个标识号,称为向量,用于唯一索引中断描述符表IDT中的描述符表项。Intel处理器允许的向量号范围是0~255,其中0~31的向量号保留用作处理器定义的中断和异常,32~255的向量号用于用户定义的中断。下表给出了Intel处理器定义的中断和异常的向量分配:
向量号 | 助记符 | 描述 | 类型 | 错误号 | 触发源 |
---|---|---|---|---|---|
0 | #DE | 除法错误 | 故障 | 无 | DIV或IDIV指令 |
1 | #DB | 调试异常 | 故障/陷阱 | 无 | 指令、数据或IO断点;单步调试等 |
2 | – | NMI中断 | 中断 | 无 | 不可屏蔽外部中断 |
3 | #BP | 断点 | 陷阱 | 无 | INT 3指令 |
4 | #OF | 溢出 | 陷阱 | 无 | INTO指令 |
5 | #BR | 越界 | 故障 | 无 | BOUND指令 |
6 | #UD | 未定义操作码 | 故障 | 无 | UD2指令或保留的操作码 |
7 | #NM | 设备不存在 | 故障 | 无 | 浮点或WAIT/FWAIT指令 |
8 | #DF | 双重错误 | 异常终止 | 有 | 任何可产生异常、NMI或INTR的指令 |
9 | – | 协处理器段越界(保留) | 故障 | 无 | 浮点指令 |
10 | #TS | 无效的任务状态段TSS | 故障 | 有 | 任务切换或访问TSS |
11 | #NP | 不存在的段 | 故障 | 有 | 加载段寄存器或访问系统段 |
12 | #SS | 堆栈段错误 | 故障 | 有 | 堆栈操作和SS寄存器加载 |
13 | #GP | 一般保护错误 | 故障 | 有 | 任何内存引用和其它保护检查 |
14 | #PF | 页面错误 | 故障 | 有 | 任何内存引用 |
15 | – | Intel保留 | NA | 无 | NA |
16 | #MF | x87 FPU浮点错误 | 故障 | 无 | x87 FPU浮点或WAIT/FWAIT指令 |
17 | #AC | 对齐检查 | 故障 | 有 | 对内存中任何数据的引用 |
18 | #MC | 机器检查 | 异常终止 | 无 | 与CPU类型有关 |
19 | #XF | SIMD浮点异常 | 故障 | 无 | SSE和SSE2浮点指令 |
20-31 | – | Intel保留 | NA | NA | NA |
32-255 | – | 用户定义中断 | 中断 | 外部中断或者INT n指令 |
中断描述符表
中断描述符表(IDT)包含了一个中断描述符的数组,每个中断描述符与特定的中断或异常向量对应,并指定了相关的中断处理例程。IDT中最多可包含256个描述符,处理器使用IDTR寄存器保存IDT表的位置。
中断描述符
中断描述符表包含3种类型的门描述符:
- 任务门描述符:任务门描述符格式与GDT和LDT中任务门的格式相同,包含一个任务TSS段的选择符,该任务用于处理中断和异常;
- 中断门描述符:中断门描述符包含指向中断异常处理过程的指针,中断触发时,处理器跳转到对应的中断异常处理程序的入口并执行;
- 陷阱门描述符:陷阱门描述符包含的信息与中断门相通,唯一区别在于,通过陷阱门执行中断异常处理程序不会操作标志寄存器中的IF标志。
Intel 32位处理器中定义的中断描述符格式如下:
中断与异常处理
处理器对中断和异常处理过程的调用方法与使用Call指令调用程序过程的方法类似。当响应一个中断或异常时,处理器使用中断或异常向量作为中断描述符表中的索引,执行对应的中断异常处理程序或任务。
中断与异常处理过程
当处理器调用异常或中断处理程序时:
- 如果处理程序程序将以低特权级执行,则会发生堆栈切换。发生堆栈切换时:
- 从当前执行任务的TSS中获取处理程序要使用的堆栈的段选择器和堆栈指针。在这个新堆栈上,处理器推送中断过程的堆栈段选择器和堆栈指针。
- 然后处理器将EFLAGS、CS和EIP寄存器的当前状态保存在新堆栈上,见下图;
- 如果异常导致保存错误代码,则将其推送到EIP值之后的新堆栈上。
- 如果处理程序程序将以与中断程序相同的权限级别执行:
- 处理器将EFLAGS、CS和EIP寄存器的当前状态保存在当前堆栈上,见下图;
- 如果异常导致保存错误代码,则在EIP值之后将其推送到当前堆栈上。
堆栈切换
处理器在执行中断异常处理程序时,在特权级不变和特权级发生改变的情况下,堆栈切换过程如下:
错误码
当异常条件与一个特定的段相关时,处理器会把一个错误码压入到异常处理过程的堆栈上,错误码的格式如下:
错误码包含一个段选择符以及3个标志位,其中3个标志位的作用如下:
- EXT:External event(bit 0),当设置时,表示在程序外部事件的传递过程中发生异常;
- IDT:Descriptor location(bit 1),当设置时,表示错误码的索引部分引用IDT中一个门描述符;当清除时,表示索引指向GDT或LDT中的一个段描述符;
- TI:GDT/LDT(bit 2),仅在IT标志清除时有效。当设置时,TI标志表示错误码的索引指向LDT中一个描述符;当清除时,则索引指向GDT中的描述符。
64位模式下的中断异常处理
64位模式下,中断与异常处理过程和非64位模式类似,差异点如下:
- IDT指向的所有中断处理程序入口地址使用64位;
- 中断堆栈推送的大小固定为64位;处理器使用8字节零扩展存储。
- 堆栈指针(SS:RSP)在中断时被无条件保存到新堆栈中。在传统模式中,会基于当前特权级别(CPL)的变化,处理过程不同;
- 如果CPL发生变化,则新SS设置为NULL;
- IRET行为变化;
- 有一种新的中断堆栈切换机制;
- 中断堆栈帧的对齐方式不同。
64位中断描述符
Intel 64位处理器下只定义了中断描述符和陷阱描述符,对应格式描述如下:
64位处理器下的堆栈切换
相关参考
- 《Linux内核完全注释》
- 《Intel处理器手册》