首页
社区
课程
招聘
[原创]X64下的虚拟地址到物理地址的转换
发表于: 2015-8-16 21:59 33087

[原创]X64下的虚拟地址到物理地址的转换

2015-8-16 21:59
33087

早就知道传上来排版会全乱掉,把pdf直接传上来吧
x64结构体系寻址.pdf
发现安大的关于x86启用PAE下的虚拟地址转物理地址的帖子,大家可以参考一下http://bbs.pediy.com/showthread.php?t=180989
X64结构体系内存寻址
在阅读NewBluePill源码的时候,看内存的那一块简直头疼,全是x64下的寻址,之前根本就没有接触过x64的内存寻址上的内容,看的晕头转向,决定先把x64下的寻址给弄明白了再回过头来看NewBluePill的源码,然后在网上一顿找,居然没有找到关于x64寻址的博客或者文章,简直痛苦啊,然后找了好久才发现一本不错的书《x86/x64 体系探索及编程》,然后终于把x64的寻址问题弄清楚了,总结出来分享一下学习历程。
0x01    x64寻址简介
在保护模式,CPU发出的线性地址,内存管理单元(MMU),根据当前CR3寄存器所指向的页表物理地址将该线性地址翻译成物理地址进行内存访问,该过程称为地址翻译。
在x64体系结构中,线性地址的结构如图

在x64体系中只实现了48位的virtual address,高16位被用作符号扩展,这高16位要么全是0,要么全是1。
不同于x86体系结构,每级页表寻址长度变成9位,由于在x64体系结构中,普通页大小仍为4KB,然而数据却表示64位长,因此一个4KB页在x64体系结构下只能包含512项内容,所以为了保证页对齐和以页为单位的页表内容换入换出,在x64下每级页表寻址部分长度定位9位。
为了正确翻译x64的线性地址,其页表也从x86的2级变成了4级,翻译过程如图所示,在x64体系结构中,每级页表包含512项(2^9)下级目录的指针,该指针称为页表项,描述了存储下级

  PML4T(Page Map Level4 Table)及表内的PML4E结构,每个表为4K,内含512个PML4E结构,每个8字节
  PDPT (Page Directory Pointer Table)及表内的PDPTE结构,每个表4K,内含512个PDPTE结构,每个8字节
  PDT (Page Directory Table) 及表内的PDE结构,每个表4K,内含512个PDE结构,每个8字节
  PT(Page Table)及表内额PTE结构,每个表4K,内含512个PTE结构,每个8字节。
每个table entry 的结构都是8个字节64位宽,而virtual address中每个索引值都是9位,因此每个table都是512 x 8 = 4K字节。

0x02   页转换模型
X64,准确的说应该是IA32e paging 模型提供了三种页转换模型,
① 4K页面的转换表结构;
② 2M 页面的转换结构;
③ 1G页面的转换结构;
在64位模式下,处理器将48的虚拟地址转化为物理地址,在兼容模式下,转化32位的虚拟地址。

三种模型都是物理页帧的基地址加上页偏移得到物理地址,不同只是在于页帧的大小划分不同:
①4K页面: 使用PML4T,PDPT,PDT和PT 四级页转化表结构;
②2M页面:使用PML4T,PDPT 和PDT三级页转化表结构;
③1G 页面:使用PML4T和PDPT二级页表转化结构。
而在这里我们主要讨论的是4K页面大小的寻址方式,因为在个人计算机上,普遍都是4K
页面寻址,其他的方式也主要就是页面大小的差异。
0x03   最大物理地址

在Intel中使用MAXPHYADDR来表示最大的物理地址,我们可以通过CPUID的指令来获得处理支持的最大物理地址,然而这已经不在此次的讨论范围之内,我们需要知道的只是:
当MAXPHYADDR 为36位,在Intel平台的桌面处理器上普遍实现了36位的最高物理地址值,也就是我们普通的个人计算机,可寻址64G空间;
当MAXPHYADDR 为40位,在Inter的服务器产品和AMD 的平台上普遍实现40位的最高物理地址,可寻址达1TB;
当MAXPHYADDR为52位,这是x64体系结构描述最高实现值,目前尚未有处理器实现。

而对下级表的物理地址的存储4K页面寻址遵循如下规则:
① 当MAXPHYADDR为52位时,上一级table entry的12~51位提供下一级table物理基地址的高40位,低12位补零,达到基地址在4K边界对齐;
② 当MAXPHYADDR为40位时,上一级table entry的12~39位提供下一级table物理基地址的高28位,此时40~51是保留位,必须置0,低12位补零,达到基地址在4K边界对齐;
③ 当MAXPHYADDR为36位时,上一级table entry的12~35位提供下一级table物理基地址的高24位,此时36~51是保留位,必须置0,低12位补零,达到基地址在4K边界对齐。

0x04    实际转化
  CR3
当CR4.PCIDE = 0时,CR3的结构如图

CR3可以使用64位宽,但是它表示的PML4T的物理基地址同样受到之前所说的MAXPHYADDR的约束,图示的只是理想的MAXPHYADDR为52位时的情况。
而当CR4.PCIDE = 1的时:

R3的低12位提供一个PCID值,用来定义当前Process Context ID.
当对CR3进行更新时,CR3第63位决定是否需要处理器的TLB和paging-struct cache,这不在我们此次谈论的范围之内。
  PML4E
接着再看PML4E的结构,如图:

PML4E并没有PS标志位,因此第7位是保留的,而PML4E提供的PDPT的物理基地址也受之前的MAXPHYADDR规则的约束。
  PDPTE
然后就是PDPTE结构:
由于新增了1G 页面,因此在PDPTE结构里将控制1G的页面转化,由PDPTE.PS标志位进行转换,如图:

当PDPTE.PS=1,也就是PDPTE的第7位为1时,PDPTE将提供1G的物理页面地址;当PDPTE.PS=0,也就是PDPTE的第7位为0时,使用非1G的页面,将提供下一级的PDT的物理基地址,同样受MAXPHYADDR规则的约束。

1G页面下的PDPTE 的结构解析如下:

同样地,PDPTE提供的1G页面的物理地址也遵守MAXPHYADDR的规则,1G页面的地址低30将补0,意味着1G边界上对齐。
4K和2M页面下的PDPTE结构解析如下:

将提供下一级PDT的物理基地址,同样也遵循MAXPHYADDR规则,那么再根据PDE.PS再决定是使用2M页面还是4K页面。
  PDE
PDE的结构和PDPTE类似,也是用PS(第7位)表示是使用2M的页面还是4K 的页面,下面是2M 页面的PDE结构解析:

同样对于页面的物理基地址也遵循MAXPHYAD原则。
接下来是4K 页面的 PDE 结构解析

也遵循MAXPHYADDR 规则。
  PTE
PTE的结构解析:

同样遵循MAXPHYADDR规则。

0x05  实际例子
上面写了很多都是原理性的东西,可能看完之后对于x64还没有很清晰的认识,我们以一个很简单的例子来加深对于x64结构体系的寻址的认识。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 8
支持
分享
最新回复 (21)
雪    币: 290
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
谢谢分享。
2015-8-16 22:03
0
雪    币: 707
活跃值: (1301)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
3
不错,学习一下
2015-8-17 08:06
0
雪    币: 6
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢楼主分享技术贴。
2015-8-17 09:03
0
雪    币: 11075
活跃值: (17602)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
楼主辛苦了,搞了这么牛逼的资料上来
2015-8-17 09:24
0
雪    币: 393
活跃值: (224)
能力值: ( LV8,RANK:140 )
在线值:
发帖
回帖
粉丝
6
学习一下
2015-8-17 12:09
0
雪    币: 11
活跃值: (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
学习一下
2015-8-17 12:35
0
雪    币: 228
活跃值: (115)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
8
非常详细的介绍,值得占座
2015-8-17 13:31
0
雪    币: 401
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
此帖子值得玩味学习,正在进行中,,,
2015-9-2 20:31
0
雪    币: 31
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
学习了。
2015-9-4 09:18
0
雪    币: 22
活跃值: (52)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
涨姿势了
2015-10-26 11:25
0
雪    币: 581
活跃值: (215)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
12
又一个类似的文章
2015-10-26 12:35
0
雪    币: 938
活跃值: (943)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
当MAXPHYADDR为42位时呢
2016-1-19 17:00
0
雪    币: 25
活跃值: (506)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
mark
2016-7-11 10:34
0
雪    币: 1648
活跃值: (2671)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
15
张老师的软件调试书中有写过这个
2016-7-22 17:07
0
雪    币: 180
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
duoxie!
2016-9-18 15:46
0
雪    币: 180
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
rc =
                MacroStrong_PhysicalMemoryAllocate(
                &Device,
                &Buffer_1,
                TRUE // Do not allocate a smaller buffer on failure
                );
        if (rc != MS_STATUS_OK)
        {
                Cons_printf("Error unable to allocate physical buffer\n");
                return -1;
        }

        Cons_printf("memory allocated: %d\n",Buffer_1.Size);
       
        // Map the buffer into user space
        rc =
                MacroStrong_PhysicalMemoryMap(
                &Device,
                &Buffer_1
                );
        if (rc != PLX_STATUS_OK)
        {
                Cons_printf("Error ÿ unable to map physical buffer\n");
                return -1;
        }

        rc = MacroStrong_PciRegisterWriteFast( &Device, 0x68,0x5f );
        if (rc != PLX_STATUS_OK)
        {
        Cons_printf("\n   ERROR: write 0x68 register fail\n");
             _Pause;
        }

        memset(Buffer_1.UserAddr, 0xaa, Buffer_1.Size);

        Cons_printf("Buffer_1.CpuPhysical:%x\n",Buffer_1.CpuPhysical);
        Cons_printf("Buffer_1.PhysicalAddr:%x\n",Buffer_1.PhysicalAddr);
        Cons_printf("Buffer_1.UserAddr:%x\n",Buffer_1.UserAddr);
       
        RegDataL= Buffer_1.PhysicalAddr&0x00000000ffffffff;
        RegDataU= (Buffer_1.PhysicalAddr>>32) &0x00000000ffffffff;
2016-9-18 15:53
0
雪    币: 20
活跃值: (136)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
想请问一下,为什么NonPagedPool分配出来的内存按照这个寻址找不到。最后的9位下标不是*8反而是*0x1000?
2019-5-31 11:18
0
雪    币: 21
活跃值: (66)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
sqdwr 想请问一下,为什么NonPagedPool分配出来的内存按照这个寻址找不到。最后的9位下标不是*8反而是*0x1000?
0x1000不就是8吗
2020-9-19 01:22
1
雪    币: 1067
活跃值: (627)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
mark,感谢,省去很多时间跟精力
2021-3-4 11:55
1
雪    币: 876
活跃值: (584)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
mark
2021-10-22 13:13
0
雪    币: 225
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
想请教一个问题,如何能将cr3的内容读取出来。不是mov eax, cr3。而是mov eax, [cr3].
2021-12-20 16:27
0
游客
登录 | 注册 方可回帖
返回
//