实模式和保护模式都是CPU的工作模式。
实模式与保护模式介绍
在实模式下,程序可以操作任何地址空间,而且无法限制程序的执行权限。尽管这种模式给设置硬件功能带来许多方便,但却给程序执行的安全性和稳定性带来了灾难性的后果,一旦程序执行错误,很可能导致整个系统崩溃。况且实模式的寻址能力有限,故而才进化出保护模式。
在保护模式里,处理器按程序的执行级别分为0、1、2、3四个等级(由高到低排序)。最高等级0由系统内核使用,最低等级3由应用程序使用,Linux内核目前仅使用这两个等级(0级和3级)。而等级1和等级2介于内核程序与应用程序之间,它们通常作为系统服务程序来使用。虽然层级划分的决定权在系统开发者手里,但一些特殊汇编指令必须在0特权级下才能执行。保护模式不仅加入了程序的权限,还引入了分页功能。分页功能将庞大的地址空间划分成固定大小的内存页面,此举不仅便于管理,而且还缩减了应用程序的空间浪费现象。不过,在保护模式的段级保护措施中,从段结构组织的复杂性,到段间权限检测的繁琐性,再到执行时的效率上,都显得臃肿,而且还降低了程序的执行效率和编程的灵活性。当页管理单元出现后,段机制显得更加多余。随着硬件速度不断提升和对大容量内存的不断渴望,IA-32e模式便应运而生。
IA-32e模式不仅简化段级保护措施的复杂性,升级内存寻址能力,同时还扩展页管理单元的组织结构和页面大小,推出新的系统调用方式和高级可编程中断控制器。
从实模式进入保护模式:哪些任务必须在进入保护模式之前完成?
为了进入保护模式,处理器必须在模式切换前,在内存中创建一段可在保护模式下执行的代码以及必要的系统数据结构,只有这样才能保证模式切换的顺利完成。相关系统数据结构包括IDT/GDTLDT描述符表各一个(LDT表可选)、任务状态段TSS结构、至少一个页目录和页表(如果开启分页机制)和至少一个异常/中断处理模块。
在处理器切换到保护模式前,还必须初始化GDTR寄存器、IDTR寄存器(亦可推迟到进入保护模式后,使能中断前)、控制寄存器CR1~4、MTTRs内存范围类型寄存器。
- 系统数据结构。系统在进入保护模式前,必须创建一个拥有代码段描述符和数据段描述符的GDT ( Globad Descriptor Table,全局描述符表)(第一项必须是NULL描述符),并且一定要使用LGDT汇编指令将其加载到GDTR寄存器。保护模式的栈寄存器SS,使用可读写的数据段即可,无需创建专用描述符。对于多段式操作系统,可采用LDT (Local Descriptor Table,局部描述符表)(必须保存在GDT表的描述符中)来管理应用程序,多个应用程序可独享或共享一个局部描述符表LDT。如果希望开启分页机制,则必须准备至少一个页目录项和页表项。(如果使用4 MB页表,那么准备一个页目录即可。)
- 中断和异常。在保护模式下,中断/异常处理程序皆由IDT ( Interrupt Descriptor Table,中断描述符表)来管理。IDT由若干个门描述符组成,如果采用中断门或陷阱门描述符,它们可以直接指向异常处理程序;如果采用任务门描述符,则必须为处理程序准备TSS段描述符、额外的代码和数据以及任务段描述符等结构。如果处理器允许接收外部中断请求,那么IDT还必须为每个中断处理程序建立门描述符。在使用IDT表前,必须使用LIDT汇编指令将其加载到IDTR寄存器,典型的加载时机是在处理器切换到保护模式前。
- 分页机制。CRO控制寄存器的PG标志位用于控制分页机制的开启与关闭。在开启分页机制(置位PG标志位)前,必须在内存中创建一个页目录和页表(此时的页目录和页表不可使用同一物理页),并将页目录的物理地址加载到CR3控制寄存器(或称PDBR寄存器)。当上述工作准备就绪后,可同时置位控制寄存器CRO的PE标志位和PG标志位,来开启分页机制。(分页机制往往与模式切换同时进行,不能在进入保护模式前开启分页机制。)
- 多任务机制。如果希望使用多任务机制或允许改变特权级,则必须在首次执行任务切换前,创建至少一个任务状态段TSS结构和附加的TSS段描述符。(当特权级切换至0、1、2时,栈段寄存器与栈指针寄存器皆从TSS段结构中取得。)在使用TSS段结构前,必须使用LTR汇编指令将其加载至TR寄存器,这个过程只能在进入保护模式后执行。此表也必须保存在全局描述符表GDT中,而且任务切换不会影响其他段描述符、LDT表、TSS段结构以及TSS段描述符的自由创建。只有处理器才能在任务切换时置位TSS段描述符的忙状态位,否则忙状态位始终保持复位状态。如果既不想开启多任务机制,也不允许改变特权级,则无需加载TR任务寄存器,也无需创建TSS段结构。
保护模式---->IA-32e模式( 64位模式):哪些任务必须在进入IA-32e模式( 64位模式)之前完成?
在进入IA-32e模式前,处理器依然要为IA-32e模式准备执行代码、必要的系统数据结构以及配置相关控制寄存器。与此同时,还要求处理器只能在开启分页机制的保护模式下切换到IA-32e模式。
- 系统数据结构。当IA-32e模式激活后,系统各描述符表寄存器(GDTR、LDTR、IDTR、TR )依然沿用保护模式的描述符表。由于保护模式的描述符表基地址是32位,这使得它们均位于低4GB线性地址空间内。既然已经开启IA-32e模式,那么系统各描述符表寄存器理应(必须)重新加载(借助LGDT、LLDT、LIDT和LTR指令)为IA-32e模式的64位描述符表。
- 中断和异常。当软件激活IA-32e模式后,中断描述符表寄存器IDTR仍然使用保护模式的中断描述符表,那么在将IDTR寄存器更新为64位中断描述符表IDT前不要触发中断和异常,否则处理器会把32位兼容模式的中断门解释为64位中断门,从而导致不可预料的结果。使用cLI指令能够禁止可屏蔽硬件中断,而NMI不可屏蔽中断,必须借助外部硬件电路才可禁止。
IA32_EFER寄存器(位于MSR寄存器组内)的LME标志位用于控制IA-32e模式的开启与关闭,该寄存器会伴随着处理器的重启(重置)而清零。IA-32e模式的页管理机制将物理地址扩展为四层页表结构。在IA-32e模式激活前(CR0.PG=1,处理器运行在32位兼容模式),CR3控制寄存器仅有低32位可写入数据,从而限制页表只能寻址4GB物理内存空间,也就是说在初始化IA-32e模式时,分页机制只能使用前4 GB物理地址空间。一旦激活IA-32e模式,软件便可重定位页表到物理内存空间的任何地方。以下是IA-32e模式的标准初始化步骤。
- (1)在保护模式下,使用wov CRO汇编指令复位CRO控制寄存器的PG标志位,以关闭分页机制。(此后的指令必须位于同一性地址映射的页面内。)
- (2)置位CR4控制寄存器的PAE标志位,开启物理地址扩展功能(PAE)。在IA-32e模式的初始化过程中,如果PAE功能开启失败,将会产生通用保护性异常(#GP )。
- (3)将页目录(顶层页表PML4)的物理基地址加载到CR3控制寄存器中。
- (4)置位IA32_EFER寄存器的LME标志位,开启IA-32e模式。
- (5)置位CRO控制寄存器的PG标志位开启分页机制,此时处理器会自动置位IA32_ERER寄存器的LMA标志位。当执行Mov CRo指令开启分页机制时,其后续指令必须位于同一性地址映射的页面内(直至处理器进入IA-32e模式后,才可以使用非同一性地址映射的页面)。
如果试图改变IA32_EFER.LME、CRO.PG和CR4.PAE等影响IA-32e模式开启的标志位,处理器会进行64位模式的一致性检测,以确保处理器不会进入未定义模式或不可预测的运行状态。如果一致性检测失败,处理器将会产生通用保护性异常(#GP )。以下境遇会导致一致性检测失败。
- 当开启分页机制后,再试图使能或禁止IA-32e模式。
- 当开启IA-32e模式后,试图在开启物理地址扩展(PAE)功能前使能分页机制。
- 在激活IA-32e模式后,试图禁止物理地址扩展( PAE )。
- 当CS段寄存器的L位被置位时,再试图激活IA-32e模式。
- 如果TR寄存器加载的是16位TSS段结构。