前言:我们开始操作系统中又两个重要的概念:「异常」和「中断」
本质
异常和中断的本质其实是一样的:
发生异常(exception)和中断(interrupt)事件后,系统将进入 OS 内核态对相应事件进行处理
说到底,中断和异常确实不是相同的东西。通常说外部中断,内部异常。
接下来我们说说这两者的不同。
异常
异常的分类
我们可以把异常分为三类
-
故障(Fault)
执行指令引起的异常:缺页、越权、越级、溢出、非法指令。断点为故障发生的地方
-
自陷(Trap)
预先安排的事件:调试程序时打的断点,单步跟踪,系统调用。是一种自愿中断。断点为自陷指令的下一条指令
-
终止(Abort)
硬件故障事件,此时机器会终止,调出中断服务程序来终止程序甚至重启操作系统。断点随意!反正我们不执行了
一些思考
-
自陷处理完成后回到哪条指令执行?
自陷指令的下一条指令会执行
-
哪些故障(fault)补救后可继续执行,哪些只好终止当前进程?
缺页、TLB 缺失。补救后可继续,回到发生故障的指令重新执行
异常举例——页故障
-
页故障
是什么时候发生的?执行每条指令都要进行
访存
,在保护模式下,每次访存都要进行逻辑地址到物理地址的转换
,在地址转换过程中会发现是否发现了页故障
-
页故障
是由软件发现还是硬件发现?逻辑地址到物理地址的转换是由 MMU 执行的
,所以所有的页故障都是由硬件发现的。而且所有的异常和中断事件都是由硬件检测法线
以下情况会发生页故障
- 缺页(可恢复)
- 地址越界(不可恢复,称为 segment fault)
- 访问越级或者越权(不可恢复,称为 segment fault)
- 越级:
用户进程访问内核
- 越权:
读写权限不相符
- 越级:
异常举例——自陷
用单步跟踪和设置断点调试程序
- IA-32 中,当 CPU 被处于单步跟踪状态时(TF = 1 && IF = 1 某个寄存器的一部分,后面说),每条指令都被设置成了陷阱指令,执行每条指令后,**都会发生中断类型号为 1 的“调试”异常,从而转去执行“单步跟踪处理程序” **
- IA-32 中,用于程序调试的断点设置陷阱指令为 int 3,对应机器码为 CCH。若调试程序在被调试程序某处设置了断点,则调试程序就在该处“加”一条 int 3 指令(该首字节)。执行到该指令时,会暂停被调试程序的运行,并发出“EXCEPTION_BREAKPOINT”异常,以调出调试程序执行,执行结束后回到被调试程序执行
中断
外设通过中断请求信号线向CPU提出中断请求,不由指令引起
每执行完一条指令,CPU 就查看中断请求引脚,若引脚的信号有效,则进行中断响应:
将当前 PC (断点)和当前机器状态保存到栈中。并关中断。然后,从数据总线读取中断类型号,根据中断类型号跳转到对应的中断服务程序执行。中断检测及响应过程由硬件完成。中断服务程序执行具体的中断处理工作,中断处理完成后,再回到被打断程序的“断点”处继续执行。
也就说说,整个过程如下:
- 保护断点
- 关中断
- 转中断处理
中断的分类
-
可屏蔽中断
通过 INTR 向 CPU 请求,可通过设置屏蔽字来屏蔽请求,若中断请求被屏蔽,则不会被送到CPU
-
不可屏蔽中断
非常紧急的硬件故障,如:电源掉电,硬件线路故障等。通过 NMI 向 CPU 请求。一旦产生,就被立即送 CPU,以便快速处理。这种情况下,中断服务程序会尽快保存系统重要信息,然后在屏幕上显示相应的消息或直接重启系统。
中断相应过程
-
关中断(中断允许位清 0)
使 CPU 处于禁止中断状态,以防止新终端破坏断点(PC),程序状态(PSW)和现场(通用寄存器)
-
保护断点和程序状态
PC→栈 或 EPC(专门存放断点的寄存器)
PSWR →栈 或 EPSWR(专门保存程序状态的寄存器)
-
识别中断事件
有软件识别和硬件识别(向量中断)两种不同的方式
用专门的硬件查询电路按优先级顺序识别异常,得到“中断类型号”,根据此号,到中断向量表中读取对应的中断服务程序的入口地址
所有事件都被分配一个“中断类型号”,每个中断都有相应的“中断服务程序”,可根据中断类型号找到中断服务程序的入口地址。