1. 概述
分页是更加粒度化的内存管理机制, 分页是用粒度化的单位"页"来管理线性地址空间和物理地址空间. x86下一个典型的页大小是4KB, 则一个4GB的虚拟地址空间可以划分为1024X1024个页面. 物理地址空间的划分同理. x86允许大于4KB的页面大小, 这里只介绍4KB页面.
同时, 分页机制让操作系统中的虚拟内存机制称为可能. 一个页面可以存在于物理内存(!!!)中, 也可以存放在磁盘的交换区域!!!(如Linux下的Swap分区!!!, Windows的虚拟内存文件!!!)中, 程序可以使用比机器物理内存更大的内存区域!!!.
分页机制的核心思想是通过页表将线性地址转换为物理地址, 并配合旁路转换缓冲区(Translation Lookaside Buffer, TLB!!!)来加速地址转换过程. 操作系统在启动过程中, 通过将CR0寄存器的PG位置1来启动分页机制.
从图中看到, 分页机制主要由页表、CR3和TLB三个部件构成. 下面以4KB页面的32位分页为例进行讲解.
1.1. 页表
页表(Page Table)是用于将线性地址转换成物理地址的主要数据结构. 一个地址对齐到页边界(!!!)后的值称为页帧号, 它实际是该地址所在页面的基地址. 线性地址对应的页帧号!!!即虚拟页帧号(Virtual Frame Number, VFN!!!), 物理地址对应的页帧号!!!即物理页帧号(Physical Frame Number, PFN!!!)或机器页帧号(Machine Frame Number). 页表就是存储VFN到PFN映射的数据结构。
4KB的32位分页使用两级页表, 如图.
⓵ 页目录项(Page Directory Entry): 包含页表的物理地址(!!!不是线性地址!!!). 页目录项存放在页目录(Page Directory, 也称为页目录表PDT!!!)中, CPU使用线性地址的22~31位(高10位)索引页目录, 以获得该线性地址对应的页目录项. 每个页目录项为4B大小, 故页目录占用4KB大小的物理页面, 共包含1024的页目录项.
⓶ 页表项(Page Table Entry): 页表项包含该线性地址对应的PFN(!!!物理地址页帧号!!!)。页表项存放在页表(Page Table)中, CPU使用线性地址的12~21位索引页表, 获得该线性地址对应的页表项. 通过将线性地址的0~11位偏移量和基地址相加, 就可以得到线性地址对应的物理地址. 页表项为4B大小, 故页表包含1024个页表项, 占用一个4KB页面.
图2-9显示了页目录项、页表项的构成, 通过其中的各个字段, 可以对页面访问权限, 缓存机制, 全局页等属性进行控制. 这里只关注P(Present)字段, 该字段使虚拟内存的实现成为可能. P根据其值不同, 可以代表两种情况:
- P=1: 物理页面存在于物理内存中, CPU完成地址转换后, 可以直接访问该页面.
- P=0: 页面不在物理内存中, 当CPU访问该页面时会产生一个缺页错误(Page Fault)并交由操作系统的缺页错误处理程序处理. 通常操作系统会将存放在磁盘上的页面(!!!)调入物理内存, 使访问可以继续. P=0时, 页目录项、页表项格式变成图2-10中的格式。此时1~31位供操作系统使用以记录物理页面在磁盘上的信息, 通常是物理页面在磁盘上的位置!!!.
CPU在索引页目录前, 必须知道页目录所在的物理地址, 该物理地址存放在CR3(Control Register 3)寄存器中, 也称为页目录基地址寄存器(Page-directory base register, PDBR). 一个进程在运行前(!!!), 必须将其页目录的基地址存入CR3. 页目录的基地址必须对齐到4K边界.
1.2. TLB
为提高地址转换效率, x86架构使用TLB对最近用到的页面映射进行缓存, 当CPU访问某个线性地址, 其所在页面的映射存在于TLB中, 无须查找页表即可进行地址转换. 注意, 很多资料说TLB存放的是线性地址到物理地址的转换, 准确来说应该是: VFN到PFN的转换!!!. 即, CPU从TLB获得一个线性地址对应的PFN后, 仍然要和线性地址的偏移相加, 才能得到最后的物理地址, 而非直接从TLB中获取物理地址.
TLB作为缓存, 其能存放的映射条目有限, 当TLB中没有空闲条目可用时, 替换哪一个旧条目由CPU决定.
TLB也有缓存一致性的问题,这主要是指TLB中的映射条目(!!!)和页表中的映射条目(!!!)的一致性。当操作系统对页表进行修改,要负责对TLB中对应条目或整个TLB进行刷新(!!!)。从软件的角度来看, x86提供了两种方式刷新TLB:
⓵ 更新CR3: 此操作可以导致TLB被整体刷新, TLB中所有映射条目失效(全局TLB除外). 操作系统将当前CR3中的值重新写会CR3以刷新整个TLB. 进程切换时, 新进程的页目录基地址会写入CR3而使老进程在TLB中的条目失效.
⓶ INVLPG指令: 这是一种更细粒度的刷新, 操作系统用它对TLB中单独的页目录项、页表项进行刷新. 这通常是在操作系统修改页表后进行的(例如分配/释放页面!!!).
1.3. 线性地址转换为物理地址的过程
⓵ CPU访问一个线性地址, 映射在TLB中跳到⓺. 如映射不存在于TLB中, 称为TLB Miss发生, 进行下一步.
⓶ 查找页表, 页面在物理内存!!! 中跳到⓸, 不会再进行下一步.
⓷ 操作系统的缺页处理函数接管, 通常进行如下操作: a)将页面从磁盘复制到物理内存中; b)更改对应页表项, 设置P为1, 并对其他字段相应设置; c)刷新TLB中对应的页表项; d)从缺页错误处理函数中返回.
⓸ 到这一步, 页面已经存在于物理内存中, 并且页表已经包含了该映射. 此时, 重新执行引发TLB Miss的指令.
⓹ TLB Miss再次发生(!!!), CPU重新查页表, 把相应的映射插入到TLB中.
⓺ 到这一步, TLB已经包含了该线性地址对应的PFN. 通过将线性地址中的偏移部分和PFN相加, 就得到了对应的物理地址.
翻译自《Intel® 64 and IA-32 Architectures Software Developer Manual Volume 3A》
每个table里的entry(表项)分别被称为PTE(Page Table Entry)、PDE(Page Directory Table Entry)、PDPE(Page Directory Pointer Table Entry)和PML4E(Page-Map Leve-4 Table Entry)。
注: CR3存放的是物理地址, 表项中也是物理地址.
2. 32位分页
线性地址是32位宽, 采用一级或两级页转换表.
每个表项大小是4字节宽, 32位.
CR3使用32位.
2.1. 4KB页面线性地址翻译
使用PDT(page directory table,页目录表)和PT(page table,页表)两级表格。
用32位分页的到一个4KB页面的线性地址翻译
4KB页面线性地址构成: 10(PDT索引, 1024个项) + 10(PT索引, 1024个项) + 12(Page offset, 4KB页)
一个table的大小:
- 一个PDT有1024项(2^10); 占用空间: 1024 x 4字节 = 4KB.
- 一个PT有1024项(2^10); 占用空间: 1024 x 4字节 = 4KB.
一个进程一次性全部表示需要的页表结构内存:
- PDTE可能共有: 1024(2^10) 个; 占用空间: 1024 x 4字节 = 4KB.
- PTE可能共有: 1024(2^10) x 1024(2^10) 个; 占用空间: 1024 x 1024 x 4字节 = 4MB.
2.2. 4MB页面线性地址翻译
使用PDT(page directory table)一级表格。
用32位分页的到一个4MB页面的线性地址翻译
4MB页面线性地址构成: 10(PDT索引, 1024个项) + 22(Page offset, 4MB页)
一个table的大小:
- 一个PDT有1024项(2^10), 占用空间: 1024 x 4字节 = 4KB.
一个进程一次性全部表示需要的页表结构内存:
- PDTE可能共有: 1024(2^10) 个; 占用空间: 1024 x 4字节 = 4KB.
2.3. CR3和分页结构项
32位分页的CR3和分页结构项的格式
2.4. 物理地址组成
32位paging下最高为40位物理地址(!!!)(依赖于PSE-36与MAXPHYADDR值)。如果不使用PSE-36机制, 那么最高为32位物理地址(!!!).
4K页面,能映射的物理地址最高是32位(!!!)
2.4.1. CR3生成PDT物理基地址
在32位paging模式下,CR3使用低32位(在Intel64或AMD64机器上64位, 只使用低32位!!!),CR3的Bit 31到Bit 12位提供20位的Page Directory Table的物理基地址(物理基地址!!!高20位!!!)。
那么以36位的物理基地址为例,它是这样形成的。
① base of PDT[35:32] =0 值(高4位Bit 35到Bit 32为0值!!!如果是40位物理地址高位也会是补0!!!)。
② base of PDT[31:12] =CR3[31:12] (中间20位由CR3的Page Driectory base域提供)。
③ base of PDT[11:00] =0 值(低12位补0!!!)。
因此CR3提供的PDT物理基地址(!!!)是4K边界对齐(!!!)的。和4KB分页的物理地址形成方式一致(!!!).
2.4.2. 4KB页PDE生成PT的物理基地址
32位paging模式的4K页面里,能映射的物理地址最高是32位(!!!4K页最高32位物理地址!!!),下一级32位的page table物理地址形成如下。
① base of PT[31:12] (高20位)=PDE[31:12] ,它是PDE的高20位值。
② base of PT[11:0] (低12位)=0 值,32位地址的低12位补0。
因此,PDE里提供的PT物理基地址(!!!)是4K边界对齐(!!!由PT物理基地址组成决定的!!!)的。
2.4.3. 4KB页PTE生成页面的物理基地址
在32位paging模式下4K页面使用的是32位的最高映射物理地址(!!!只能使用最高32位物理地址!!!)。因此page frame的形成如下。
① page base[31:12] =PTE[31:12] ,PTE的高20位对应物理页面的高20位。
② page base[12:0] =0 值。物理页面的低12位补0。
所以物理页面在4KB边界对齐.
2.4.4. 4MB页PDE生成页面的物理基地址
4MB页面没有PT, PDE直接指向页面.
4MB页面的PDE结构提供4MB页面的物理基地址, 地址组成方式如下:
① 当处理器不支持PSE-36功能时,4M page frame只能映射到32位的物理地址空间(!!!)上,PDE[31: 22] 是4M page base[31: 22] (高10位), 这时候PDE[21:13] 共9位是保留位,必须设置为0值。
② 当MAXPHYADDR值为36位时,PDE[16:13] 是4M page base[35:32] 位(高4位),PDE[31: 22] 是4M page base[31: 22] (中间10位), 而PDE[21:17] 是保留位,必须设置为0值。
③ 当MAXPHYADDR值为40位时,PDE[20:13] 是4M page base[39:32] 位(高8位), PDE[31: 22] 是4M page base[31: 22] (中间10位),而PDE[21] 位是保留位,必须设置为0值。
④ 当MAXPHYADDR值为52位时,也仅能使用40位的物理地址(!!!),同③。
因此,4M page frame的基地址形成除上述所说外,36位或40位的物理地址低22位将补0(!!!),物理页面将在4M边界上对齐(!!!)。
2.4.5. 最终物理地址的生成
上面可以看到, 所有页面基地址都是4KB或4MB边界对齐的, 再加上线性地址低位的偏移offset, 生成最终的物理地址.
3. PAE分页
线性地址32位宽, 使用两级或三级页转换表.
每个表项8字节宽.
新CR3仍然32位宽, 但只使用了27位, 拼凑了32位PDPT物理地址。
3.1. 4KB页面线性地址翻译
使用PDPT (page directory pointer table,页目录指针表),PDT 和PT 。
用PAE分页的到一个4KB页面的线性地址翻译
4KB页面线性地址构成: 2(PDPT索引, 4个项) + 9(PDT索引, 512个项) + 9(PT索引, 512个项) + 12(Page offset, 4KB页)
一个table的大小:
- 一个PDPT有4项(2^2); 占用空间: 4 x 8字节 = 32字节.
- 一个PDT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
- 一个PT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
一个进程一次性全部表示需要的页表结构内存:
- PDPTE可能共有: 4(2^2) 个; 占用空间: 4 x 8字节 = 32字节.
- PDE可能共有: 4(2^2) x 512(2^9) 个; 占用空间: 4 x 512 x 8字节 = 16KB.
- PTE可能共有: 4(2^2) x 512(2^9) x 512(2^9) 个; 占用空间: 4 x 512 x 512 x 8字节 = 8MB.
3.2. 2MB页面线性地址翻译
使用PDPT 和PDT 。
用PAE分页的到一个2MB页面的线性地址翻译
2MB页面线性地址构成: 2(PDPT索引, 4个项) + 9(PDT索引, 512个项) + 21(Page offset, 2MB页)
一个table的大小:
- 一个PDPT有4项(2^2); 占用空间: 4 x 8字节 = 32字节.
- 一个PDT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
一个进程一次性全部表示需要的页表结构内存:
- PDPTE可能共有: 4(2^2) 个; 占用空间: 4 x 8字节 = 32字节.
- PDE可能共有: 4(2^2) x 512(2^9) 个; 占用空间: 4 x 512 x 8字节 = 16KB.
3.3. CR3和分页结构项
3.4. 物理地址组成
PAE下, 线性地址仍然32位宽(!!!), CR3还是32位宽, 支持最高52位的物理地址,依赖于MAXPHYADDR值。当MAXPHYADDR为36时只能映射到36位的物理地址,以此类推。
3.4.1. CR3生成PDPT物理基地址
CR3低5位被忽略,提供27位的PDPT基地址.
32位的PDPT物理地址形成如下:
① base of PDPT[31:5] =CR3[31:5] ,高27位由CR3提供。
② base of PDPT[4:0] =0 值,低5位补0。
如果是36位或更大物理地址, 则进行高位补0.
因此,PDPT的基地址是32字节边界对齐(2^5!!!)的。
3.4.2. PDPTE生成PDT的物理基地址
4KB页和2MB页这是一致的
在PDT(page directory table)物理基地址上,它的地址为52位(最高支持)、40位或是36位,它的形成如下。
① 当MAXPHYADDR为52位时,base of PDT[51:12] =PDPTE[51:12] ,由PDPTE结构的[51:12] 提供PDT的高40位。
② 当MAXPHYADDR为40位时,base of PDT[39:12] =PDPTE[39:12] ,由PDPTE结构的[39:12] 提供PDT的高28位。此时PDPTE[51:40] 是保留位,必须为0值。
③ 当MAXPHYADDR为36位时,base of PDT[35:12] =PDPTE[35:12] ,由PDPTE结构的[35:12] 提供PDT的高24位。此时PDPTE[51:36] 是保留位,必须为0值。
PDT的低12位(!!!)将补0值,因此PDT物理基地址将在4K边界上对齐(!!!)。
3.4.3. 4KB页PDE生成PT的物理基地址
PDE[51:12] (最多30位, 加上12位0, 最大52位物理地址)提供PT的物理基地址高位, 低12位全部补0, PT地址为4K边界对齐。
如果物理地址比较小, bit 51往下减少.
3.4.4. 4KB页PTE生成页面的物理基地址
PTE[51:12] 提供4K页面的高物理地址位(最多40位), 低12位全部补0, 页面地址4K边界对齐.
如果物理地址比较小, bit 51往下减少.
3.4.5. 2MB页PDE生成页面的物理基地址
2MB页面没有PT, PDE直接指向页面.
① MAXPHYADDR为52位时,2M page frame 地址的[51:21] (高31位)由PDE[51:21] 提供。
② MAXPHYADDR为40位时,2M page frame 地址的[39:21] (高19位)由PDE[39:21] 提供,此时PDE[51:22] 为保留位,必须为0。
③ MAXPHYADDR为36位时,2M page frame 地址的[35:21] (高15位)由PDE[35:21] 提供,此时PDE[51:36] 为保留位,必须为0
2M page frame 地址的[20:0] (低21位!!!)补0,因此2M页面的地址在2M边界上对齐。
3.4.6. 最终物理地址的生成
上面可以看到, 所有页面基地址都是4KB或2MB边界对齐的, 再加上线性地址低位的偏移offset, 生成最终的物理地址.
4. IA-32e分页
线性地址48位宽, 使用两级到四级的页转换表.
每个表项都是8字节宽.
CR3是64位宽, 针对是否支持PCIDE功能, CR3使用不一样。
4.1. 4KB页面线性地址翻译
使用PML4T (page map level-4 table,四层映射表),PDPT ,PDT 和PT 。
用IA-32e分页的到一个4KB页面的线性地址翻译
4KB页面线性地址构成: 9(PML4T索引, 512个项) + 9(PDPT索引, 512个项) + 9(PDT索引, 512个项) + 9(PT索引, 512个项) + 12(Page offset, 4KB页)
一个table的大小:
- 一个PML4T有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
- 一个PDPT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
- 一个PDT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
- 一个PT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
一个进程一次性全部表示需要的页表结构内存:
- PML4E可能共有: 512(2^9)个; 占用空间: 512 x 8字节 = 4KB.
- PDPTE可能共有: 512(2^9) x 512(2^9) 个; 占用空间: 512 x 512 x 8字节 = 2MB.
- PDE可能共有: 512(2^9) x 512(2^9) x 512(2^9) 个; 占用空间: 512 x 512 x 512 x 8字节 = 1GB.
- PTE可能共有: 512(2^9) x 512(2^9) x 512(2^9) x 512(2^9)个; 占用空间: 512 x 512 x 512 x 512 x 8字节 = 512GB.
4.2. 2MB页面线性地址翻译
使用PML4T ,PDPT 和PDT 。
用IA-32e分页的到一个2MB页面的线性地址翻译
2MB页面线性地址构成: 9(PML4T索引, 512个项) + 9(PDPT索引, 512个项) + 9(PDT索引, 512个项) + 21(Page offset, 2MB页)
一个table的大小:
- 一个PML4T有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
- 一个PDPT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
- 一个PDT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
一个进程一次性全部表示需要的页表结构内存:
- PML4E可能共有: 512(2^9)个; 占用空间: 512 x 8字节 = 4KB.
- PDPTE可能共有: 512(2^9) x 512(2^9) 个; 占用空间: 512 x 512 x 8字节 = 2MB.
- PDE可能共有: 512(2^9) x 512(2^9) x 512(2^9) 个; 占用空间: 512 x 512 x 512 x 8字节 = 1GB.
4.3. 1GB页面线性地址翻译
使用PML4T 和PDPT 。
用IA-32e分页的到一个1GB页面的线性地址翻译
1GB页面线性地址构成: 9(PML4T索引, 512个项) + 9(PDPT索引, 512个项) + 30(Page offset, 1GB页)
一个table的大小:
- 一个PML4T有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
- 一个PDPT有512项(2^9); 占用空间: 512 x 8字节 = 4KB.
一个进程一次性全部表示需要的页表结构内存:
- PML4E可能共有: 512(2^9)个; 占用空间: 512 x 8字节 = 4KB.
- PDPTE可能共有: 512(2^9) x 512(2^9) 个; 占用空间: 512 x 512 x 8字节 = 2MB.
4.4. CR3和分页结构项
IA-32e分页的CR3和分页结构项的格式
4.5. 物理地址组成
线性地址48位宽(!!!), CR3已经是64位宽, 支持最高52位的物理地址,依赖于MAXPHYADDR值。当MAXPHYADDR为36时只能映射到36位的物理地址,以此类推。
4.5.1. CR3生成PML4T物理基地址
CR3[51:12] 提供PML4T的物理地址高位(最多40位), 低12位全部补0, PML4T地址4K边界对齐.
如果物理地址比较小, bit 51往下减少.
4.5.2. PML4E生成PDPT的物理基地址
PML4E[51:12] 提供PDPT的物理地址高位(最多40位), 低12位全部补0, PDPT地址4K边界对齐.
如果物理地址比较小, bit 51往下减少.
4.5.3. 4KB页和2MB页PDPTE生成PDT的物理基地址
PDPTE[51:12] 提供PDT的物理地址高位(最多40位), 低12位全部补0, PDT地址4K边界对齐.
如果物理地址比较小, bit 51往下减少.
4.5.4. 1GB页PDPTE生成页面的物理基地址
1GB页面没有PDT, 没有PT, PDPTE直接指向页面.
PDPTE[51:30] 提供PDT的物理地址高位(最多22位), 页面地址低30位全部补0, 页面地址1GB边界对齐.
如果物理地址比较小, bit 51往下减少.
4.5.5. 4KB页PDE生成PT的物理基地址
PDE[51:12] 提供PT的物理地址高位(最多40位), 页表PT地址低12位全部补0, 页表PT地址4K边界对齐.
如果物理地址比较小, bit 51往下减少.
4.5.6. 4KB页PTE生成页面的物理基地址
PTE[51:12] 提供页面的物理地址高位(最多40位), 页面地址低12位全部补0, 页面地址4K边界对齐.
如果物理地址比较小, bit 51往下减少.
4.5.7. 2MB页PDE生成页面的物理基地址
2MB页面没有PT, PDE直接指向页面.
PDE[51:21] 提供页面的物理地址高位(最多31位), 页面地址低21位全部补0, 页面地址2MB边界对齐.
如果物理地址比较小, bit 51往下减少.
4.5.8. 最终物理地址的生成
上面可以看到, 所有页面基地址都是4KB, 2MB或1GB边界对齐的, 再加上线性地址低位的偏移offset, 生成最终的物理地址.
5. 分页错误代码
6. 参考
https://blog.csdn.net/Firas/article/details/17207813
|