【Linux 0.12】80x86保护模式——中断和异常处理
80x86保护模式及其编程
中断和异常处理
中断和异常是指明系统、处理器或当前执行程序(或任务)的某处出现了一个事件,该事件需要处理器进行处理。通常该事件会导致执行控制被迫从当前运行程序转移到称为中断处理程序或异常处理程序的特殊软件函数或任务中。处理器响应中断或异常采取的行动称为中断/异常服务(处理)。
当收到异常或中断时,处理器自动把当前正在执行的程序或任务挂起,并开始运行中断或异常处理程序。当处理程序执行完毕,处理器就恢复并继续执行被中断的程序或任务。被中断的程序的恢复过程不会失去程序执行的连贯性,除非从异常中恢复是不可能的或者中断导致当前运行程序被终止。
异常和中断向量
为了有助于处理异常和中断,每个需要被处理器进行特殊处理的处理器定义的异常和中断条件都被赋予了一个标识号,称为向量(vector)。处理器把赋予异常或中断的向量用作中段描述符表IDT的一个索引号,用来定位一个异常或中断的处理程序入口地址。
允许的向量号范围时0255,其中031保留用作80x86处理器定义的异常和中断,不过目前该范围内的向量号并非每个都定义了,未定义的将留作今后使用。
范围在32~255的向量号用于用户定义的中断。这些中断通常用于外部IO设备,使得这些设备可以通过外部硬件中断机制向处理器发送中断。
中断源和异常源
1. 中断源
处理器从两种地方接收中断:
- 外部产生的中断(硬件中断)
- 软件产生的中断
外部中断通过处理器芯片上的两个引脚接收(INTR和NMI)。EFLAGS的IF标志可以用来屏蔽所有硬件中断。
通过在指令操作数中提供中断向量号,INT n指令可以用于从软件中产生中断。
2. 异常源
异常也有两个来源:
- 处理器检测到的程序错误
- 软件产生的异常
INT0, INT3和BOUND指令可以从软件产生异常。
异常的分类
- 故障(Fault):通常时一种可以被纠正的异常,并且一旦被纠正之后就可以继续运行。此时异常处理程序的返回地址指向产生故障的指令。
- 陷阱(Trap):来源于一个引起陷阱的指令。此时异常处理程序的返回地址指向引起陷阱的后一条指令。
- 中止(Abort):不报告导致异常指令的精确位置,且不允许导致异常的程序重新继续执行。
程序或任务的重新执行
为了让程序或任务在异常或中断处理完之后能够恢复执行,除了中止以外的所有异常都能够报告精确的指令位置,并且所有的中断保证在指令的边界上发生。
故障类异常:异常处理程序的返回地址指向产生故障的指令,即原出错指令会被重新执行。Fault最常见的例子是 Page-fault(页面故障,又称缺页中断)。异常处理程序通过把该页面加载到内存中并重新执行该指令来恢复程序的执行。
为了确保重新执行对于当前执行的程序具有透明性,处理器会保存必要的寄存器和堆栈指针信息,使得能够返回到出错指令之前的状态。
陷阱类异常:处理器产生异常时保存的返回指针指向引起陷阱操作的后一条指令。如果在一条执行控制转移的指令执行器件检测到一个Trap,那么返回指令指针会指向JMP指令的目标位置,而不是JMP的后一条指令。
中止类异常:不支持可靠地重新执行程序或者任务。中止异常的处理程序一般用来收集处理器的诊断信息,尽可能恰当地关闭程序和系统。
开启和中止中断
EFLAGS的IF标志可以屏蔽硬件中断。
中断描述符表
IDT。每个表项(中段描述符)8Byte。
IDT表可以存放三种类型的门描述符:中断门,陷阱门,和任务门。
因为最多只有256个中断或异常向量,所以IDT无需包含多余256个描述符。
IDT表可以驻留在线性地址空间的任何地方,对齐8 Byte会提高访问效率。
同样,IDT表的相关信息保存在IDTR中。
异常和中断处理
处理器对异常和中断的处理过程的调用操作方法与使用CALL指令调用程序过程和任务的方法类似。
当响应一个异常或中断时,处理器使用处理异常或中断的向量作为IDT表中的索引。
- 如果索引值指向中断门或陷阱门,则处理器使用与CALL指令操作调用门类似的方法调用异常或中断处理过程。
- 如果索引值指向任务门,则处理器用与CALL指令操作任务门类似的方法进行任务切换。