windows内核(6)——中断与异常和控制寄存器
今天来学习一下X86中断与异常和控制寄存器
中断
中断通常是由CPU
外部的输入输出设备(硬件)所触发的,供外部设备通知CPU
有事情需要处理,因此又叫中断请求,英文为Interrupt Request
。中断请求的目的是希望CPU
暂时停止执行当前正在执行的程序,转去执行中断请求所对应的中断处理例程,中断处理程序由 IDT 表决定。
80x86
有两条中断请求线:非屏蔽中断线,NMI
,全称NonMaskable Interrupt
和可屏蔽中断线,INTR
,全称Interrupt Require
。
可屏蔽中断
CPU 的 EFLAGS 有一个 IF 位,它表示了 CPU 当前是否接受可屏蔽中断请求,下面是 EFLAGS 寄存器的图解
IF 是第九位,权值为 0x200,这也就是为什么在用户态我们看到的 EFLAGS 值几乎都是 2xx,因为用户态几乎不允许把该位复位,复位该位需要特权指令 cli 来操作,而重新设置指令需要 sti 来操作。
IF = 1 的时候,可屏蔽中断请求可以被执行,IF = 0 的时候,可屏蔽中断会被屏蔽,不会被执行,不可屏蔽中断走的是 CPU 的NMI引脚,而可屏蔽中断走的就是INTR引脚。
在硬件级,可屏蔽中断是由一块专门的芯片来管理的,通常称为中断控制器。它负责分配中断资源和管理各个中断源发出的中断请求.为了便于标识各个中断请求,中断管理器通常用IRQ
,全称为Interrupt Request
,后面加上数字来表示不同的中断,例如在键盘设备中,可以看到键盘的请求是一号中断
不可屏蔽中断
不赘述了,就是 CPU 收到就必须立刻执行的事件,诸如CPU掉电,总线校验错误,内存校验错误,看门狗错误等,一旦发生了这些事件,硬件会向 CPU 的 NMI 引脚发送一个中断请求要求 CPU 立刻响应。不过大部分的 NMI 可能都表示着CPU生存周期的终结(出现的故障无法恢复),当然也有一些软件产生的 NMI 中断,可能在执行完事件处理程序之后,会允许 CPU 继续运行。
异常
异常通常是CPU
在执行指令时检测到的某些错误,比如除0、访问无效页等。也可以看出,异常是 CPU 主动触发的,是在检测到一些指令不符合某些要求的时候触发的。而中断是由外部设备(中断源)向CPU请求的,是被动的。int n
虽然这个指令是中断(Interrupt)的缩写,但是它本质还是 CPU 主动触发了一个异常,就跟除法的时候检测到了被除数为零是差不多的。
异常处理
无论是由硬件设备触发的中断请求还是由CPU
产生的异常,处理程序都在IDT
表。常见的异常处理程序如下表所示:
错误类型 | (IDT表)中断号 |
---|---|
页错误 | 0xE |
段错误 | 0xD |
除零错误 | 0x0 |
双重错误 | 0x8 |
缺页异常
这是 CPU 主动触发的比较多的异常,当PDE/PTE
的 P=0
时或当PDE/PTE
的属性为只读但程序试图写入的时就会触发。一旦发生缺页异常,CPU
会执行IDT
表中的0xE
中断处理程序,由操作系统来接管。
在 Windows 操作系统中,大家都听过 pagefile.sys,它占用空间很大并且无时无刻不被写入,以前问过一个很蠢的问题就是,这个文件是否能删?先来了解一下这个文件是干啥的,答:为了节省物理内存。由于程序局部性的原理,一个程序所占用的物理页,很可能只有一小部分的数据会被频繁读写或者执行,大部分数据可能都不会反复被使用,那么对于这样一部分的物理页,操作系统会选择将该物理页保存到外部文件,也就是这个 pagefile.sys,也就是这个物理页不会被挂上去了。但是当再一次需要使用的时候怎么办呢,此时找不到对应的物理页,CPU 报告一个缺页异常,调用 IDT 表的 0xE 中断程序去处理,发现这个虚拟内存事实上是有对应的物理内存,只是现在被交换到外部文件当中,那就重新指定一个物理页,把内容写回重新挂上,向CPU报告“这个虚拟内存已经被正确挂上了物理页,可以访问了”,那么CPU重新执行这条指令之后就不会报错了就接着运行。
可以说,缺页异常在操作系统中是无时无刻不在发生。就连刚申请的内存页,在不访问之前也是不会挂物理页的(即不实际占用内存),在第一次访问的时候会引发缺页异常,发现这个页是正确的,只是没被挂物理页,那么挂上物理页之后重新执行再返回。
控制寄存器介绍
控制寄存器(CR0、CR2、CR3、CR4)中有一些标志和数据域用于控制系统级操作,另外一些标志则专用来支持操作系统和管理程序,其中,CR1作保留目前不使用。
CR0
CR0寄存器中含有控制处理器操作模式和状态的系统控制标志,可以说它是总开关的集合体。如下图所示:
这里解释几个重要的位
PE
位是启用保护模式(Protection Enable)标志。若PE = 1
是开启保护模式,反之为实地址模式。这个标志仅开启段级保护,而并没有启用分页机制。若要启用分页机制,那么PE
和PG
标志都要置位。PG
位是启用分页机制。在开启这个标志之前必须已经或者同时开启PE
标志。PG = 0
且PE = 0
,处理器工作在实地址模式下。PG = 0
且PE = 1
,处理器工作在没有开启分页机制的保护模式下。PG = 1
且PE = 0
,在PE
没有开启的情况下无法开启PG
。PG = 1
且PE = 1
,处理器 工作在开启了分页机制的保护模式下。WP
位对于Intel 80486
或以上的CPU
,是写保护(Write Proctect)标志。当设置该标志时,处理器会禁止超级用户程序(例如特权级0的程序)向用户级只读页面执行写操作;当CPL < 3
的时候,如果WP = 0
可以读写任意用户级物理页,只要线性地址有效。如果WP = 1
可以读取任意用户级物理页,但对于只读的物理页,则不能写。
CR1
保留,暂不使用
CR2
当CPU访问某个无效页面时,会产生缺页异常,此时,CPU会将引起异常的线性地址存放在CR2中。
CR3
CR3含有存放页目录表页的物理地址,因此CR3也被称为PDBR(Page-Directory Base address Register,页目录基地址寄存器)。因此前面提到的,dirbase 就是 CR3 的值,事实上任务的切换也依赖于 CR3 寄存器。
CR4
Cr4
的结构如下图所示:
VME
用于虚拟8086模式。PAE
用于确认是哪个分页,PAE = 1
,是2-9-9-12
分页,PAE = 0
是10-10-12
分页。PSE
是大页是否开启的总开关,如果置0,就算PDE
中设置了大页你也得是普通的页。