IA32中断和异常(Interrupt And Exception)
IA32 Interrupt And Exception
不同体系架构中断和异常的定义内涵不太一样,可以理解,但是同一体系架构的不同教科书也不太一样,淦了
最后还是去读了一波intel的手册,RTFM!!!,在64-ia-32-architectures-software-developer-vol-3a-part-1-manual的chapter 6
EFLAGS寄存器
Interrupt
The processor receives interrupts from two sources:
• External (hardware generated) interrupts.
• Software-generated interrupts.(如int n来调用n中断)
通常是由CPU外部的输入输出设备(硬件)所触发的,希望cpu停下手里的任务去执行对应得中断处理程序,之后再回到手里任务来,所以中断是异步的,被叫做异步中断或硬件中断
cpu提供了两引脚
INTR(INTeRrupt)可屏蔽中断(maskable interrupt)通过INTR向CPU发生请求
NMI(Non Maskable Interrupt)不可屏蔽中断(nonmaskable interrupt)通过NMI向CPU发生请求
可以通过CLI清除EFLAGS寄存器里IF(Interrupt enable Flag)位(IF=0)来禁止可屏蔽中断发生,STI(IF=1)允许可屏蔽中断发生(IA32只有在响应中断时把IF=0关闭中断,响应异常的时候不会关闭)
不可屏蔽中断,意如其名
Exception
The processor receives exceptions from three sources:
• Processor-detected program-error exceptions.
• Software-generated exceptions.
• Machine-check exceptions.
异常通常是CPU在执行指令时因为检测到预先定义的某个或多个条件而产生的同步事件,又被叫做同步中断,来自处理器内部,IF位在这里不起任何作用,立即执行
故障(Fault)
可能被异常处理程序修复,如果修复,再返回到当前引起异常的指令,比如说我们的缺页异常,指令引用一个虚拟地址,发现他对应的的物理页面不在内存,异常处理程序会把它从磁盘取出来放到内存,加载后再回到该指令就可以正常执行,修复不了,终止
陷阱(Traps)
有意的异常,执行完陷阱指令后,报告给cpu异常,比如我们的int n(有的书里把这个叫做软中断),int3, into(溢出检测),bound(地址越界检测),ud2(未定义指令)等,最重要的作用就是提供用户和内核的接口–系统调用,异常处理程序的返回地址指向导致异常指令的下一个指令地址
终止(Aborts)
直接终止,处理程序将控制返回给一个abort例程,该例程会终止这个应用程序
中断向量表(Interrupt Vector Table,IVT)
实模式下用于存储中断处理程序入口的表
系统开机后处于实模式,1M的寻址空间,由BOIS做检测和初始化,初始化就包括了在00000H~003ffh 1kb区域建立中断向量表,表里的每一项记录中断或异常处理程序的入口地址,叫做中断向量,占4个字节,所以共有256个,BIOS再利用INT执行特定中断处理程序把引导程序从磁盘加载到内存,引导后,进入保护模式
中断描述符表(Interrupt Descriptor Table,IDT)
保护模式下用于存储中断处理程序入口的表
IDTR寄存器来描述的IDT的位置和长度lidt指令可以往idtr里装入数据,和GDTR一样前32位是idt地址,16位表长度描述表的大小,为0时大小是1
IDT的每个表项是一个8字节的门描述符(Gate Descriptor)结构
我们之前的段描述符中描述的是一片内存区域,而门描述符中描述的是一段代码
还记得我们之前段描述符的S=0代表该描述符描述的是一个系统段,S=1代表该描述符描述的是代码段、数据段或堆栈段,TYPE和S段配合使用,段的访问权限或系统控制描述类型
这里的门就是系统段S=0,根据TYPE不同分为不同门
任务门描述符 0101 用于任务切换
中断门描述符 D110 用于描述中断处理例程的入口 IF位自动置 0
陷阱门描述符 D111 用于描述异常处理例程的入口 IF位不会自动置0
D位用来表示描述的是16位门(0)还是32位门(1),同样DPL表示访问本段的 最低权限要求
异常和中断处理过程
CPU收到中断向量号后,把IDTR里IDT基地址+中断向量号*8得到中断门描述符
如果是使用INT3 int n INTO等指令产生的中断或异常,会检测CPL和门描述符里的DPL,CPL权限必须大于等于DPL,
然后再次检测CPL权限必须小于门描述符里选择子对于代码段的DPL,也就是特权转移处理除了返回,只能从低权限转到高权限
如果是由硬件产生的中断或处理器检测到的异常,不会进行第一次和门描述符DPL的检测,只和代码段检测
把选择子加载到cs 偏移加载到eip执行
中断发生时的压栈
拿到中断描述符后CPL和描述符里的选择子对应当的DPL比较
>>>CPL权限低于DPL的话需要切换到高特权级的栈,为了执行完中断后恢复,会先临时保存当前栈的ss和esp,从TSS段里拿到DPL级别的栈加载到ss和esp,然后把临时保存的旧ss:esp压入新栈,然后压入eflags寄存器,cs,eip,有的中断还会压入出错码
>>>CPL=DPL是不用切换堆栈,故不用压入原ss esp,其余一样
然后选择子加载到cs 偏移加载到ei,执行中断处理程序,中断执行完用iret指令返回被中断程序,iret会把eip cs eflags弹出到寄存器,iret执行时esp必须指向eip,所以我们必须自己弹出出错码
iret同样会进行权限检测,进行逆过程决定是不是弹出就ss:esp
IA32中断向量号
0-255
其中0-31被cpu设计者占用,32-255供操作系统等使用
32-255 | 用户定义中断 | 中断 | 可屏蔽中断 | 来自INTR的外部中断或INT n指令 |