异常和中断的分类

上一节把事件分成了异常和中断两大类。这一节把每一类再往下切一层。

切分的依据不是”事件本身像什么”,而是”处理完之后回到哪里”。 这个视角一旦立住,五个子类的名字就不必硬背了——它们是按返回地址的三种可能反推出来的分类。

机制

异常的三个子类

子类什么时候发生处理完之后典型
故障 Fault指令执行过程中发现问题,问题可能被修复重新执行当前这条指令缺页、除零、段错误、非法操作码
自陷 Trap指令有意触发,本身就是为了进内核执行下一条指令系统调用 INT n / syscall、断点 INT 3、单步调试
终止 Abort硬件出了无法恢复的错不返回,程序(甚至系统)终止校验错、总线错、机器检查

三个子类恰好对应”返回地址”的三种可能:当前指令、下一条指令、不返回。 这就是本节开头说的反推。

故障为什么要重新执行当前指令,用缺页解释最清楚:MOV EAX, [ADDR] 执行到一半发现 ADDR 所在的页不在内存,于是触发缺页故障;操作系统把页调进来(OS 3.2.2),然后必须让这条 MOV 重来一遍——因为它上次根本没取到数。若返回到下一条,这次访存就永久丢失了。

Fault能否修复后重执行常见处理
缺页通常能调页后重执行
除零通常不能自然修复终止/抛异常
非法操作码通常不能终止,也可能软件模拟
保护异常视原因而定修复或终止

自陷为什么返回下一条:INT 0x80 的语义就是”我要进内核办件事”,办完了当然继续往下走。它的行为和 CALL 极像——区别只在于它同时切换了特权级(OS 1.3.1)。

这里有一个必须点破的不对称:故障和自陷都由当前指令引起,但保存的断点不同。

故障:断点当前指令地址自陷:断点下一条指令地址

而 5.2.2 说过,PC 在取指周期就已经自增,所以硬件手里现成的那个值是”下一条”。于是:

  • 自陷:直接存 PC 的当前值即可,硬件不用做额外的事
  • 故障:必须把 PC 回退到当前指令的开头再保存——这需要硬件额外记住”当前指令有多长”或”当前指令的起始地址”

“故障要回退 PC”是本节最容易被忽略的一处实现代价,而它在变长指令集(4.1.4)上尤其麻烦:指令长度不定,回退多少字节不是常数,所以 x86 需要专门保存当前指令的起始地址。这是定长指令的又一个隐性好处。

中断的两个子类

子类能否被屏蔽走哪根线典型
可屏蔽中断能——CPU 关中断(IF=0)或设备被屏蔽时不响应INTR键盘、磁盘、打印机、时钟
不可屏蔽中断 NMI不能——任何情况下都响应NMI电源掉电、内存校验错、严重硬件故障

NMI 存在的理由是时间:掉电后靠电容供电只剩几毫秒,必须立刻保存现场,没有等待”开中断”的余地。所以它绕过 IF 这道总闸,直接进。

NMI 与可屏蔽中断走的是两根不同的物理引脚——这一点决定了它们的判优不在同一个队列里:NMI 的优先级永远高于任何可屏蔽中断,不需要参与排队。

完整分类表

事件异常(内中断,同步)故障重执行当前指令自陷执行下一条终止不返回中断(外中断,异步)可屏蔽中断()不可屏蔽中断()

中断(外中断)的返回位置只有一种:下一条指令。 因为它是在指令边界响应的,当前指令已经完整执行完了。

硬件与软件的分工

这张表在选择题里出现的频率极高,尤其是”下列哪些由硬件完成”这类问法。

阶段做什么谁做
检测每条指令末尾查中断请求线;执行中检查异常条件硬件
响应关中断、保存断点(PC)、保存 PSW、转入口地址硬件(中断隐指令)
保存现场保存通用寄存器软件(服务程序开头)
判断中断源确定是哪个设备 / 哪种异常硬件(向量方式)或软件(查询方式)
具体处理读扫描码、调页、打印错误……软件
恢复现场恢复通用寄存器软件
返回IRET 恢复 PC 和 PSW、开中断软件发起,硬件完成

分界线在”保存断点”与”保存现场”之间,这两个词只差一个字,含义完全不同:

断点 = PC + PSW,由硬件保存——不保存它,程序回不来 现场 = 通用寄存器,由软件保存——不保存它,程序回来了但数据乱了

为什么硬件不顺手把通用寄存器也存了? 因为不知道要存多少。中断服务程序可能只用两个寄存器,全存 32 个是浪费;而且不同 ISA 的寄存器数量不同,硬件把这件事交给软件,正是 ISA 抽象的一部分(4.3.4 里 caller/callee-saved 的划分是同一个思路:让软件按需决定存哪些)。

与操作系统的接口

跨到 OS 那边,这套分类原样复用,只是关注点变了:

CO 关心OS 关心
硬件怎样夺走控制权夺走之后由哪段内核代码接手
断点保存在哪进程的上下文保存到 PCB 的哪个字段
故障要重执行重执行前要把缺的页调进来
自陷返回下一条系统调用号怎样分发到具体的服务例程

三个必须记住的对应:

  • 系统调用 = 自陷类异常(OS 1.3.3)
  • 缺页 = 故障类异常(OS 3.2.2)
  • 时钟中断 = 可屏蔽中断,它是进程调度得以发生的硬件基础(OS 2.1.3)——没有时钟中断,一个死循环的用户程序就能永久占住 CPU

最后这一条值得停一下:抢占式调度之所以可能,完全是因为有一个 CPU 无法拒绝的外部事件在定期打断它。 这是”中断”这个机制对操作系统最根本的贡献,比 I/O 通知重要得多。

边界

层次辨析:故障 / 自陷 / 终止

判据是返回到哪:

  • 故障 → 重新执行当前指令(缺页、除零)
  • 自陷 → 执行下一条(系统调用、断点)
  • 终止 → 不返回(硬件故障)

反推记法:三个子类就是”返回地址的三种可能”。

边界辨析:断点 / 现场

  • 断点 = PC + PSW,硬件在中断隐指令中保存
  • 现场 = 通用寄存器,软件在服务程序开头保存

高频选择题:“下列由硬件完成的是”——答关中断、保存断点、转入口地址,不含保存通用寄存器。

边界辨析:可屏蔽 / 不可屏蔽

  • 可屏蔽(INTR):受 IF 和设备屏蔽位控制,可以被暂时挡住
  • 不可屏蔽(NMI):任何情况下都响应,优先级最高,不参与排队

NMI 的理由是时间紧迫(掉电只剩几毫秒),不是”更重要”这种模糊说法。

边界辨析:自陷是异常,不是中断

系统调用由指令主动触发,内部、同步、可复现——三条判据全指向异常。

“主动触发”不构成把它算作中断的理由。中文里”软中断”这个叫法是历史遗留,容易误导。

对照速查

事件类别返回到
缺页异常 - 故障当前指令
除数为 0异常 - 故障当前指令
非法操作码异常 - 故障当前指令
系统调用异常 - 自陷下一条
断点 INT 3异常 - 自陷下一条
校验错 / 总线错异常 - 终止不返回
键盘、磁盘、时钟中断 - 可屏蔽下一条
掉电中断 - NMI一般不返回
由硬件完成由软件完成
检测、关中断保存现场(通用寄存器)
保存断点(PC、PSW)判断中断源(查询方式时)
转中断服务程序入口具体处理
判断中断源(向量方式时)恢复现场、发起 IRET

考点

  • 给事件判子类 + 返回位置:本节最稳定的题型,靠上面那张速查表。
  • “下列哪些由硬件完成”:答关中断、保存断点、送入口地址。保存通用寄存器是软件做的。
  • 故障与自陷的断点差异:故障存当前指令地址,自陷存下一条。
  • NMI 的特点:不可屏蔽、优先级最高、走独立引脚、用于掉电等紧急故障。
  • 系统调用的归类:异常中的自陷。
  • 时钟中断与抢占式调度的关系:跨科高频,见 OS 2.1.3。

链接