# 分页机制

先说说最基本的未开启PAE时的10-10-12分页 (PDE为页表地址，PTE为物理页地址)

![](https://1832246008-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LckC1dmB2Mb2F1Bgx_H%2F-LnBsFfC1fDjvdEzAhTQ%2F-LnBsJF2FPKDbhQ6yPMd%2F1.jpg?generation=1566805413678806\&alt=media)

CR3存有页目录表的物理地址，页目录表有1024项，存有页表的物理地址，每张页表有1024项，存有物理页的地址。由于系统的内存通常都是按照4kb对齐，所以页目录表和页表中的地址的低12位都是保留位，另做他用。

但其实上面这种结构方式是错误的，正确的的结构方式是这样的：

![](https://1832246008-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LckC1dmB2Mb2F1Bgx_H%2F-LnBsFfC1fDjvdEzAhTQ%2F-LnBsJF46pT02kUOEtSG%2F2.jpg?generation=1566805413072422\&alt=media)

其实页目录表(PDT)本不存在，是抽象出来的.

* 页表被映射到了从0xC0000000到0xC03FFFFF的4M地址空间
* 在这1024个表中有一张特殊的表：页目录表
* 页目录被映射到了0xC0300000开始处的4K地址空间

所以我们就能根据线性地址计算所在物理页地址

**访问页目录表的公式： 0xC0300000 + PDI\*4**

**访问页表的公式： 0xC0000000 + PDI\*4096 + PTI\*4**

(PDI为页目录表偏移是线性地址高10位，PTI为页表偏移是线性地址的高12-21位)

**但本次实验环境 win7 x86 默认分页方式为 2-9-9-12分页，四页式。**

```
根据 CR3 找到 Page Directory Pointer Table
根据一级索引在 Page Directory Pointer Table 中查询到 Page Directory
根据二级索引在 Page Directory 中查询到 Page Table
根据三级索引在 Page Table 中查询到普通 4KB 物理页
在物理页中查找第四段偏移。
```

如下图：

![](https://1832246008-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LckC1dmB2Mb2F1Bgx_H%2F-Ld8DyBoRn0n4pVUibVO%2F-Ld8E0o704wifcz5D5wH%2F12.png?generation=1556006839194503\&alt=media)

根据以上描述，第一段索引其实就是 Page Directory Pointer Table(PDPT) 这张表的索引。 下面的彩图也许能帮助你理解。

![](https://firebasestorage.googleapis.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LckC1dmB2Mb2F1Bgx_H%2Fuploads%2FJQKI9Vr3NKPfnGEQqUtu%2Ffile.png?alt=media)

这种分页方式不同于三段式，三段式分页最大只支持4GB内存寻址，intel把处理器的管脚数从32位增加到36个满足了更大的内存需求。

三段式分页中的 PDE 和 PTE 都是 4 字节，无论是 PDT 还是 PTT 都有1024个表项。而PAE分页中，PDPT只有 4 个表项，PDT 和 PTT 有 512 个表项，PDPTE、PDE、PTE 的大小是 8 字节。 PDPT 表一共占用 32 字节，PDT 、PTT 表仍然占用 4KB 的物理页。

这里列出它的PTE结构图：

![](https://1832246008-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LckC1dmB2Mb2F1Bgx_H%2F-LdE5wKRYaSJCnjra0C-%2F-LdE5xeQTV6gVxZCCPnS%2F15.png?generation=1556105387677356\&alt=media)

PTE结构的低12位同三段式分页仍然是属性，唯一的区别就是，Page Base Address 由原来的 20 位变成了现在的 24 位，相对以前扩展了 4 位。注意从 36-63 位这28位是保留位，不可用的。

这意味着，PTE 可以索引到的物理页页号由原来的 2的20次方 变成现在的 2的24次方，同样的，一个物理页大小是 4KB，那么PTE可以索引到的最大物理地址将会达到 2^24 \* 2^12 =64GB。

其实，PAE 所做的事情，只是把线性地址的 4GB 虚拟空间打散到了物理地址的64 GB 空间中。

形如图：

![](https://1832246008-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LckC1dmB2Mb2F1Bgx_H%2F-LdE5wKRYaSJCnjra0C-%2F-LdE5xeSADvDs_0qoKYB%2F16.png?generation=1556105387768444\&alt=media)

> 这里就直接给出该分页模式下 PDE 和 PTE 地址计算公式

addr 存放的是线性地址

```c
pPDE = (int*)(0xc0600000 + ((addr >> 18) & 0x3ff8));
pPTE = (int*)(0xc0000000 + ((addr >> 9) & 0x7ffff8));
```
