深入详解保护模式下的内存分页机制


转载自http://blog.csdn.net/jn1158359135/article/details/7106383


386及更高型号处理器使用内存分页机制,这使得同一个线性地址可以被映射为多个物理地址,这种映射是通过分页单元这一特殊的硬件电路实现的。通常程序中所使用的线性地址是由链接器帮我们产生的,而操作系统通过维护每个进程私有的页目录和页表实现线性地址与物理地址之间的转换,转换过程对于进程来说是透明的。此外正如保护模式下的段寄存器提供对整个段的访问控制一样,分页单元在更细粒度的页级层面上提供对整个页的保护机制,例如当前页是否可读或可写,访问该页所需的最小特权级以及该页是否已被交换至磁盘从而产生一个缺页异常,我们将逐渐深入了解这种机制的实现原理。

何谓页?
首先要明白什么是页?从抽象意义上来讲页是一个具有固定尺寸的窗口,从逻辑意义上来讲页是具有固定大小的一组连续线性地址的集合。而每个页实际对应的物理内存则被称为页框,这意味着一个页框的尺寸必须和一个页相匹配。通常我们在引用页时指的是页内所存储的数据,引用页框时指的是内存地址空间。一个页的大小可以指定为4KB(212=4KB)的任意倍数,这根据不同的体系结构或操作系统的设置而定,而x86架构下的Windows/Linux均采用4KB大小的分页方式,这就说明32位线性地址中必定存在一个12位的指示页内偏移量的域,我们将在后续的线性地址与物理地址之间的转换部分看到线性地址的具体组织。

相关控制寄存器
处理器中与分页单元有关的寄存器为CR0~CR3控制寄存器,其中CR1被处理器保留,CR2寄存器则用于存放页故障线性地址,当根据某个线性地址所寻址的页不在内存中时将触发一个缺页异常,此时处理器负责将该线性地址加载至CR2寄存器从而把适当的页重新加载到内存中。与分页单元联系最紧密的当属CR0和CR3控制寄存器,其中CR0寄存器中各个位的组织结构如下所示:


图1-1

其中比较重要的几个位及其更详细的解释如下:

  • PG=0时禁用分页机制,PG=1时则启用分页机制。若禁用分页那么线性地址与物理地址一一对应,但通常将该位置1以启用分页机制,此时线性地址需要通过分页单元的转换才能形成物理地址。

以下是Intel文档中关于分页机制的详细描述:
IA-32 Memory Models
When employing the processor’s memory management facilities, programs do not       — 使用处理器内存管理设施时程序不会
directly address physical memory. Instead, they access memory using one of three          直接寻址物理内存
memory models: flat, segmented, or real address mode:

• Flat memory model — Memory appears to a program as a single, continuous    — 内存对于程序来说就是一个单一连续的地址
address space (Figure 3-3). This space is called a linear address space. Code,      空间,这被称为线性地址空间。要注意此时的
data, and stacks are all contained in this address space. Linear address space is      线性地址是保护模式下的
byte addressable, with addresses running contiguously from 0 to 232 - 1 (if not in
64-bit mode). An address for any byte in linear address space is called a linear
address
.

• Segmented memory model — Memory appears to a program as a group of    — 对于程序来说就像一系列独立的地址空间的内存
independent address spaces called segments. Code, data, and stacks are                 被称为段。注意关键的地方来了,先解释一下:
typically contained in separate segments. To address a byte in a segment, a           为了在段内寻址一个字节,程序形成了一个
program issues a logical address. 
This consists of a segment selector and an     逻辑地址。它由段选择子和一个偏移量所组成。
offset (logical addresses are often referred to as far pointers)
. The segment        (注意只有保护模式下的段寄存器中才会
selector identifies the segment to be accessed and the offset identifies a byte in               有段选择子)
the address space of the segment. Programs running on an IA-32 processor can
address up to 16,383 segments of different sizes and types, and each segment
can be as large as 232 bytes.

• Real-address mode memory model — This is the memory model for the Intel     — 这个内存模型是为8086处理器所使用的,使用
8086 processor. It is supported to provide compatibility with existing programs           它是为了与运行在8086上的已有程序提供兼容性。
written to run on the Intel 8086 processor. The real-address mode uses a specific
implementation of segmented memory in which the linear address space for the
program and the operating system/executive consists of an array of segments of
up to 64 KBytes in size each. The maximum size of the linear address space in    注意这里:线性地址空间的最大尺寸为1MB,
real-address mode is 220 bytes.                                                                               说明该内存模型在实模式下使用。


Paging and Virtual Memory
With the flat or the segmented memory model, linear address space is      — 最重要的地方来了:在平坦或是段式内存模型
mapped into the processor’s physical address space either directly or        下,线性地址或是直接或是通过分页方式被映射到
through paging. When using direct mapping (paging disabled), each linear     处理器的物理地址空间。当分页禁用而直接映射
address has a one-to-noe correspondence with a physical address. Linear      时线性地址与物理地址一一对应。线性地址不
addresses are sent out on the processor's address lines without translation.         通过转换而直接送至处理器的地址空间中。


When using the IA-32 architecture’s paging mechanism (paging enabled), linear     — 当使用32位体系结构的分页机制时,线性
address space is divided into pages which are mapped to virtual memory.              地址空间被分割成映射至虚拟内存的页。随后
The pages of virtual memory are then mapped as needed into physical memory.   虚拟内存中的这些页被映射至物理内存。
When an operating system or executive uses paging, the paging mechanism     (这里直接略过虚拟内存,和我们的分析无关)
is transparent to an application program. All that the application sees is 
linear address space.

由上述最后一段话我们发现分页机制的实施只囊括了平坦内存模型(Flat Memory Model)或段式内存模型(Segmented Memory Model),而这两种模型根据分析知道都是在保护模式下才存在,处理器的分页机制压根就没有提及实地址模式内存模型,因此在实模式下无法使用分页机制。

  • PE位用于实模式与保护模式之间的转换。
  • CD位用于启用或禁用高速缓存,注意这里的高速缓存所对应的是L1,L2数据或指令高速缓存而并非是用于加速线性地址转换的TLB。
  • NW位指示高速缓存是采用通写还是写回策略,这两种策略简单来讲就是:若采用通写则在更新cache的同时也更新与其对应的RAM;而写回则延迟写RAM的时间,只有当cache采用某种替换策略将当前行的数据进行覆盖时才有可能将数据写回对应的内存,因此这有可能导致数据之间的不一致性,除非显示使用刷新高速缓存的指令或者产生一个FLUSH硬件信号时才将高速缓存行写回到RAM中。
  • AM位与EFLAG寄存器中的AC位一起起来,指示处理器是否检查内存对齐,当该位清零时不论AC位为何值都将禁用内存对齐检查。
  • WP位用以实现写时拷贝机制。该机制的原理为当父进程调用fork()产生子进程时,父子进程共享相同的内存地址空间,当其中的某个进程对可写的数据段实行更新操作时,将复制该数据段同时修改相应进程的页表项以指向新的数据段。注意代码段是只读的,因此更新操作只可能发生在数据段上,而堆栈段由于用来保存进程的局部变量,因此堆栈段总是独有的。

其余的位在执行浮点指令时使用,当存在数字协处理器时,可通过设置相应的位将浮点指令交由专用的处理器执行。

下面是CR2和CR3寄存器:


图1-2

其中CR3寄存器存放页目录的基地址。有关PCD和PWT位的详细解释如下:
(引自《Pretected Mode Software Architecture》Tom Shanley,MindShare著)
Page Directory Cacheability
The processor must be instructed as to whether or not the locations within the        —处理器被指示在页目录内的本地表项是否
page directory may be cached or not.This is accomplished with CR3[PCD].(see       被缓存,这是通过CR3寄存器中PCD位完成
Figure 13-15 on page 257). CR3[PCD]=0 permits the processor to cache entries      的。PCD=0 那么允许处理器缓存页目录
from the page directory, while CR3[PCD] = 1 inhibits caching from the directory.     中的表项,PCD=1则禁用缓存
The section that follows this one describes how the processor           —这句话与下文的第一句话重复,只在这里解释一下它的
handles memory writes to the page directory when                                含义:若当前位置位(PCD),下一个
it is marked cacheable.                                                                              区域(指PWT位)指示对页目录内存写策略

Page Directory Wirte Policy

This section describes how the processor handles memeory wirtes to page directory
entries when the directory is marked cacheable(CR3[PCD]=0). The manner in which        
the memory write is handled depends on the following factors:                —内存写方式依赖于一下两个因素:
• The state of CR3[PWT]. This is the page write-through bit.                      CR3寄存器中的PWT位指示页的通写位
• Whether the write results in a data cache hit or miss.                            写导致的数据高速缓存是否命中
                                                                                                                 (我们在这里解释PWT位,因此忽略该要素)

……PWT=1,indicating that the write data must also be written to       —PWT位置1指示写缓存数据的同时必须写外存
external memory.The processor therefore initiates a memory write      处理器因此发起内存写事物以更新内存中的
transaction to update the page directory entry in memory.
……Using a        相应页目录项
write-through policy ensure that the page directory in memory is always kept up
to date.……PWT=0,indicating that the write data doesn't necessarily have       —PWT清零则指示写缓存数据时
to be written to external memory(this is referred to as a write-back policy)         不必同时写外存。

There are three possible cases and the handling of the write is case-dependent:……
上述翻译中的外存实际指的就是内存,因为cache是在处理器上的,所以计算机的内存对于它来说也就变得像是”外部存储器“了。


分页机制的实现
在启用分页机制后,32位的线性地址被划分成3个域:

  • Directory(目录),在线性地址中为最高10位,用于访问页目录表中的项。
  • Table(页表),在线性地址中为中间10位,用于访问页表中的项。
  • Offset(偏移量),最低12位,用于访问页内的某个存储单元。

如下图所示:


图1-3

线性地址的转换分两步完成:首先由CR3寄存器中的页目录基地址域找到相应的页目录表,通过线性地址中的目录域找到对应的页目录项,随后根据页目录项中存放的页表的基地址找到相应的页表,再通过线性地址中的页表域找到相应的页表项,最后根据页表项中存放的页的基地址及线性地址中的偏移量便完成了线性地址到物理地址的转换。上述转换过程如下图所示:

图1-4

举例:现假设进程读线性地址0x2011 1230(二进制形式为0010 0000 0001 0001 0001 0010 0011 0000)中的一个字节。

  1. 页目录域占用最高的10个位,因此其值为0010 0000 00,在高位补齐两个0得到0000 1000 0000,转换为16进制即0x080。
  2. 页表域占中间的10个位,其值为01 0001 0001,同样在高位补齐两个0形成的16进制索引为0x111。
  3. 偏移量占最低的12个位,因此我们直接得到该字节在页内的偏移量为0x230。


系统中的每个进程必须有且仅有一个页目录,且在该进程的生命周期内该页目录必须常驻内存。因为线性地址中的目录域为10位,因此可寻址的页目录项多达210=1024个,对于线性地址中的页表域也是如此,又因为一个页目录项/页表项占4个字节,所以任意一个页目录或页表恰好占据一个物理页框。同时因为偏移量的数据位宽度为12,因此可寻址整个页内的任意一个字节(212=4096)。此外,由于一个页目录或页表存在1024个表项,所以一个页目录对应1024个页表,一个页表对应1024个页,因此一个进程可寻址的内存空间为1024×1024×4096B=232=4GB。

采用二级分页模型的好处是系统使用相对较少的内存更为简单地实现了地址之间的转换。考虑一个一级分页模型,假定32位线性地址被分成20位的页表域以及12位的偏移量,那么即使某个应用小到只需一个物理页框便可运行,系统仍将为整个页表分配4MB的内存空间,因此产生了极大的浪费,而使用二级分页模型,则只需为页目录分配一个物理页框并初始化首个页目录项,随后再为页表分配一个页框并初始化首个页表项即可,此时总共只消耗了8KB的物理内存,而如果使用三级分页模型,虽然较之于前两者,其内存利用率更高,但带来的问题是管理的复杂度增加,线性地址的转换速度降低。


以下是4字节的页目录项和页表项的组织形式:


图1-5
  • 页框基地址标志(Field域):指示页表或页的基地址。
  • Present标志(P位):在页目录/页表项中,该标志位置1表示对应的页表或页驻留在内存中,反之则说明不在内存中。若在地址转换过程中发现该位为0,分页单元将该线性地址放入CR2控制寄存器中,并产生缺页异常。
  • Read/Write标志(R/W位):在页目录/页表项中,Read/Write标志清零表示相应的页表或页是只读的,否则为可读可写。
  • User/Supervisor标志(U/S位):指示访问页表或页所需的特权级,若该标志为0,那么当前特权级小于3时才能对相应的页表/页寻址,反之则总能对相应的页表或页进行寻址。
  • PWT和PCD标志:用于控制高速缓存对页表/页的处理方式。
  • Accessed标志(A位):当分页单元对物理页框寻址时设置该标志位。注意分页单元不会重置这个标志,置位操作必须由操作系统执行。
  • Dirty标志(D位):只在页表项中存在该标志位,当对某个物理页框执行写操作时设置该位。操作系统在调度时根据该位判断是否将该页写回磁盘,以此来保证数据之间的一致性要求。同Accessed标志一样分页单元从不重置该标志,而是交由操作系统完成。
  • Page Size标志(PS位):该位只在页目录项中使用。若该位置1,则启用扩展分页机制——即将二级分页模型切换为一级分页模型,32位线性地址被分为10位的页目录域以及22位的偏移量域。


基于对局部性原理(locality principle)的考虑,因此引入高速缓存作为提升系统性能的一种方式。通常执行一条指令只需一个时钟周期,而取指阶段的内存寻址却需花费上百个时钟周期,所以若每次执行时都从内存中取指无疑极大地浪费了计算资源。由此在处理器与内存之间架设一层或多层特殊的存储结构,将内存中的指令及数据映射至相应的高速缓存行,那么对于局部性良好的程序,在大多数情况下直接对高速缓存进行操作即可。由于数据可读可写,因此一旦对数据进行写操作将导致存储层次结构中的数据一致性遭到破坏。基于这个原因,处理器提出了通写与写回这两种策略,其中通写策略在处理器写高速缓存的同时更新对应的内存,而写回策略则在写高速缓存时并不马上对内存更新,而是当高速缓存发生行替换时才更新相应内存,或者通过专用指令显示要求处理器马上执行更新操作。

以上是对高速缓存的粗略介绍,现实中需要考虑的问题还有很多:比如采用何种方式为内存及高速缓存建立映射,这样当进行地址转换之后直接利用物理地址地址访问相应的高速缓存。并且高速缓存又可分为直接映射高速缓存,N-路组相联高速缓存,全相联高速缓存,选取何种形式组织相应的高速缓存行更为合适。而替换策略又分为最近最少使用(LRU),先进先出(FIFO)策略等等。

L1-i/L1-d/L2 cache
处理器上的L1高速缓存分为两个部分,其中一部分用于存放执行的指令,称为L1-i cache,另外一部分用于存放待处理的数据,称为L1-d cache。在处理器外部的L2高速缓存并不细分,因此又称其为统一高速缓存。根据CR0控制寄存器(如图1-1)中的CD标志位来选择启用或禁用这一类高速缓存,NW位指明当缓存发生更新时的内存写策略。而CR3控制寄存器中的PCD/PWT位则指示页目录是否缓存及相应的内存写策略,页目录项及页表项中的PCD/PWT位指示对相应的页表及页是否启用缓存和内存写策略。

TLB(转移后备缓冲区 Translation Lookaside Buffer)
这类缓存主要用于存放物理地址以加速对线性地址的转换操作。当线性地址被第一次使用时,通过页目录/页表计算得出相应的物理地址,这个地址在使用后将被缓存在TLB中,以备将来对同一线性地址引用时直接从TLB中得到其对应的物理地址。这里还要注意的是,当CR3控制寄存器被更新时,硬件将自动使TLB中的所有项均无效,因为CR3被更改后将存放新的页目录基地址,所以线性地址转换时不允许再引用TLB中的表项。

※物理地址扩展(PAE  — Physical Address Extension)下的分页机制
引入物理地址扩展,主要是因为4GB的物理内存对于运行数以千计的进程的大型服务器构成了很大的瓶颈,因此这促使Intel对x86的物理内存进行扩展。Intel通过将处理器上的管脚数从32位增加到36使得寻址能力达到236=64GB,使其得以满足高端市场的需求,最后也就导致了对页内存寻址的另类解释。事实上现在的低端PC市场都已经逐渐从32位向64位过度,所以对这一机制简单介绍一下。

在64GB的物理内存中,页的尺寸仍为4KB,这导致页框数由原来的4GB/4KB=220变为64GB/4KB=224。因此在页目录项和页表项中,相应基地址域的数据位的宽度将由原来的20位变为24位,从而基地址+访问控制域总共需要36位表示,由于双字为系统的基本单位,所以这些项由原先的4个字节成倍扩展至8个字节,结果是页目录或页表中的表项由原先的1024项变为4096/8=512项。

同时为了支持PAE启用了三级分页模型,线性地址的转换过程如下:

  • 首先根据CR3控制寄存器找到页目录指针表(PDPT — Page Directory Pointer Table),注意此时CR3中的页目录基地址域的数据位宽度由20增加为27。该页目录指针表总共由4个表项构成,每个表项占用8个字节,因此在32位线性地址中使用最高的2位(位31-30)索引用于其中的一个表项。
  • 根据该表项得到24位的页目录基地址,再由线性地址中的9个位(位29-21)得到一个页目录项,注意单个页目录或页表中的表项的个数已由原先的1024变为512。
  • 采用同样的方式找到页表项,即根据页目录项中存放的24位基地址加上线性地址中的9个位(位20-12)得到一个页表项。
  • 最后通过线性地址中的最低12个位(位11-0)找到所要寻址的物理内存单元。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值