购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.2.3 页表的原理

相比于实模式,保护模式最重要的变化就是引入了虚拟内存,虚拟内存是保护模式的核心概念。有了虚拟内存,每个进程才能独享4GB的地址空间,而且程序员也不用担心会与其他进程相互影响。但同时,CPU要访问真实的物理内存时必须使用物理地址。这就要求CPU有能力将线性地址转换成物理地址。

负责将虚拟内存地址翻译成物理内存地址的模块叫作MMU(Memory Management Unit,内存管理单元),它是现代CPU内存管理的核心。而MMU要使用一个结构来辅助地址翻译,这个结构中维护着虚拟内存和物理内存的映射关系,这个结构就是页表(Page Table)。页表数据保存在内存中,是操作系统加载运行以后由操作系统主动创建的,也就是说页表和全局描述符表都是由软件维护的,并且供硬件使用的一个数据结构。

页的本质就是一块整齐的大内存。大多数操作系统默认设置页的大小为4KB,这是一个综合了多种因素而得到的最优选择。在一些特殊的场景下,有些操作系统会把页面设得更大。但从学习操作系统内核的角度,一开始就认为页的大小是4KB是没什么问题的。

1.物理页面映射

虽然虚拟内存提供了很大的空间,但实际上进程启动之后,这些空间并不是全部都能使用的。开发者必须使用malloc等分配内存的接口才能将内存从待分配状态变成已分配状态。

得到一块虚拟内存以后,这块内存就是未映射状态,因为它并没有被映射到相应的物理内存,直到对该块内存进行读写时,操作系统才会真正地为它分配物理内存。然后这个页面才能成为正常页面。这个过程当然还依赖CPU的缺页中断机制,在实现操作系统内核的过程中,很长一段时间都不会涉及缺页中断,所以这部分内容被安排在第7章实现execve函数时再详细介绍。

在虚拟内存中连续的页面,在物理内存中不必是连续的。只要维护好从虚拟内存页到物理内存页的映射关系,开发人员就能正确地使用内存。这种映射关系是操作系统通过页表来自动维护的,如图2-4所示。图2-4中展示了两个进程的页表,左侧是进程1的页表,右侧是进程2的页表。页表中的每一项叫作PTE(Page Table Entry,页表项)。每一个PTE对应一个物理页面,这种对应关系被称为页面映射(Mapping)。

图2-4 页面映射示意

页的大小是4KB,那么用于页内地址编码的长度就是log 2 4096=12位,32位地址还有20位用于编码PTE的索引。换言之,4GB的虚拟内存需要使用1M个PTE进行映射。每个PTE的大小是4B,所以理论上创建一个进程,它自己的页表就占据了4MB的空间。实际上,进程的地址空间中有大量空间是从不使用的,这些空间所对应的PTE并不需要保留在内存中,为了避免页表过大,人们进一步引入了多级页表。

2.多级页表

将1024个PTE组成一张页表,因为每个PTE的大小是4B,所以一张页表的大小刚好就是4KB,占据一个内存页,这样管理就更加方便。

一个页表项对应着一个大小为4KB的页,所以1024个PTE所能支持的空间就是4MB。那为了编码更多地址,系统就必须使用更多的页表。为了管理这些页表,人们进一步引入了页表的数组:页目录表。

页目录表中的每一项叫作PDE(Page Directory Entry,页目录项),每个PDE都对应一个页表,它记录了页表开始处的物理地址,这就是多级页表结构,如图2-5所示。为了编码更大的空间,现代的64位处理器上还设置了更多级的页表。

图2-5 多级页表

有了多级页表(见图2-5)以后,CPU要通过虚拟地址找到物理地址就需要以下4个步骤。

1)确定页目录基地址。每个CPU都有一个特殊寄存器,最高级页表的基地址就存在于这个寄存器里。在x86上,这个寄存器是cr3。cr3寄存器又叫作PDBR(Page Directory Base Register,页目录基地址寄存器)。每一次计算物理地址时,MMU都会从cr3寄存器中取出页目录所在的物理地址。

2)定位PDE。一个32位的虚拟地址可以拆成10位、10位和12位三段,上一步找到的页目录表基地址加上高10位的值再乘以4就是PDE的位置。这是因为,一个PDE正好是4B,所以1024个PDE共占据4096B,刚好组成一页,而1024个PDE需要10位进行编码。这样,CPU就可以通过最高10位找到该地址所对应的PDE了。

3)定位PTE。PTE里记录着页表的位置,CPU通过PDE找到页表的位置以后,再用中间10位计算页表中的偏移,就可以找到该虚拟地址所对应的页表项了。PTE的大小是4B,所以一页之内刚好也是1024项,用10位进行编码。所以计算公式与上一步相似,用页表基地址加上中间10位再乘以4,可以得到PTE的地址。

4)确定真实的物理地址。上一步CPU已经找到PTE了,这里存储着物理地址,这才真正找到该虚拟地址所对应的物理页。虚拟地址的低12位刚好可以对一页内的所有字节进行编码,所以我们用低12位来代表页内偏移。计算的公式是物理页的地址直接加上低12位。

页总是4KB地址对齐的,这意味着每个页的起始地址都是4KB对齐的,每个页表占一个页,所以页表的起始地址也是4KB对齐的。也就是说,起始地址的低12位都是0。PDE和PTE的大小是32位,它们的低12位就空闲出来,CPU可以使用这些位进行权限管理。这对页管理机制至关重要,下一节就来详细分析PDE和PTE的结构。

3.页目录项和页表项的结构

由前可知,PDE中存储着页表基地址,这个地址只会占据高20位,而低12位用不到,所以CPU把低12位用于属性管理了。

PDE的详细结构如图2-6所示。

图2-6 PDE结构

PTE的详细结构如图2-7所示。

图2-7 PTE结构

从PDE和PTE两个结构的对比可以看出,两者的区别主要是第6位和第7位,除此之外,其他的属性位都是相同的。所以,这里就将这两个结构的各个属性合并起来讲解。以下是每个属性的具体作用。

❑P位:指示当前表项指向的页是否在物理内存中。值为1代表在内存中,值为0代表不在内存中,当CPU试图访问不在物理内存中的页时,就会产生缺页中断。操作系统必须处理这个中断,为该表页所代表的线性地址分配物理内存,也就是建立从线性地址到物理地址的映射关系。

❑R/W位:指示当前表项指向的页的读写权限。该位为0表示只读,为1表示可读、可写。该位与U/S位和cr0中的WP(Write Protection,写保护)位相互作用。确保特定特权级的指令有权限对页面进行读写操作。

❑U/S位:指示一个页的特权级。如果CPU当前特权级是0、1或者2,该位就是0,

表示系统级别(Supervisor Privilege Level)。如果当前特权级为3,该位就是1,表示用户级别(User Privilege Level)。

R/W位和U/S位,以及WP位之间会相互影响。如果WP位为0,用户级页面的R/W位为0,系统级程序依然可以对页面进行写操作。如果WP位为1,则系统级程序不能写入用户级只读页。

❑PWT位:控制页的缓存(Cache)策略,该位为0时,缓存写采用写回(Write Back)策略,为1时,采用写直达(Write Through)策略。当cr0寄存器的CD(即Cache Disable,可理解为缓存有效位)位为1时,则PWT位不起作用。

❑PCD位:用于控制对单个页的缓存,为0时页可以被缓存,为1时页不可以被缓存。当cr0寄存器的CD位为1时,PCD位不起作用。

❑A位:用于指示页是否被访问。当页面被加载到物理内存中以后,处理器第一次访问此页时设置这一位。处理器不会自动清除此位,需要软件来清除。Linux的内存管理没有使用这一位来标识是否访问过。

❑D位:用于指示页是否被写入。此位为1时表示该页被写入。当页被加载进物理内存后,处理器第一次写入此页时设置该位。处理器不会自动清除此位,需要软件清除。脏页面是内存管理的核心概念之一,它往往意味着内存中的值与硬盘设备上的内容不一致,需要软件来进行数据同步。在后面的缓冲区管理部分我们会看到这一点。Linux采用了软件的手段来自己维护页面状态,没有使用D位。

❑PS位:决定页的大小,为0时代表页大小为4KB。

❑PAT位:在Linux中未使用,此处设为0即可。

❑G位:指示当前页是否是全局页。如果此位置位,那么此页的页表或者页目录项就不会在TLB中失效。

至此,保护模式下的内存管理机制就全部介绍完了。下一节将会实现从实模式向保护模式的跳转。 0aoSowUnkBhaLXIhbigzKX6WeQZhHHNZzS1Mb37rk18EsFFgD2655qkTcQby5LAf

点击中间区域
呼出菜单
上一章
目录
下一章
×