x86保护模式-七中断和异常
386相比较之前的cpu 增强了中断处理能力 并且引入了 异常概念
一 80386的中断和异常
为了支持多任务和虚拟存储器等功能,386把外部中断称为中断 把内部中断称为异常
最多支持256中断或异常
1.中断
中断是由异步的外部事件引起的。外部事件及中断响应与正执行的指令没有关系。
通常中断对应i/o操作的完成,cpu中intr引脚接受外部的可屏蔽的中断请求,NMI引脚接受外部不可屏蔽的中断请求。
EFLAGS标志寄存器中的IF标志决定是否屏蔽可屏蔽的中断请求
intr发出中断请求的同时还有一个8位的中断向量。cpu根据向量号来决定下一步的操作。8059a能够设置向cpu提供向量号,处理中断请求的优先级。
8259级联,最多可用 1片主帖+8片从片, 每片从片有8个外部中断请求IR0~IR7,
主片的IR0~IR7引脚分别连接8个从片的INT引脚。最多可有 8x8=64个外部中断请求。
cpu不屏蔽来自NMI的中断请求,响应NMI中断时,不从外部硬件接收中断向量号。固定的向量号为2 。为了不可屏蔽的嵌套,每当接受一个NMI中断,cpu就在内部屏蔽了再次响应NMI,这一屏蔽过程直到执行中断返回指令IRET后才结束。
所以NMI处理程序应该以IRET指令结束。
2.异常
异常时80386在执行指令期间检测到不正常的或非法的条件所引起的。与正在执行的指令有直接的联系。
例如 除法指令 除数等于0时。特权级不正确,指令不能成功完成。
软中断指令“INT n”和“INTO”也归类于异常而不称为中断,是因为执行这些指令产生异常事件。
386识别多种不同类别的异常,并且赋予每一种类别以不同的中断向量号。异常发生后,cpu响应异常,根据向量号转到相应的异常处理程序。
根据引起异常的程序是否可被恢复和恢复点不同,把异常分类为故障fault,陷阱trap和中止abort。我们把对应的异常处理程序分别称为故障处理程序、陷阱处理程序和中止处理程序。
故障是在引起异常的指令之前,把异常情况通知给系统的一种异常。故障是可以排除的。当控制转移到故障处理程序时,所保存的断点cs及eip的值指向引起故障的指令。这样,在故障处理程序把故障排除后,执行IRET返回到引起故障的程序继续执行时,刚才引起故障的指令可重新得到执行。
这种重新执行,不需要操作系统软件的额外参与。故障的发先可能在指令执行之前,也可能在指令执行期间。
如果在指令执行期间检测到故障,那么中止故障指令,并把指令的操作数恢复为指令开始执行之前的值。这可保证故障指令的重新执行得到正确的结果。
例如,一条指令执行期间,发现段不存在,那么就停止该指令的执行,并通知系统产生段故障,对应的段故障处理程序可通过加载该段的方法来排除故障,之后,原指令就可以成功执行,至少不再发生段不存在的故障。
陷阱是在引起异常的指令后,把异常情况通知给系统的一种异常。当控制转移到异常处理程序时,所保存的断点cs及eip的值指向引起陷阱的指令的下一条要执行的指令。下一条要执行的指令,不一定就是下一条指令(例如call 指令)。因此陷阱处理程序并不能总根据保存的断点,反推确定出产生异常的指令。在转入陷阱处理程序时,引起陷阱的指令应正常完成,它有可能改变了寄存器或存储单元。
软中断指令、单步异常是陷阱的例子。
中止是在系统出现严重情况时,通知系统的一种异常。引起中止的指令是无法确定的。产生中止时,正执行的程序不能被恢复执行。系统接收中止后,处理程序要重新建立各种系统表格,并可能重新启动操作系统。硬件故障和系统表中出现非法值或不一致的值是中止的例子
3.优先级在一条指令执行期间,入检测到不只一个中断或异常,那么按下边所列优先级通知系统。把优先级最高的中断或异常通知系统,其他优先级较低的异常被废弃,而优先级较高的中断则保持悬挂
二 异常的类型
中断和异常一样都分为多种类型
1.386识别的异常
多种不同类别的异常及赋予的对应中断向量号如下表所示。
某些异常还可以出错码的形式提供一些附加信息传递给异常处理程序,出错代码列表中的“无”表示没有出错代码,“有”表示有出错代码。
保护模式下的某些中断向量号的分配与实模式的中断向量号发生冲突。实模式下的中断向量号的分配基于pc微机系统的8086/8088cpu,上表中的中断向量号的分配是80386所规定的。实际上8086/8088 保留了这些发生冲突的中断向量号。尽管有冲突,80386需要向下兼容,原因是80386的实模式下,几乎不发生哪些中断向量号与外部硬件中断请求时所提供的中断向量号存在冲突的异常。需要注意的是,在保护模式下必须重新设置8259a中断控制器,以产生不予异常相冲突的硬件中断向量。
2.故障类异常
当发生故障,控制转移到故障处理程序时,所保存的断点cs及eip的值指向引起故障的指令,以便在排除故障后恢复执行
a 除法出错故障 异常0
除法出错时一种故障。当执行DIV指令或IDIV指令时,如果除数等于0或者商太大,以至于存放商的操作数容纳不下
此故障没有出错码
b 边界检查故障 异常5
如果BOUND指令发现被测试的值超过了指令中给定的范围,那么就发生边界检查故障。无出错码
c 非法操作码故障 异常6
如果386不能把cs和eip所指向存储单元的位模式识别为某条指令的部分,那么就发生非法操作码故障。当出现如下情况时 发生这样的故障 cs:ip指向的位置不是指令
(1)操作码字段的内容不是一个合法的386指令代码
(2)要求使用存储器操作数的场合,使用了寄存器操作数
(3)不能被加锁的指令前使用了LOCK前缀。
非法操作码故障不提供错误码
d 设备不可用故障(异常7)
不支持387协处理器,可用该异常的处理程序代替协处理器的软件模拟器。发生任务切换时,使得只有在新任务使用浮点指令时,才进行387寄存器状态的切换。设备不可用故障不提供出错码。
(1)执行浮点指令时,cr0中em位或ts位为1。
(2)执行wait指令时,cr0中的ts位及em位都为1。
(3)异常的处理程序必须是一个程序而不是任务,否则当处理程序发布一条IRET指令时,80386就设置ts位。然后协处理器再次执行这个发生故障的指令,发现ts是置位的。因此再次发生异常7,结果就是死循环。处理程序能通过陷阱门被调用,因为执行期间可以允许中断
e 无效tss故障 (异常0ah)
当正从任务状态段tss装入选择子时,如果发生了除了段不存在外的段异常时,就发生此故障。
1进入故障处理程序时,保存的cs及eip指向发生故障的指令
2或者该故障作为任务切换的一部分发生时,指向任务的第一条指令
3提供出错码
其中选择子部分指向引起故障的tss的选择子。16位的出错码的主要成分是选择子,指向引起故障的tss的选择子。高13位是选择子的索引部分,TI位是描述符表指示位。
上图为异常出错码的一般格式。从途中可见出错码不含选择子的rpl 而由IDT位和EXT位代替。当处理某一异常或外部中断时,又发生了某种异常,那么EXT位置1.当从中断描述符表IDT中读出表项并产生异常时,IDT位置1,这只在中断或异常的处理期间才会发生。当没有选择子时,构成出错码选择子部分的值为0。
4.引起无效tss故障的原因如下
a tss描述符中的段限长小于103
b 无效的LDT描述符,或者LDT未出现
c 堆栈段不是一个可写段
d 堆栈段选择子索引的描述符超出描述符表界限
e 堆栈段DPL与新的cpl不匹配;
f 堆栈段选择子的rpl不等于cpl
g 代码段选择子索引的描述符超出描述符表界限
h 代码段选择子不指向代码段
i 非一致代码段的dpl不等于新的cpl
j 一致代码段的dpl大于新的cpl
k 对应ds es fs 或gs的选择子指向一个不可读的段,例如系统段
l 对应ds es fs 或gs的选择子索引的描述符超出描述符表的界限
f 段不存在的故障(异常0bh)
处理器在把描述符装入非ss寄存器的高速缓冲时,如果发现描述符其他方面有效,而p位为0表示(对应段不存在),那么在引用此描述符时就发生段不存在故障。有关ss段的情形纳入堆栈段故障。在进入故障处理程序时,保存的cs及eip执行发生故障的指令;或者该故障作为任务切换的一部分发生时,指向任务的第一条指令。
段不存在故障提供了一个包含引起该故障的段选择子的出错代码。出错码的格式如上图所示。选择子索引部分为引起段不存在故障的段描述符选择子的索引。
g 堆栈段故障(异常0ch)
cpu检测到用ss寄存器进行寻址的段有关的某种问题时,就发生堆栈段故障。在进入故障处理程序时,保存的cs级eip指向发生故障的指令;或者该故障作为任务切换的一部分发生时,指向任务的第一条指令。堆栈段故障提供一个出错码,出错码的格式也如上如所示
引起堆栈段故障的原因
(1)堆栈操作时,偏移超出段界限所规定的范围。这种情况下的出错码是0.例如PUSH操作时,堆栈溢出。
(2)在由特权级变换所引起的对内层堆栈操作时,偏移超出段界限所规定的范围。这种情况下的出错码包含有内层堆栈的选择子。
(3)装入到ss寄存器(高速缓冲寄存器)的描述符中的存在位为0.这种情况下的出错码包含有对应的选择子。
第一中情况容易辨别。第2和3中情况的辨别需要通过判断出错码所含的选择子所指示的描述符中的存在位进行,如果存在位为1,那么是第二种情况,否则是第三种情况。
h 通用保护故障(异常0dh)
除了明确列出的段异常外,其他的段异常都被视为通用保护故障。在进入故障处理程序时,保存的cs及eip指向发生故障的指令;或者该故障作为任务切换的一部分发生时,指向任务的第一条指令。通用保护故障提供一个出错码,出错码的格式也如上图所示。
根据处理程序可能作出的响应,通用保护故障可分为如下两类:
(1)违反保护方式,但程序无须中止的异常。此类故障的出错码为0.这种异常在应用程序执行特权指令或I/O访问呢时发生,支持虚拟8086程序的系统或支持虚拟i/o访问的系统需要模拟这些指令,并在模拟完成产生故障的指令后,重新执行被中断的程序。
(2)违反保护方式,并导致程序终止的异常。这类故障提供的出错码可能为0 ,也可能不是0(能确定选择子时)。引起此类的故障原因
a 向某个只读数据段或代码段写;
b 从某个智能执行的代码段读出;
c 将某个系统段描述符装入到数据段寄存器ds、es、fs、gs或ss;
d 将控制转移到一个不可执行的段;
e 在通过段寄存器cs、ds、es、fs或gs访问内存时,偏移超出段界限
f 当访问某个描述符表时,超过描述符表段界限;
把pg位为1但pe位为0的控制信息装入到cr0寄存器;
切换到一个正忙的任务。
对上述两类通用保护故障的辨别,可通过检查引起故障的指令和出错码进行。如果出错码非0,那么肯定是第二类通用保护故障。如果
出错码是0,那么需要进一步检查引起故障的指令,以确定它是否是系统支持的可以模拟的指令。
i 页故障 异常0eh 略
j 协处理器出错 异常10h
协处理器出错故障指示协处理器发生了未被屏蔽的数字错误,如上溢或下溢。在引起故障的浮点指令之后的下一条浮点指令
或WAIT指令,把协处理器出错作为一个故障通知给系统。协处理器出错故障不提供出错码。
3.陷阱类异常
a 调试陷阱 异常1
调试异常有故障类型,也有陷阱类型。调试程序可以访问调试寄存器dr6 以确定调试异常的原因和类型。调试异常不提供出错码。
b 单字节 INT3 异常3
INT3是一条特别的单字节 INT n 指令 ,调试程序可利用该指令支持程序断点。INT3指令被看成是一种陷阱。而不是一个中断。当由于执行INT3指令进入异常3处理程序时,被保存的cs和eip指向紧跟INT3的指令,即INT3后面的字节。INT3陷阱不提供出错码。
c 溢出 异常4
INTO指令提供条件陷阱。如果OF标志为1,那么INTO指令产生陷阱;否则不产生陷阱,继续执行INTO后面的指令。在进入溢出处理程序时,被保存的cs和eip指向INTO指令的下一条指令。溢出陷阱不提供出错码。
4.中止类异常
a 双重故障异常 异常8
当系统正在处理一个异常时,如果又检测到一个异常,处理器试图向系统通知一个双重故障,而不是通知第二个异常。双重故障属于中止类异常,所以在转入双重故障处理程序时,被保存的cs和eip可能不指向引起双重故障的指令,而且指令的重新启动不支持双重故障。 出错码为0
当正处理一个段故障异常时,有可能又产生一个页故障。在这种情况下,通知给系统的是一个页故障异常而不是双重故障异常。但是,如果正处理一个段故障或页故障时,又一个段故障被检测到;或者如果正处理一个页故障时,又一个页故障被检测到,那么就引起双重故障。
当正处理一个页故障时,又一个段或页故障被检测到,那么处理器暂停执行指令,并进入关机方式。关机方式类似于处理器指令一条HLT指令后的状态:处理器空转,并维持到处理器接收到一个NMI中断请求或者被重新启动为止。在关机方式下,处理器不响应INTR中断请求。
双重故障通常指示系统表出现严重的问题,例如段描述符表、页表或中断描述符表出现问题。双重故障处理程序在重建系统表后,可能不得不重新启动操作系统。
b 协处理器段越界 异常9
协处理器段越界异常属于中止类异常,这是因为引起该异常的指令不能被重新启动。但更浮点指令操作数超出段界限时,产生该中止异常。协处理器段越界异常不提供出错码。在异常处理程序入口保存的cs及eip指向被中止的指令。这种中止不是系统的中止,而是只影响到这种异常时正执行的指令所在的程序。
三 中断和异常的转移方法