三种分页模式(32bit,PAE,IA-32e)下的线性(虚拟)地址到物理地址的转换

为了更好管理更大的内存,现代操作系统和CPU硬件引入了保护模式。其中保护模式的分页机制通过内存管理单元(MMU,Memory Management Unit)实现了物理地址到线性(虚拟)地址的转换,这个转换过程也称地址翻译。而本文探讨线性地址到物理地址的转换过程,并通过实际操作来体现。

实验环境:

  • win 10
  • windbg Preview
  • VirtBox+win xp(切换PAE状态)

实验环境主要涉及Windbg通过VirtBox实现内核双机调试和本地内核调试。

具体理论部分可参考Intel手册中关于Paging的章节:https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-manual-325462.html

涉及到的概念

控制寄存器:

  • cr0:分页机制的开关,PE位代表保护模式。PG位代表分页机制
  • cr3:分页数据结构的基地址,cr3中存储的物理地址与分页模式有关
  • cr4:控制硬件虚拟化设置(Pentium及80486以后才有)

PAE:Physical Address Extension,物理地址扩展。

查看系统是否开启了PAE(以xp为例),我的电脑-系统属性-常规:计算机;或者查看CR4寄存器的5位是否为1。

对于在长模式(long mode)中的x64来说,PAE是必须的。PAE改变了传统的保护模式分页机制,增加了一级页,CR3不再指向页目录物理段地址,而是指向页目录指针表,即一个包含4个页目录指针的表。

分页模式

启用分页模式条件:cr0.PG = 1 且 cr0.PE = 1

根据不同CPU架构及特性主要分为三种模式,处于哪种模式视寄存器属性不同:

  • 32-bit paging(32位OS): cr0.PG = 1 ; cr4.PAE = 0
  • PAE paging(32位OS且开启了PAE): cr0.PG = 1 ; cr4.PAE = 1 ; IA32_EFER.LME = 0
  • IA-32e paging(64位OS): cr0.PG = 1 ; cr4.PAE = 1 ; IA32_EFER.LME = 1

需要注意的是

  1. 32bit下,每个entry(表项)是4字节大小;而在PAE和IA-32e下,每个entry是8字节大小
  2. 在x64体系中只实现了48位的virtual address,高16位被用作符号扩展,这高16位要么全是0,要么全是1。所以在讨论64bit地址的时候,高16位不使用

    Paging相关数据结构

  • PML4T:The page map level 4 table,每个表为4kb,内含512个PML4E结构。这个表的物理基址存储在cr3[12:51]中(IA-32e特有)
  • PML4E:The page map level 4 entry,PML4表项,每个8字节大小(IA-32e特有)
  • PDPT:Page Directory Pointer Table,页目录指针表,每个表4kb,内含512分PDPTE结构(PAE和IA-32e特有,PAE下这个表的物理地址存储在cr3[5:31]中)
  • PDPTE/PDPE:Page Directory Pointer Table Entry,页目录指针表项,每个8字节(PAE和IA-32e特有)
  • PDT:Page Directory Table,每个表4K,内含512个PDE结构
  • PDTE/PDE:Page Directory Table Entry,页目录表的表项
  • PT:Page Table,每个4kb,内含512个PTE结构
  • PTE:Page Table Entry

这里需要注意的是各种table及entry的描述性数据结构,在实际操作中,其低12bit都置0处理,因为这部分是用来描述页表属性的。

地址转换基本原理

原理很简单,就是讲线性地址拆分,各个域对应不同表,表项的index,然后来一步步定位。随着32bit OS到64bit OS的转变,32bit地址到64位地址的转变,地址转换的层级也就逐步增多,从二级页表(32bit)到三级(PAE),再到4级(64bit)。

页转换模型

IA-32e提供了三种页转换模型:

  • 4k:PML4t,PDPT,PDT和PT
  • 2M:PML4T,PDPT和PDT
  • 1G:PML4T和PDPT

本文所有分页模式下的转换都是基于4K的寻址方式,因为在个人计算机上,普遍是4K,4K对齐嘛

32bit地址

32bit的线性地址到物理地址转换最简单,是通过二级页表来进行的。此时cr3高20位中存储的是页目录表物理基地址

具体步骤:

  1. 将32bit地址拆分为三部分:高10位(PDE index),中间10位(PTE index),低12位(物理页offset)
  2. 获取页表的物理基地址:PDE index 4 + cr3中页目录表基地址= PT base addr,通过这个指针即可找到页表的物理基地址
  3. 获取分配到的物理页地址:PTE index * 4 + PT base addr,就可以找到存储物理页地址的页表项
  4. 物理页地址+物理页offset=物理地址

这里为什么乘以4呢,因为每个entry 4字节大小

32bit No PAE

以未开启PAE的win xp下calc.exe为例,其入口地址为0x1012475,这个地址怎么来的呢,OD载入即可找到。因为没有ASLR,所以每次运行的地址是固定的。将0x1012475分成三部分:

  • 0x10
  • 0x12
  • 0x475

0x1012475入口特征

32bit地址转换过程
根据上面两张图,可以看出物理地址0x145e8375处数据和0x1012475处数据一致

为了进一步验证是否数据是否一致,在Windbg下修改物理地址处数据,然后通过OD查看虚拟地址处的数据,发现也是一致变化的。
Windbg修改数据

开启PAE

此时线性地址要拆分成四部分,高2位(PD index),中高9位(PT index),中的(PTE index),低12位(物理页偏移)。此时cr3[5:31]存储的是PDPT base addr。
cr3 PDPT base

开启硬件的PAE选项,可以发现XP下多了”物理地址扩展”
开启PAE

将0x1012475拆分成四部分:

  • 0x0
  • 0x8
  • 0x12
  • 0x475

具体转换步骤如下图:
PAE下地址转换过程
这里为什么乘以8呢,因为PAE下每个entry 8字节大小

IA-32e地址转换

此时64bit线性地址要拆分成五部分:

  • [51:42] (PML4E index)
  • [41:32](PDPE index)
  • [31:22](PDE index)
  • [21:13](PTE index)
  • [12:0](physical offset)

此时cr3[5:31]存储的是PML4T base addr。
cr3 PML4T base

用以下这张图可以清晰明了表示:
1G2M4Kpage

这里测试写了一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <cstdio>
#include <iostream>

using namespace std;

int main()
{
char szName[20] = "HelloWorld";
printf("szName:0x%x\n", szName);
cout << "szName:" << &szName << endl;
getchar();
return 0;
}

为什么这里要写个printf输出呢。因为在看雪论坛上看到一个帖子啊,讲x64位虚拟地址转换,用printf直接输出值,这样是不严谨的,因为printf直接输出的话,只能输出32bit地址,如果是64bit的话,高32bit会被截取掉的。看雪上那篇帖子测试的时候正好输出了32bit的地址,所以可以寻到物理地址。

这里将szName的地址:0x2f440ff628分成五部分:

  • 0x0
  • 0xbd
  • 0x20
  • 0xff
  • 0x628

具体转换步骤如下图:
IA-32e地址转换
同样这里乘以8也是因为每个entry 8字节大小

Windbg有一个扩展指令,!vtop可将虚拟地址转换成物理地址,在上图中也有验证。

参考链接

启用PAE后虚拟地址到物理地址的转换:https://bbs.pediy.com/thread-180989.htm

X64下的虚拟地址到物理地址的转换:https://bbs.pediy.com/thread-203391.htm

理解 paging:http://www.mouseos.com/arch/paging.html

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/converting-virtual-addresses-to-physical-addresses

https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-manual-325462.html