中断和异常
中断和异常:指明系统、处理器或当前执行程序的某处出现一个事件,需要处理器进行处理。
这种事件导致执行控制权从当前程序转移到被称为中断/异常处理程序的特殊函数或任务中。处理器响应中断或异常所采取的行动被称为中断/异常服务。
中断发生在程序执行的随机时刻,例如:要求外部设备提供服务等。
异常发生在处理器执行一条出错指令时,例如:被0除错误、违反保护机制、页错误等。
异常和中断向量
每一个异常和中断都被赋予一个标识号,称为向量。该向量作用于中断描述符表IDT的一个索引值,来定位一个异常或中断的处理程序入口点位置。
保护模式下的异常和中断:
中断源
处理器从两个地方接受中断:
- 外部中断
- 软中断
外部中断通过芯片引脚(INTR和NMI)接收。如图为级联8259A:
软中断通过在操作数中提供中断向量号,INT n 指令来进行软件中断。例如指令 INT 0x80会执行linux系统中断调用。
异常源
处理器接收的异常来源: - 处理器检测到的程序错误异常
- 软件产生的异常
异常可被分为:故障(Fault)、陷阱(Trap)、中止(Abort)。
Fault:是一种通常可以被纠正的异常,并且一旦被纠正就可以继续运行,返回地址指向产生Fault的指令。
Trap:是一个引起陷阱的指令被执行后立刻会报告的异常,返回地址指向引起Trap的下一条指令。
Abort:是一种不会总是报告导致异常的指令的精确位置的异常,并且不允许导致异常的程序重新继续执行。
开启和禁止中断
标志寄存器EFLAGS的中断允许标志IF能够禁止为INTR引脚收到可屏蔽硬件中断提供服务。 - IF=0:处理器禁止发送到INTR引脚的中断
- IF=1:发送到INTR引脚的中断信号会被处理器进行处理
IF标志并不影响发送到NMI引脚的非屏蔽中断,也不影响处理器产生的异常。
IF标志的影响: - 处理器在响应硬件复位时清除IF标志(IF=0)
- 使用STI和CLI来设置和清除(CPL<=IOPL时)
- PUSHF指令会把EFLAGS压入堆栈,在那里进行修改,POPF指令把修改后的内容装入EFLAGS寄存器
- 任务切换、POPF、IRET指令会加载EFLAGS寄存器,可以用来修改IF标志
- 当通过中断门处理一个中断时,IF标志会被自动清除(复位),从而会禁止可屏蔽硬件中断,但陷阱门处理IF标志不会被复位
异常和中断优先级
如果在一条指令边界有多个异常或中断等待处理,处理器会首先处理最高优先级的异常或中断,低优先级的异常会被丢弃,而低优先级的中断则会保持等待,当中断处理程序返回到产生异常/中断的程序或任务时,被丢弃的异常会重新发生。
异常和中断的优先级:
** 中断描述符表 **
中断描述符表DIT将每个异常或中断向量分别与它们的处理过程联系起来。IDT表可以驻留在线性地址空间的任何地方,处理器使用IDTR寄存器来定位IDT表的位置。
中断描述符表IDT和寄存器IDTR:
指令LIDT和SIDT分别用于加载和保存IDTR寄存器的内容。
IDT描述符
IDT表中可以存放三种类型的门描述符:
- 中断门描述符
- 陷阱门描述符
- 任务门描述符
中断和异常处理
当处理器执行异常或中断处理过程调用时会进行以下操作:
1、如果处理过程将在高特权级上执行时会发生堆栈切换:
-
处理器从当前执行任务的 TSS 段中得到中断或异常处理过程使用的堆栈的段选择符和栈指针,然后把被中断程序的栈选择符和栈指针压入新栈中
-
接着把EFLAGS、CS、EIP寄存器的当前值压入新栈
-
如果异常会产生一个错误号,那么错误号也被压入新栈
2、如果处理过程将在被中断任务同一特权级上运行不会发生堆栈切换: -
把EFLAGS、CS、EIP寄存器的当前值压入当前堆栈
-
如果异常会产生一个错误号,那么错误号也被压入栈
任务门中断
当通过 IDT 中任务门来访问异常或中断处理过程就会导致任务切换。
IDT 中的任务门会引起 GDT 中的 TSS 描述符:
错误码
当异常条件与一个特定的段相关时,处理器会把一个错误码压入异常处理过程的堆栈。
-
位0是外部事件EXT标志
置位:表示执行程序以外的事件造成了异常 -
位1是描述符位置IDT标志
置位:表示错误码索引部分指向IDT中的一个门描述符
复位:指向GDT或LDT的一个段描述符 -
位2是GDT/LDT表选择标志 TI(当位1复位时才有用)
置位:索引指向LDT
复位:索引指向GDT
页故障错误码
-
位0(P) :异常由于页面不存在或违反访问特权引发。P=0,表示页不存在;P=1,违反页级保护权限。
-
位1(W/R):异常由于内存读写或写操作引起。W/R=0,表示由读操作引起;W/R=1,表示由写操作引起。
-
位2(U/S) :发生异常时CPU执行的代码级别。U/S=0,表示超级用户代码;U/S=1,一般用户代码
处理器还会把引起页面故障异常所访问的线性地址存放在CR2中,页出错程序可以使用这个地址来定位想关的页目录和页表项。