IA-32保护模式下的内存寻址方式(二):分页

有关IA-32分段可参考:IA-32保护模式下的内存寻址方式(一):分段

1、分页、页、页框、缺页异常、页表的概念简述:

MMU的分页单元(Paging unit)会把通过MMU分段单元(segmentation unit)计算得到的线性地址再次进行计算转化得到物理地址。分页单元除了进行地址计算,还有一个重要的任务就是要进行权限检查:将请求的访问类型(权限级别)和线性地址的访问权限(DPL,在段描述符中)进行比较,如果访问无效,则产生一个缺页异常。

那么何为页?页指的是线性地址被分成以固定长度为单位的组。一页即一组、一个单位(如单位大小为4KB则一页即4KB)。那么指定一页的访问权限就是指定这整个页所有地址的访问权限。而何为页框?页框指的是分页单元把所有的RAM分成固定长度的页框(或物理页)。每一个页框包含一个页,但是页不一定在页框中。页可以在RAM中(映射到了页框里)或磁盘上(未被映射到物理内存中)。那么如果访问的一个线性地址经过MMU的权限检查,但是该页不在内存中映射,就会产生一个缺页异常,需要时就要将对应的页映射到内存中去,而部分页可能会被替换到磁盘中去。

缺页异常:CPU通过地址总线可以访问连接在地址总线上的所有外设,包括物理内存、IO设备等等,但从CPU发出的访问地址并非是这些外设在地址总线上的物理地址,而是一个虚拟地址,由MMU将虚拟地址转换成物理地址再从地址总线上发出,MMU上的这种虚拟地址和物理地址的转换关系是需要创建的,并且MMU还可以设置这个物理页是否可以进行写操作,当没有创建一个虚拟地址到物理地址的映射,或者创建了这样的映射,但那个物理页不可写的时候,MMU将会通知CPU产生了一个缺页异常。(来自:缺页异常详解)

页表:线性地址需要映射到物理地址中去,程序才能正常运行。而把线性地址映射到物理地址的数据结构被称为页表(page table)。页表存放于主存之中,并且在启用分页单元之前必须由内核对页表进行初始化(这虽然牵扯到操作系统内核,但对分页单元的初始化来说内核无特例)。从80386开始,所有的80x86处理器都支持分页,分页单元启动与否由CPU的CR0寄存器的PG标志位(CR0第31位)决定。PG清除则关闭分页机制,PG置位则启用分页。当禁用分页时,所有线性地址都被视为物理地址。 如果PE标志(CR0的第0位)未被置位,则PG标志无效; 实际上,当PE标志清除时设置PG标志会导致生成一般保护异常(#GP)。 PE和PG组合如下所示:

IA-32保护模式下的内存寻址方式(二):分页_第1张图片

IA-32的CR0寄存器如下所示:

IA-32保护模式下的内存寻址方式(二):分页_第2张图片

由于对于不同厂商、不同CPU型号其分页方式不尽相同,但是基本原理都是一样的。这里我们就IA-32的三种分页方式(80386开始导入的常规分页机制、Pentium开始导入的扩展分页机制、Pentium Pro开始导入的物理地址扩展(PAE)分页机制)进行学习。

2、常规分页:

常规分页方式,是将32bit的线性地址分成三部分:页目录项偏移量10bit+页表项偏移量10bit+页内偏移量12bit

如果是常规分页或扩展分页,CR3寄存器中存放页目录基址(所以CR3也叫页目录基址寄存器,PDBR);
如果是物理地址扩展分页,则CR3存放页目录指针表基址(所以CR3也叫也目录指针表基址寄存器,PDPTR)。

我们先来说PDBR:每个活动的进程必须有一个分配的页目录,正在使用的页目录基址存放在CR3中(注意:不必要为每个页表都分配RAM,当进程实际需要一个页表时,才会给该页表分配RAM)。页目录的基地址Base由高 20 位确定(从CR3中取出),低 12位是 0,所以页目录的地址必须是页边界对齐的(4KB)。CR3(PDBR)的结构如下所示:

IA-32保护模式下的内存寻址方式(二):分页_第3张图片

常规分页步骤读取CR3高20bit并在低12bit 补0,得到页目录的基址,页目录基址加上页目录偏移量索引到页目录项;读取页目录项得到页表基址,页表基址再加上页表偏移量得到页表项;读取页表项获取页基址,根据页基址和页内偏移量便可得到一个线性地址的物理地址。具体结构与流程如下图所示:

IA-32保护模式下的内存寻址方式(二):分页_第4张图片

其中Directory和Table均为10bit(注意:这10bit只是索引,不是偏移的字节数,乘以页目录项/页表项的大小4,才是偏移字节数),则页目录项和页表项均为1024(2^10=1024)项,因此一个页目录可以寻址达:1024×1024×4KB = 2^32 = 4GB个单元。和32bit线性地址寻址预期能力相同。关于页目录项和页表项的具体内容,在扩展分页之后再统一说明。

3、扩展分页:

扩展分页是从Pentium模型开始,加入到80x86微处理器中的,其允许页框大小为4MB而不是4KB,去掉了中间页表,只采用一级目录来进行地址转换,节省了内存空间。32bit的线性地址分为两部分:页目录偏移高10bit+页内偏移低22bit(2^22 = 4MB)。通过设置CR4寄存器的PSE标志位,就能使扩展分页与常规分页共存,至于到底是4KB分页还是4MB分页,就得看页目录项的Page Size标志的具体内容了。
IA-32的CR4寄存器如下图所示:
IA-32保护模式下的内存寻址方式(二):分页_第5张图片
扩展分页步骤:读取CR3高20bit并在低12bit 补0,得到页目录的基址,页目录基址加上页目录偏移量索引到页目录项;读取页目录项得到页基址,根据页基址和页内偏移量便可得到一个线性地址的物理地址。具体结构与流程如下图所示:
IA-32保护模式下的内存寻址方式(二):分页_第6张图片

其实在扩展步骤中,我们仅仅描述了能够进行地址转换的步骤,并没有对相应标志进行检查(比如检查Page Size标志来确定下面索引的是页表还是页框,即是二级目录还是一级目录)。下面,我们就具体来分析页目录项和页表项的具体内容。

4、常规分页和扩展分页的页目录项与页表项结构:

那么常规分页和扩展分页的结构和流程知道了,页目录项和页表项的格式分别是怎样的?页目录项和页表项结构大部分相同,如各项中的下一索引对象的页基址等。结构分别如下:

①常规分页(4KB)的页目录项:
IA-32保护模式下的内存寻址方式(二):分页_第7张图片

②常规分页(4KB)的页表项:
IA-32保护模式下的内存寻址方式(二):分页_第8张图片

③扩展分页(4MB)的页目录项:
IA-32保护模式下的内存寻址方式(二):分页_第9张图片

各字段含义解释:

(1)P(Present):存在标志。该标志表明表项所指的页或者页表当前是否在内存中。该标志置位时,则页在物理内存中,将执行地址转换。该标志清零时,表示页不在内存中,如果处理器试图访问该页,将产生一个页故障异常(#PF)。处理器并不置位或者清零该位;而是由操作系统或者管理程序来维护该标志的状态。 如果处理器产生一个页故障异常,操作系统一般情况下必须执行如下操作:

①将页从磁盘复制到内存中;
②将页地址装入页表项或者页目录表项中并设置它的存在标志(P=1)。其它标志位,比如脏位(D位)和访问位(R/W位),也必须同时设置;
③使 TLB 中的当前页表项失效;
④从缺页异常处理程序返回,重新执行被中断的进程或任务。

(2)R/W(Read/Write):读写标志。该标志确定对一个页或者一组页(当它是一个指向页表的页目录表项时)的读写权限。当这个标志被清零时,该页是只读的;当这个标志被置位,该页是可读可写的。该标志与 U/S 标志和 CR0 寄存器中的 WP 标志是相互影响的(具体可参考Intel Architecture Software Developer’s Manual Volume 3: System Programming:Table 4-2. Combined Page-Directory and Page-Table Protection)。

(3)U/S(User/Supervisor):用户/管理者标志。该标志确定一个页或者一组页是用户特权还是管理特权。当这个标志被清零,则页被赋予管理特权;该标志置位时,则页被赋予用户特权。

(4)PWT(Write-through):页级通写标志。控制单个页(页表)的通写(Write-through)或者回写(Write-back)高速缓存策略。当 PWT 标志被置位时,为通写;当 PWT 标志被清零时,为回写策略。

通写与回写
①通写:控制器既写高速缓存,也写对应的RAM内存;
②回写:控制器仅更新高速缓存,不更新RAM。

(5)PCD(Page Cache disabled):页级高速缓存禁用标志。控制单个页或者页表的高速缓存。当该标志被置位时,相关页或者页表的高速缓存被禁止;当该位被清零时,相关页或页表可以被高速缓存。这个标志可以用来禁止高速缓存包含内存映射 I/O 端口的页或者即使被高速缓存,也不能对性能有提高的页。

CR0与PWT和PCD
①处理器的CR0寄存器的CD(高速缓存禁用)标志位用来控制是否启用高速缓存。 CD标志被置位时,处理器将忽略PCD标志,即高速缓存被禁用,CD被清零时,高速缓存被启用。
②处理器的CR0寄存器的NW(不通写)标志位用来指明高速缓存是通写还是回写策略(在CD清零时有效)。当 NW 和 CD 标志都置 0 时,则开启命中高速缓存的写操作的回写(对 Pentium 4、Intel Xeon、P6 系列和 Pentium 处理器而言)或通写(仅对 Intel486处理器而言)。

(6)A(Accessed):访问标志。指明页或页表是否曾经被访问过。内存管理软件通常会在页或者页表被载入内存时,清零该位。当页或者页表第一次被访问以后,处理器会置位该标志。

(7)D(Dirty):脏位。指明页是否曾经被写入过(在指向页表的页目录表项中,不使用该标志,即只有页表项有该标志)。通常,内存管理软件在页刚被载入内存时,将该标志清零。当页的第一次写操作完成后,处理器置位该标志。

A和D这两个标志具有“粘性”,就是说,一旦被设置,处理器不会隐式地对它清零。只有软件可以对它清零。内存管理软件使用访问位A和脏位D来调度页或者页表进出物理内存。

(8)PS(Page Size):页尺寸标志。该标志仅被用于页目录表项。当该标志被清零时,页尺寸为 4KB,页目录表项指向一个页表。当该标志被置位时,页的尺寸为 32 位寻址的 4MB(当PAE启用时,页的尺寸为2MB),页目录表项指向一个页。如果页目录表项指向一个页表,所有与那个页表相关的页都是 4KB(PS标志决定寻址的级数,一级/二级)。

(9)G(Global page):全局标志,只应用于页表项。(Pentium Pro 处理器引入的)指明全局页。当一个页被标明为全局的,并且 CR4 中的启用全局页(PGE)标志被置位时,一旦 CR3寄存器被载入或者发生任务切换,TLB 中的页表或者指向页的页目录表项并不失效。这个标志可以防止使 TLB 中频繁使用的页(比如操作系统内核或者其它的系统代码)失效。只有软件可以置位或者清零该位(在 Pentium 和更早期的IA-32 架构处理器中,该位是被保留的)。

(10)Avail:保留可供软件使用的位。

(11)Base Address:基址。对于4KB分页(即二级寻址),该字段为20bit加上12bit置0信息(4KB对齐),共32bit作为页表或页的基址。对于4MB分页(即一级寻址),该字段为10bit加上22bit置0信息(4MB对齐),共32bit作为页的基址(此时就不存在页表了)。

5、物理地址扩展(PAE)分页:

物理地址扩展分页是由Pentium Pro引入的,将CPU的32位管脚增加到36位。因此可寻址的范围可达2^36=64GB。通过设置CR4寄存器的PAE标志位,可以激活PAE(页目录项中的页大小标志PS启用大尺寸页,在PAE启用时为2MB)。而Intel为了支持PAE已经改变了分页机制:

①64GB的RAM被分为2^24个页框。页表项的物理地址字段从20bit增加到24bit(36-12=24)。因为PAE页表项必须包含12个标志位和24个物理地址位,总数为36bit,页表项大小从32bit变为64bit,增加了一倍,因此一个4KB的页表就只能包含512项而不再是1024项。

②引入了页目录指针表(Page Directory Pointer Table,PDPT)的页表新级别,PDPT由四个64bit的表项组成。PDPT的表项指向页目录项。

③CR3寄存器中存放的就不再是页目录基址,而是页指针表基址。因此CR3不再是PDTR而是PDPTR(Page Directory Pointer Table Register),因为PDPT存放在RAM的前4GB中,并在32字节(2^5)的倍数上对齐,因此CR3中需要27bit来存放PDPT的基址。CR3(PDPTR)如下所示:

这里写图片描述

而PAE有三级寻址和二级寻址的区别,类似于常规分页和扩展分页。PAE的三级寻址页的大小和常规分页一样,均为4KB(4GB/4/512/512=4KB);但是PAE的二级寻址页大小为2MB(4GB/4/512=2MB)而不是扩展分页的4MB(注意:PAE没有扩大进程的线性地址的空间,依旧是32bit,只不过是对于物理地址变成了36位,进程能访问的地址依旧由32bit线性地址决定为4GB)。PAE对于32bit的线性地址的两种解释方式结构分别如下:

4KB分页:
IA-32保护模式下的内存寻址方式(二):分页_第10张图片

4KB分页为三级目录,这三级目录的页指针表项、页目录表项以及页表项的结构分别如下所示:
IA-32保护模式下的内存寻址方式(二):分页_第11张图片

2MB分页:
IA-32保护模式下的内存寻址方式(二):分页_第12张图片

2MB分页为二级目录,这二级目录的页指针表项、页目录表项的结构分别如下所示:
IA-32保护模式下的内存寻址方式(二):分页_第13张图片

分段分页我们都有了了解,那么对于MMU地址转换的主要工作也就可以比较清晰了,如下图所示(常规分页方式为例):
IA-32保护模式下的内存寻址方式(二):分页_第14张图片

最后,我们将不同标志位与页尺寸以及物理地址的关系进行总结,如下表所示:
IA-32保护模式下的内存寻址方式(二):分页_第15张图片
而至于更多分页方式(如64系统中的分页方式),只不过是对于现有的分页方式的目录层级数以及各级目录的项数以及具体细节进行了改变/增加,其核心思路依旧是采用多级目录的方式。

参考书籍资料:
《Intel Architecture Software Developer’s Manual volumn 3:System Programming》(《IA-32卷3:系统编程指南》)
Daniel, P, Bovet, &, Marco, Cesati. Understanding the Linux Kernel[M]. California:O’Reilly Media, 2005.(《深入LINUX内核》(第三版))

你可能感兴趣的:(Intel,80x86架构【P6微架构】)