|
象中断分为多种类型一样,异常也可分为多种类型。
1.80386识别的异常
80386识别的多种不同类别的异常及赋予的对应中断向量号如下表所示。某些异常还以出错码的形式提供一些附加信息传递给异常处理程序,出错代码列中的“无”表示没有出错代码,“有”表示有出错代码。
异
常
一
览
表 |
向量号 |
异常名称 |
异常类型 |
出错代码 |
相关指令 |
| 0 |
除法出错 |
故障 |
无 |
DIV,IDIV |
| 1 |
调试异常 |
故障/陷阱 |
无 |
任何指令 |
| 3 |
单字节INT3 |
陷阱 |
无 |
INT 3 |
| 4 |
溢出 |
陷阱 |
无 |
INTO |
| 5 |
边界检查 |
故障 |
无 |
BOUNT |
| 6 |
非法操作码 |
故障 |
无 |
非法指令编码或操作数 |
| 7 |
设备不可用 |
故障 |
无 |
浮点指令或WAIT |
| 8 |
双重故障 |
中止 |
有 |
任何指令 |
| 9 |
协处理器段越界 |
中止 |
无 |
访问存储器的浮点指令 |
| 0AH |
无效TSS异常 |
故障 |
有 |
JMP、CALL、IRET或中断 |
| 0BH |
段不存在 |
故障 |
有 |
装载段寄存器的指令 |
| 0CH |
堆栈段异常 |
故障 |
有 |
装载SS寄存器的任何指令、对SS寻址的段访问的任何指令 |
| 0DH |
通用保护异常 |
故障 |
有 |
任何特权指令、任何访问存储器的指令 |
| 0EH |
页异常 |
故障 |
有 |
任何访问存储器的指令 |
| 10H |
协处理器出错 |
故障 |
无 |
浮点指令或WAIT |
| 11H—0FFH |
软中断 |
陷阱 |
无 |
INT n |
由上表可见,保护模式下的某些中断向量号的分配与实模式的中断向量号发生了冲突。实模式下的中断向量号的分配基于PC微机系统的8086/8088 CPU,上表中的中断向量号的分配是80386所规定的。实际上,Intel在宣布8086/8088时,保留了这些发生冲突的中断向量号。尽管发生这样的冲突,但以80386为CPU的微机系统仍可保持与以8086/8088为CPU的微机系统的兼容,原因是在80386的实模式下,几乎不发生那些中断向量号与外部硬件中断请求时所提供的中断向量号存在冲突的异常。需要注意的是,在保护模式下必须重新设置8259A中断控制器,以产生不与异常相冲突的硬件中断向量。
2.故障类异常
当发生故障,控制转移到故障处理程序时,所保存的断点CS及EIP的值指向引起故障的指令,以便在排除故障后恢复执行。
(1)除法出错故障(异常0)
除法出错是一种故障。当执行DIV指令或IDIV指令时,如果除数等于0或者商太大,以至于存放商的操作数容纳不下,那么就产生这一故障。除法出错故障不提供出错码。
(2)边界检查故障(异常5)
如果BOUND指令发现被测试的值超过了指令中给定的范围,那么就发生边界检查故障。边界检查故障不提供出错码。
(3)非法操作码故障(异常6)
如果80386不能把CS和EIP所指向存储单元的位模式识别为某条指令的部分,那么就发生非法操作码故障。当出现如下情况时,发生这样的故障:(1)操作码字段的内容不是一个合法的80386指令代码;(2)要求使用存储器操作数的场合,使用了寄存器操作数;(3)不能被加锁的指令前使用了LOCK前缀。非法操作码故障不提供操作码。
(4)设备不可用故障(异常7)
设备不可用故障支持80387数字协处理器。在没有80387协处理器硬件的系统中,可用该异常的处理程序代替协处理器的软件模拟器。在发生任务切换时,使得只有在新任务使用浮点指令时,才进行80387寄存器状态的切换。设备不可用故障不提供出错码。该故障在下列情况下产生:(1)在执行浮点指令时,控制寄存器CR0中的EM位或TS位为1;(2)在执行WAIT指令时,控制寄存器CR0中TS位及EM位都为1。需要注意的是,本异常的处理程序必须是一个过程而不能是任务,否则当处理程序发布一条IRET指令时,80386就设置TS位。然后协处理器再次执行这个发生故障的指令,发现TS是置位的,因此就再次发生异常7,结果是无休止的循环。处理程序能通过陷阱门被调用,因为执行期间可以允许中断。
(5)无效TSS故障(异常0AH)
当正从任务状态段TSS装入选择子时,如果发生了除了段不存在故障以外的段异常时,就发生无效TSS故障。在进入故障处理程序时,保存的CS及EIP指向发生故障的指令;或者该故障作为任务切换的一部分发生时,指向任务的第一条指令。
无效TSS故障提供了一个出错码,出错码的格式如下图所示。其中选择子部分是指向引起故障的TSS的选择子。16位的出错代码的主要成分是选择子,指向引起故障的TSS的选择子。高13位是选择子的索引部分,TI位是描述符表指示位。
| 出错代码的格式 |
| BIT15—BIT3 |
BIT2 |
BIT1 |
BIT0 |
| 选择子的索引部分 |
TI |
IDT |
EXT |
上图所示出错码格式是异常时出错码的一般格式。从图中可见出错码中不含选择子的RPL,而由IDT位和EXT位代替。当处理某一异常或外部中断时,又发生了某种异常,那么EXT位置1。当从中断描述符表IDT中读出表项并产生异常时,IDT位置1,这只在中断或异常的处理期间才会发生。当没有选择子时,构成出错码选择子部分的值为0。
一些引起无效TSS故障的原因如下:
TSS描述符中的段限长小于103;
无效的LDT描述符,或者LDT未出现;
堆栈段不是一个可写段;
堆栈段选择子索引的描述符超出描述符表界限;
堆栈段DPL与新的CPL不匹配;
堆栈段选择子的RPL不等于CPL;
代码段选择子索引的描述符超出描述符表界限;
代码段选择子不指向代码段;
非一致代码段的DPL不等于新的CPL;
一致代码段的DPL大于新的CPL;
对应DS、ES、FS或GS的选择子指向一个不可读段(如系统段);
对应DS、ES、FS或GS的选择子索引的描述符超出描述符表的界限。
(6)段不存在故障(异常0BH)
处理器在把描述符装入非SS段寄存器的高速缓冲时,如果发现描述符其它方面有效,而P位为0(表示对应段不存在),那么在引用此描述符时就发生段不存在故障。有关SS段的情形纳入堆栈段故障。在进入故障处理程序时,保存的CS及EIP执行发生故障的指令;或者该故障作为任务切换的一部分发生时,指向任务的第一条指令。
段不存在故障提供了一个包含引起该故障的段选择子的出错代码。出错码的格式如上图所示。选择子索引部分为引起段不存在故障的段描述符选择子的索引。
(7)堆栈段故障(异常0CH)
当处理器检测到用SS寄存器进行寻址的段有关的某种问题时,就发生堆栈段故障。在进入故障处理程序时,保存的CS及EIP指向发生故障的指令;或者该故障作为任务切换的一部分发生时,指向任务的第一条指令。堆栈段故障提供一个出错码,出错码的格式也如上图。
具体地说,当出现下列三种情况时,将引起堆栈段故障:
(1)在堆栈操作时,偏移超出段界限所规定的范围。这种情况下的出错码是0。例如PUSH操作时,堆栈溢出。
(2)在由特权级变换所引起的对内层堆栈的操作时,偏移超出段界限所规定的范围。这种情况下的出错码包含有内层堆栈的选择子。
(3)装入到SS寄存器(高速缓冲寄存器)的描述符中的存在位为0。这种情况下的出错码包含有对应的选择子。
上述第一种情况是容易辨别的。第二和第三种情况的辨别要通过判断出错代码所含选择子所指示的描述符中的存在位进行。如果存在位为1,那么是第二种情况;否则是第三种情况。
(8)通用保护故障(异常0DH)
除了明确列出的段异常外,其它的段异常都被视为通用保护故障。在进入故障处理程序时,保存的CS及EIP指向发生故障的指令;或者该故障作为任务切换的一部分发生时,指向任务的第一条指令。通用保护故障提供一个出错码,出错码的格式也如上图所示。
根据处理程序可能作出的响应,通用保护故障可分为如下两类:
(1)违反保护方式,但程序无须中止的异常。这类故障提供的出错码为0。这种异常在应用程序执行特权指令或I/O访问时发生,支持虚拟8086程序的系统或支持虚拟I/O访问的系统需要模拟这些指令,并在模拟完成产生故障的指令后,重新执行被中断的程序。
(2)违反保护方式,并导致程序终止的异常。这类故障提供的出错码可能为0,也可能不为0(能确定选择子时)。引起这类故障的一些原因如下:
向某个只读数据段或代码段写;
从某个只能执行的代码段读出;
将某个系统段描述符装入到数据段寄存器DS、ES、FS、GS或SS;
将控制转移到一个不可执行的段;
在通过段寄存器CS、DS、ES、FS或GS访问内存时,偏移超出段界限;
当访问某个描述符表时,超过描述符表段界限;
把PG位为1但PE位为0的控制信息装入到CR0寄存器;
切换到一个正忙的任务。
对上述两类通用保护故障的辨别,可通过检查引起故障的指令和出错码进行。如果出错码非0,那么肯定是第二类通用保护故障。如果出错码是0,那么需要进一步检查引起故障的指令,以确定它是否是系统支持的可以模拟的指令。
(9)页故障(异常0EH)
关于页故障的详细说明请见后面的文章。
(10)协处理器出错(异常10H)
协处理器出错故障指示协处理器发生了未被屏蔽的数字错误,如上溢或下溢。在引起故障的浮点指令之后的下一条浮点指令或WAIT指令,把协处理器出错作为一个故障通知给系统。协处理器出错故障不提供出错码。
3.陷阱类异常
(1)调试陷阱(异常1)
调试异常有故障类型,也有陷阱类型。调试程序可以访问调试寄存器DR6,以确定调试异常的原因和类型。调试异常不提供出错码。
(2)单字节INT3(异常3)
INT3是一条特别的单字节“INT n”指令。调试程序可利用该指令支持程序断点。INT3指令被看成是一种陷阱,而不是一个中断。当由于执行INT3指令进入异常3处理程序时,被保存的CS和EIP指向紧跟INT3的指令,即INT3后面的字节。INT3陷阱不提供出错码。
(3)溢出(异常4)
INTO指令提供条件陷阱。如果OF标志为1,那么INTO指令产生陷阱;否则不产生陷阱,继续执行INTO后面的指令。在进入溢出处理程序时,被保存的CS和EIP指向INTO指令的下一条指令。溢出陷阱不提供出错码。
4.中止类异常
(1)双重故障异常(异常8)
当系统正在处理一个异常时,如果又检测到一个异常,处理器试图向系统通知一个双重故障,而不是通知第二个异常。双重故障属于中止类异常,所以在转入双重故障处理程序时,被保存的CS和EIP可能不指向引起双重故障的指令,而且指令的重新启动不支持双重故障。双重故障提供的出错码为0。
当正处理一个段故障异常时,有可能又产生一个页故障。在这种情况下,通知给系统的是一个页故障异常而不是双重故障异常。但是,如果正处理一个段故障或页故障时,又一个段故障被检测到;或者如果正处理一个页故障时,又一个页故障被检测到,那么就引起双重故障。
当正处理一个双重故障时,又一个段或页故障被检测到,那么处理器暂停执行指令,并进入关机方式。关机方式类似于处理器指令一条HLT指令后的状态:处理器空转,并维持到处理器接收到一个NMI中断请求或者被重新启动为止。在关机方式下,处理器不响应INTR中断请求。
双重故障通常指示系统表出现严重的问题,例如段描述符表、页表或中断描述符表出现问题。双重故障处理程序在重建系统表后,可能不得不重新启动操作系统。
(2)协处理器段越界(异常9)
协处理器段越界异常属于中止类异常,这是因为引起该异常的指令不能被重新启动。当浮点指令操作数超出段界限时,产生该中止异常。协处理器段越界异常不提供出错码。在异常处理程序入口保存的CS及EIP指向被中止的指令。这种中止不是系统的中止,而是只影响检测到这种异常时正执行的指令所在的程序。 |