前言
对于80386而言把外部中断称为"中断",内部中断为"异常"且通常在两条指令间响应中断或异常
为了分析除0后操作系统的具体操作,我打算先从分析中断与异常的具体细节开始进行分析,进而来引出除0后的相关操作
中断异常分析
- 中断
中断分为可屏蔽中断和非屏蔽中断。可屏蔽中断常用于响应外部事件,当标志寄存器EFLAGS中的IF标志位置1时,INTR引脚上的高电平产生中断请求,处理器将在现行指令结束时响应并执行两个总线周期,读取数据线上的8位向量号,并于中断向量表对应转入响应服务.IF复位屏蔽后来中断。也可由程序置位以便中断嵌套。并在结束后使用RET指令复位
非屏蔽中断不受IF位影响,无需中断响应周期,由内部提供中断向量号2。在NM I服务过程中,80386不为后来的NMI和INTR请求提供服务,每当接受一个NMI中断,处理器就在内部屏蔽了再次响应NMI,这一屏蔽过程直到执行中断返回指令IRET后才结束。所以,NMI处理程序应以IRET指令结束。
- 异常
异常用于处理指令故障,根据产生位置不同和向量号不同分为故障、陷阱、中止,进而转相应的中断处理程序。
故障是在指令执行之前将相关异常通知给系统,故80386认为故障可排除,当系统处理故障时,保存的断点CS指向当前引起故障的指令。在故障处理完后,回到程序的断点处,指令可以重新执行。陷井是引起问题的指令执行后立即报告的异常。它包括用户定义的中断,主要用于软件调试。断点CS值指向引起陷阱的指令的下一条要执行的指令。中止是在系统出现严重情况时,通知系统的一种异常。引起中止的指令是无法确定的。产生中止时,正执行的程序不能被恢复执行。系统接收中止后,处理程序要重新建立各种系统表格,并可能重新启动操作系统。
由上述分析可知除0操作应当算做一种异常,并有相对应的中断向量号
除0操作的异常
查询相关文献可知除法操作的向量号为0,当执行DIV指令或IDIV指令时,如果除数等于0或者商太大,以至于存放商的操作数容纳不下,接下来讲进行详细的异常转移方法分析
80386实模式下的异常的转移方法与8086相同。这里介绍的异常的转移方法是指 80386在保护模式下响应处理异常时所采用的转移方法。
在保护模式下,80386不使用实模式下的中断向量表,而是使用中断描述符表IDT。在保护模式下,80386把中断向量号作为中断描述符表IDT中描述符的索引,中断描述符表IDT所含的描述符只能是中断门、陷阱门和任务门。发生异常时首先确定返回点;形成符合出错码格式的出错码,并在实际执行异常处理程序之前把16位的出错码以32位的值压入堆栈。从IDT中取得故障门描述符,分解出选择子、偏移量和描述符属性类型,并进行有关检查。根据门描述符类型,转入异常处理程序.由于异常门处理的方式极其接近调用门,那么处理器会象处理CALL 指令引用调用门一样,引用异常例程。下述描述将借鉴于调用门。
异常处理过程:
- 使用目标代码段的DPL(也就是新的CPL)从TSS 中选择一个指向新栈的指针(段选择子和栈指针)。
- 从当前TSS 中读取将要切换到的栈的段选择子和栈指针。处理器把被异常例程的栈段选择子和栈指针压入新的栈中。
- 暂时保存当前SS 寄存器和ESP 寄存器的值。
- 将新栈的段选择子和栈指针载入SS 寄存器和ESP 寄存器。
- 将暂时保存的SS 寄存器和ESP 寄存器的值(调用例程的)压入新栈
- 将异常门的参数计数域所指定个数的参数从异常例程的栈拷贝到新栈。
- 将返回指令指针(当前CS 寄存器和EIP 寄存器)压入新栈。
- 从异常门中将新代码段的段选择子和新指令指针分别载入CS 寄存器和EIP 寄存器,然后开始执行异常处理例程。
从异常中返回
中断返回指令IRET用于从中断或异常处理程序的返回。该指令的执行根据任务嵌套标志NT位是否为1分为两种情形。
NT位为1,表示是嵌套任务的返回。当前TSS中的链接字段保存有前一任务的TSS的选择子,取出该选择子进行任务切换就完成了返回。这种情形在由通过任务门转入的中断或异常处理程序返回时出现,因为在由中断门或陷阱门转入处理程序时,NT位已被清0。
NT位为0,表示当前任务内的返回。这种情形在由通过中断门或陷阱门转入的中断或异常处理程序返回时出现。
- 检查保存的CS 寄存器的RPL 域来确定返回时是否需要改变特权级。
- 从堆栈顶载入CS 寄存器和EIP 寄存器。
- 弹出EFLAGS值
- (如果返回要求改变特权级。将保存的SS 和ESP 值载入SS 寄存器和ESP 寄存器
- (如果该返回需要改变特权级。)检验DS、ES、FS 和GS 段寄存器的内容。如果这些寄存器中的某一个所指向的段的DPL 小于新的CPL(不包括一致性代码段),该寄存器就会被赋予一个空的段选择子。