中断和异常,感觉是特别容易混淆的两个名词。在《深入理解计算机系统》一书,作者将中断归为异常中的一种(另外三种异常是陷阱、故障和终止);而在《32 位微型计算机接口技术及应用》一书,作者则将异常归为中断中的一种,区分标准是中断从处理器外部硬件还是内部处理器产生,从处理器外部硬件产生的中断是中断,从内部处理器产生的中断是异常。
但通过对这两书的陈述,除了处理分类上有点不一样,内容基本还是差不多的。在具体的分类上,IBM 的一篇博文 Linux 内核中断内幕说的更为清晰明了:
- 中断可分为同步(synchronous)中断和异步(asynchronous)中断:
- 同步中断是当指令执行时由 CPU 控制单元产生,之所以称为同步,是因为只有在一条指令执行完毕后 CPU 才会发出中断,而不是发生在代码指令执行期间,比如系统调用。
- 异步中断是指由其他硬件设备依照 CPU 时钟信号随机产生,即意味着中断能够在指令执行之间发生,例如键盘中断。
- 根据 Intel 官方资料,同步中断称为异常(exception),异步中断被称为中断(interrupt)。
- 中断可分为可屏蔽中断(Maskable interrupt)和非屏蔽中断(Nomaskable interrupt)。异常可分为故障(fault)、陷阱(trap)、终止(abort)三类。
- 从广义上讲,中断可分为四类:中断、故障、陷阱、终止。
下文中,我们用中断来表示外部中断,异常表示内部中断。关于中断和异常,《深入理解计算机系统》有一个简要的总结:
中断和异常
这部分参考自《深入理解计算机系统》第 8.1 节“异常”。
中断
中断是异步发生的,是来自处理器外部的 I/O 设备的信号的结果。下图展示了中断的处理过程:
陷阱
陷阱是有意的(intentional)异常,是执行一条指令的结果。陷阱最重要的用途是在用户程序和内核之间提供一个像过程一样的接口,即系统调用。
用户程序经常需要向内核请求服务,比如读一个文件(read)、创建一个新的进程(fork)、加载一个新的程序(execve)、终止当前进程(exit)。为了允许对这些内核服务的受控的访问,处理器提供了一条特殊的syscall n
指令。当用户程序想要请求服务n
时,可以执行这条指令。执行syscall
指令会导致一个到异常处理程序的陷阱,这个处理程序对参数解码,并调用适当的内核程序。下图概述了一个系统调用的处理过程:
故障
故障由错误情况引起,它可能能够被故障处理程序修正。一个经典的故障就是缺页异常
。
当故障发生时,处理器将控制权转移到故障处理程序。如果故障处理程序能够修正这个错误情况,它就将控制返回到引起故障的指令,从而重新执行它。否则,处理程序返回到内核中的abort
例程,abort
例程会终止引起故障的应用程序。下图概述了一个故障的处理过程:
终止
终止是不可恢复的致命错误造成的结果,通常是一些硬件错误,比如 DRAM 或者 SRAM 位被顺坏时发生的奇偶错误。终止处理程序从不将控制返回给应用程序。如下图所示,处理程序将控制返回给一个abort
例程,该例程会终止这个应用程序:
实模式下中断向量与中断向量表
实模式下,
中断服务程序的入口地址就是中断向量 IV(Interrupt Vector)。
而中断服务程序的入口地址由CS:IP
来表示,CS
和IP
在实模式下均为 16 位长。一个中断向量的格式如下:
实模式下,
中断向量表 IVT(Interrupt Vector Table)用来存放总共 256 个中断向量,每个中断向量 4 个字节长,整个表占用内存 0000H~03FFH 的区域。
中断向量表的格式如下:
对一个中断号为 Nr 的中断,它代表的中断向量在中断向量表的位置为:
IP 在中断向量表的位置: 0000 + Nr * 4 (十进制,按需转换成十六进制)
CS 在中断向量表的位置: IP + 2 (十进制,按需转换成十六进制)
- 关于每个中断向量的意义可参照下表:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24IVT Offset | INT # | Description
-----------+-----------+-----------------------------------
0x0000 | 0x00 | Divide by 0
0x0004 | 0x01 | Reserved
0x0008 | 0x02 | NMI Interrupt
0x000C | 0x03 | Breakpoint (INT3)
0x0010 | 0x04 | Overflow (INTO)
0x0014 | 0x05 | Bounds range exceeded (BOUND)
0x0018 | 0x06 | Invalid opcode (UD2)
0x001C | 0x07 | Device not available (WAIT/FWAIT)
0x0020 | 0x08 | Double fault
0x0024 | 0x09 | Coprocessor segment overrun
0x0028 | 0x0A | Invalid TSS
0x002C | 0x0B | Segment not present
0x0030 | 0x0C | Stack-segment fault
0x0034 | 0x0D | General protection fault
0x0038 | 0x0E | Page fault
0x003C | 0x0F | Reserved
0x0040 | 0x10 | x87 FPU error
0x0044 | 0x11 | Alignment check
0x0048 | 0x12 | Machine check
0x004C | 0x13 | SIMD Floating-Point Exception
0x00xx | 0x14-0x1F | Reserved
0x0xxx | 0x20-0xFF | User definable
保护模式下中断描述符与中断描述符表
请参考之前博文 Linux 内核学习笔记:预备知识之“存储器管理基础”。