Intel80386知识总结: 中断与异常机制

====================================================================
本文用于汇总整理Intel80386的中断与异常机制,
参考文献:
  • 《INTEL 80386 programmer's reference manual 1986》
  • 《Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B & 3C): System Programming Guide》

本文是系列文章《Intel80386知识总结》的一部分。
===================================================================

1. 分类与编号
1.1 中断与异常的分类
        中断与异常都属于控制流转移机制的一种,两者之间的区别在于:中断是一种来源于处理器外部的事件,处理器用异步方式予以处理。异常则由处理器本身负责检测,属于同步处理。按来源,可以对中断与异常进行以下分类:
中断:
  • Maskable Interrupts: 由INTR针脚发送
  • Nonmaskable Interrupts:由NMI针脚发送

异常:
  • 由处理器检测: 进一步分类为Faults,Traps,Aborts三类
  • 通过软件编程(也称为软中断):通过INT0/INT 3/INT n/BOUND指令触发

三种异常:
  • Faults:Faults异常逻辑上在产生异常的指令之前触发,它可以在指令执行过程中被发现,发现后需要把机器状态回溯到指令执行之前。CS寄存器和EIP寄存器指向产生异常的指令。
  • Traps:Trap异常紧接着在产生异常的指令结束后马上触发。CS寄存器和EIP寄存器动态的指向产生异常的指令的下一条指令,如果产生异常的指令是控制流转移指令,例如JMP指令产生了Trap异常,则转移后的CS和EIP寄存器值应该被压入栈。
  • Aborts:Abort异常既不提供异常产生的准确位置,也不重置机器状态,Abort异常表示严重的系统错误


1.2. 中断号
        每一种中断/异常的都对应一个唯一的中断号,NMI中断和异常的中断号由i386预定义,占据0 ~ 31。Maskable中断的中断号由中断控制器(例如典型的Intel8259A Programmable Interrupt Controller)赋值,并且其赋值逻辑是可以通过软件编程的,中断号空间占据32 ~ 255.

2. 中断屏蔽
        中断处理的正常时机是在一条指令结束之后,下一条指令开始之前进行。特别的,对于带有Prefix前缀的String指令在执行时,每完成一次Repeat,都会进行中断响应。在处理器运行的某些特殊时段,需要对中断处理进行屏蔽,主要包括以下三种情况。

2.1 在处理NMI中断的时候
        在处理一个NMI中断的时候,处理器会忽略期间通过NMI针脚发送的中断,直到遇到第一个IRET指令为止。

2.2 通过IF标志位屏蔽Maskable中断
        当IF=0时,处理器会延迟通过INTR针脚发送的Maskable中断的处理,直到IF=1。
        CLI和STI指令分别可以用来clear和set IF标志位,优先权要求:CPL 小于等于 IOPL。

2.3 在堆栈切换时
         在进行堆栈切换时通常需要类似下面的指令,分别用来更新堆栈段和栈顶:
MOV SS, AX
MOV ESP, StackTop

若在这两条指令之间发生中断/,将导致堆栈管理数据不一致。为避免这一情况,i386在通过MOV或POP指令修改SS寄存器之后会延迟处理以下中断异常:
  • NMI中断
  • INTR中断
  • debug异常
  • 单步Traps

其他异常将会获得响应不受影响。

2.4 多个中断/异常发生时的优先级
        当某个指令间隙有多个中断/异常等待处理时,按照下表的顺序先处理最高有限级中断/异常,低优先级中断在下一个指令间隙执行,低优先级异常在当前处理程序结束后再处理。
Intel80386知识总结: 中断与异常机制_第1张图片

3. 中断处理
3.1 中断描述符表(IDT)
        中断描述符表维护了一个中断号到中断处理指令描述符的映射关系,其结构与GDT、LDT类似,中断号作为其索引。因为最多只有256个中断/异常,所以IDT的长度不需要超过256×8,可以小于256×8,因为可能不是所有中断/异常都会发生且有处理程序。处理器通过IDTR寄存器找到IDT,通过LIDT和SIDT指令分别进行IDTR寄存器的set和get操作。LIDT指令要求CPL=0,SIDT没有优先权要求,可以在任何CPL执行。

3.2 中断描述符
IDT中可以包含的描述符分为三种:任务门、中断门和Trap门。任务门的作用详见i386多任务支持的内容,中断门和Trap门的格式如下所示。
Intel80386知识总结: 中断与异常机制_第2张图片
        通过任务门、中断门和Trap门可以使用以下两种方式来处理中断:
  • 使用Interrupt Procedure处理中断
  • 使用Interrupt Task处理中断


3.3 ErrorCode
某些异常会给处理程序/任务传递ErrorCode,ErrorCode的结构如下图所示:
Intel80386知识总结: 中断与异常机制_第3张图片
ErrorCode的结构和选择符类似低位的三个标志位的含义为:
  • EX:当中断/异常来自产生异常的程序外部时设置此位
  • I:当SELECTOR INDEX指向IDT的一个门描述符时设置此位
  • TI:TI=0时,SELECTOR INDEX选中GDT中的描述符;TI=1时,SELECTOR INDEX选中LDT中的描述符


3.4 使用Interrupt Procedure处理中断
        当IDT相应位置保存了Trap门或者中断门的时候,将采用Interrupt Procedure的方式处理中断,如下图所示:
Intel80386知识总结: 中断与异常机制_第4张图片
        使用Interrupt Procedure处理中断时的堆栈操作分情况如下图所示:
Intel80386知识总结: 中断与异常机制_第5张图片
使用中断门和Trap门的区别在于通过中断门会设IF为0,而通过Trap门不会。

3.5 使用Interrupt Task处理中断
        当IDT相应位置保存了任务门的时候,将采用Interrupt Task的方式处理中断,如下图所示:
Intel80386知识总结: 中断与异常机制_第6张图片
        Interrupt Task将会切换到一个独立的上下文来进行中断处理。如果任务切换是由带有ErrorCode的异常引起的,那么处理器会自动的把ErrorCode推到新任务正确的堆栈上。

你可能感兴趣的:(异常机制)