386及更高型号处理器使用内存分页机制,这使得同一个线性地址可以被映射为多个物理地址,这种映射是通过分页单元这一特殊的硬件电路实现的。通常程序中所使用的线性地址是由链接器帮我们产生的,而操作系统通过维护每个进程私有的页目录和页表实现线性地址与物理地址之间的转换,转换过程对于进程来说是透明的。此外正如保护模式下的段寄存器提供对整个段的访问控制一样,分页单元在更细粒度的页级层面上提供对整个页的保护机制,例如当前页是否可读或可写,访问该页所需的最小特权级以及该页是否已被交换至磁盘从而产生一个缺页异常,我们将逐渐深入了解这种机制的实现原理。
何谓页?
首先要明白什么是页?从抽象意义上来讲页是一个具有固定尺寸的窗口,从逻辑意义上来讲页是具有固定大小的一组连续线性地址的集合。而每个页实际对应的物理内存则被称为页框,这意味着一个页框的尺寸必须和一个页相匹配。通常我们在引用页时指的是页内所存储的数据,引用页框时指的是内存地址空间。一个页的大小可以指定为4KB(212=4KB)的任意倍数,这根据不同的体系结构或操作系统的设置而定,而x86架构下的Windows/Linux均采用4KB大小的分页方式,这就说明32位线性地址中必定存在一个12位的指示页内偏移量的域,我们将在后续的线性地址与物理地址之间的转换部分看到线性地址的具体组织。
相关控制寄存器
处理器中与分页单元有关的寄存器为CR0~CR3控制寄存器,其中CR1被处理器保留,CR2寄存器则用于存放页故障线性地址,当根据某个线性地址所寻址的页不在内存中时将触发一个缺页异常,此时处理器负责将该线性地址加载至CR2寄存器从而把适当的页重新加载到内存中。与分页单元联系最紧密的当属CR0和CR3控制寄存器,其中CR0寄存器中各个位的组织结构如下所示:
其中比较重要的几个位及其更详细的解释如下:
以下是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),而这两种模型根据分析知道都是在保护模式下才存在,处理器的分页机制压根就没有提及实地址模式内存模型,因此在实模式下无法使用分页机制。
其余的位在执行浮点指令时使用,当存在数字协处理器时,可通过设置相应的位将浮点指令交由专用的处理器执行。
下面是CR2和CR3寄存器:
其中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个域:
如下图所示:
线性地址的转换分两步完成:首先由CR3寄存器中的页目录基地址域找到相应的页目录表,通过线性地址中的目录域找到对应的页目录项,随后根据页目录项中存放的页表的基地址找到相应的页表,再通过线性地址中的页表域找到相应的页表项,最后根据页表项中存放的页的基地址及线性地址中的偏移量便完成了线性地址到物理地址的转换。上述转换过程如下图所示:
图1-4
举例:现假设进程读线性地址0x2011 1230(二进制形式为0010 0000 0001 0001 0001 0010 0011 0000)中的一个字节。
系统中的每个进程必须有且仅有一个页目录,且在该进程的生命周期内该页目录必须常驻内存。因为线性地址中的目录域为10位,因此可寻址的页目录项多达210=1024个,对于线性地址中的页表域也是如此,又因为一个页目录项/页表项占4个字节,所以任意一个页目录或页表恰好占据一个物理页框。同时因为偏移量的数据位宽度为12,因此可寻址整个页内的任意一个字节(212=4096)。此外,由于一个页目录或页表存在1024个表项,所以一个页目录对应1024个页表,一个页表对应1024个页,因此一个进程可寻址的内存空间为1024×1024×4096B=232=4GB。
采用二级分页模型的好处是系统使用相对较少的内存更为简单地实现了地址之间的转换。考虑一个一级分页模型,假定32位线性地址被分成20位的页表域以及12位的偏移量,那么即使某个应用小到只需一个物理页框便可运行,系统仍将为整个页表分配4MB的内存空间,因此产生了极大的浪费,而使用二级分页模型,则只需为页目录分配一个物理页框并初始化首个页目录项,随后再为页表分配一个页框并初始化首个页表项即可,此时总共只消耗了8KB的物理内存,而如果使用三级分页模型,虽然较之于前两者,其内存利用率更高,但带来的问题是管理的复杂度增加,线性地址的转换速度降低。
以下是4字节的页目录项和页表项的组织形式:
基于对局部性原理(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启用了三级分页模型,线性地址的转换过程如下: