分享
 
 
 

探究Windows 2000/XP原型PTE

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

内存管理可以说是操作系统实现中最重要的环节,也是最为复杂的一环节。对于相对贫乏的内存资源,内存共享也成了一个很重要的有效手段。Windows 2000/XP在此方面的实现借助于一个称为原型PTE(Prototype PTE,PPTE)的软件机制。在《小议Windows NT/2000分页机制》中我详细的介绍了Intel X86实现分段、分页的硬件PTE工作方式。我们来回顾一下这种机制:

假设我们的一个进程映射了从虚拟地址0xXXXXXXXX(假设位于分配粒度上)开始的4M空间,而这4M空间当前都相应的映射了实际的物理内存(鉴于Lazy evaluation等的先进思想,这种情况在Windows 2000/XP中比较少见)。我们将这4M空间分成1000块的4K(PAGE_SIZE,X86处理器决定),对于第n个4K(0<=n<1000),其虚拟地址(0xXXXXXXXX+n*4K),我们都有一个对应的硬件PTE,指出目前这4K驻留于物理内存的位置。通过由PDBR(CR3寄存器)与虚拟地址可定位这个硬件PTE(具体请参阅《小议Windows NT/2000分页机制》)。

现在让我们来考虑这样一种情况,我们有一个文件其大小也为4M,我们知道通常我们要使用这个文件都要将它读入内存。试想同时有两个或更多的进程需读写这个文件,这就需要解决内存共享的问题。实际上就算当前只有一个进程访问这个文件,对于这种潜在的需要共享的文件,Windows 2000/XP均会事先考虑共享情况。她通过一个称为Section的内核对象来实现这样的目的。仔细想想,这种情况下内存共享决不仅仅是内存资源的充分利用,就算我们可以为每个进程各分配4M空间,但是这将导致各个进程某种时刻可能得不到这个文件的最新内容。这是非常糟糕的情况。在内部Windows 2000/XP利用原型PTE来解决这样的情况。基于硬件PTE相同的原理,对于这样一个4M的文件,在映射这个文件时,Windows 2000/XP同样的将这个文件分成1000块,每块4K(PAGE_SIZE)大小。然后从页交换区分配1000个DWORD,每个DWORD值都是原型PTE,它们组成原型PTE表。对于这个文件的第n个4K(0<=n<1000),如果当前其驻留在物理内存中的话,其对应的PPTE的Valid位(bit 0,与硬件PTE一致)为1,然后这个PPTE的Page Frame Number(PPTE的高20位)用于指示物理内存。如果当前其仍然在磁盘中的话,Valid位为0。针对这种情况,通过PPTE的高20位(PFN Entry),查找Page Frame Datbase(由MmPfnDatabase定位),通过PFN Entry的Subsection PTE(windbg中称为restore pte,《Inside Windows 2000》中称为original pte,Windows XP内部称为Subsection PTE),定位Subsection,然后通过Subsection指向的Control Area的FILE_OBJECT,与PPTE在PPTE表的偏移n,通过公式:

PFN Entry Subsection PTE->Subsection->Control Area->FileObject + n * 4K

定位所要访问的文件偏移,这样Windows 2000/XP使用页面调入IO读入这页内容,更新PPTE表的这个PPTE。以上的这一系列定位转换算法,如Subsection PTE如何定位Subsection,我将另行介绍。上面的描述解决了一个非常重要的问题,我们不需要更新所有引用这一页面的进程的硬件PTE,因为此时所有进程的PTE均指向PPTE,我们只要更新PPTE就能达到目的。至于进程PTE如何指向PPTE,下面我会涉及到这个内容。这儿你只要有一个概念,进程的PTE为了指向PPTE,肯定是一个Invalid PTE,即bit 0为0,而且其bit 10为1(PPTE标志,具体请看我在《探寻Windows NT/2000 Copy On Write机制》列出的HARDWARE_PTE_X86结构)。

对于PPTE,因为X86处理器没有提供这样一种方式,像处理硬件PTE一样,由CPU直接进行地址转换。Windows 2000/XP内存管理器在处理Page Fault时,通过软件机制来模拟这种实现,这可以说是硬件PTE与PPTE的一个本质区别。

应该重点提出的是PPTE存在于页交换区(由MmPagedPoolStart与MmPagedPoolEnd指定的位置,从虚拟地址0xE1000000开始),其本身也有可能被Page Out,Windows 2000/XP通过MiCheckProtoPtePageState判断是否被Page Out,还有页交换区的起始地址0xE10000000将用于从无效PTE转化成原型PTE所在的地址,这等一下我会介绍到的。

照例我们用SoftICE来验证一下我们前面的描述:

:bpint e

只要我们截获这个硬件中断,我们就知道肯定发生了Page Fault,但是我们并不能确定这都是由于指向PPTE的无效PTE导致的。事实上Copy On Write等等其他机制,均会发生Page Fault(《探寻Windows NT/2000 Copy On Write机制》有详细讨论)。但是正如我们前面提及的PPTE的bit 10为1,我们还是很容易的判定一个Page Fault是不是由于指向PPTE的无效PTE导致的。由于发生Page Fault的虚拟地址由CR2寄存器指定,经过几次尝试以后,我们继续以下的讨论:

Break due to BPINT 0E (ET=2.23 Seconds)

:cpu

Processor 00 Registers

----------------------

CS:EIP=0008:801648A4 SS:ESP=0010:FCBEADC8

EAX=C002100B EBX=77E74A02 ECX=00000102 EDX=00000000

ESI=00085108 EDI=000493E0 EBP=0140FF74 EFL=00000006

DS=0023 ES=0023 FS=0038 GS=0000

CR0=8000003B PE MP TS ET NE PG

CR2=77D3BB26 //发生Page Fault的虚拟地址。

.

.

.

:page 77d3bb26

Linear Physical Attributes

77D3BB26 NP 01A714F6

从PTE值01A714F6的bit 10为1我们知道这是一个指向PPTE的无效PTE。通过query命令我们可以找到CR2指定的地址,位于模块rpcrt4.dll中。从下面可以看到:

:query 77d30000

Context Address Range Flags MMCI PTE Name

explorer 77D20000-77D8E000 07100001 FF8D1328 E169C580 rpcrt4.dll

结合我文章开始的介绍,通过以下的计算:

:? (77d3bb26-77d20000)/1000*4+e169c580

unsigned long = 0xE169C5EC, -513161748, "\xE1i\xC5\xEC"

我们可以得到其实PTE 01A714F6应该指向0xE169C5EC位置。这时候由MMCI指向的Control Area,根据我上面提到的计算公式,即可以读出rpcrt4.dll偏移(0xE169C5EC-0XE169C580)/4*1000处,即0x1B000处的4K字节,读入虚拟地址77D3B000中((0xE169C5EC-0XE169C580)/4*1000+77D20000),而CR2指定的地址77D3BB26肯定在这4K之中。

其实这样我们已经描述了MmAccessFault处理指向PPTE的无效PTE的一个典型过程。这里只是演示了原型PTE指向的页面未驻留在物理内存的情况,试想如果我们的页面已经在物理内存了,我们还有必要去费时的查找VAD吗?这就要涉及到无效的PTE如何定位原型PTE,所以我一直使用指向PPTE的无效PTE的叫法。《Inside Windows 2000》中指出指向PPTE的无效PTE的具体格式,但我发现其描述的不尽正确,我一直深信像作者那样能触及Windows 2000代码的人肯定不会有什么问题,所以我在理解PPTE时一直卡在此处。后来通过反汇编实现时发现实际上通过下面的方式来计算PPTE的位置:

(PTE>>2) & 0x3FFFFE00 + (PTE & 0x000000FF) << 1 + 0xE1000000

其中PTE为指向PPTE的无效PTE,0xE10000000是页交换区的起始地址。同样我们使用上面的例子来演示这个算法:

上面的无效PTE为01A714F6,有了这个值,我们可以得到:

PPTE Address = (0x01A714F6 >> 2) & 0x3FFFFE00 + (0x01A714F6 & 0x000000FF) << 1 + 0xE1000000

= 0x0069C53D & 0x3FFFFE00 + 0xF6 << 1 + 0xE1000000

= 0x69C400 + 0x1EC + 0xE1000000

= 0xE169C5EC

与我们通过VAD查找到的PPTE位置0xE169C5EC一致。

为了更好的理解PPTE,我们再来看一个例子。我们知道在Windows 2000/XP中ntdll.dll是个非常重要的dll,只要操作系统正常启动,ntdll肯定会被多个进程共享。我们用SoftICE作如下分析:

:query -x 77f50000

Context Address Range Flags MMCI PTE Name

smss 77F50000-77FF8000 07100005 80E6FA50 E131F9E8 ntdll.dll

.

.

.

explorer 77F50000-77FF8000 07100005 80E6FA50 E131F9E8 ntdll.dll

.

.

.

:addr smss

:mod ntdll

hMod Base PEHeader Module Name File Name

77F50000 77F500E8 ntdll \WINDOWS\system32\ntdll.dll

根据ntdll的基地址77F50000,我们查看其硬件PTE:

:dd 1df*1000+350*4+c0000000 l 4 //详细请参考《小议Windows NT/2000分页机制》

0010:C01DFD40 02267027 02F2E005 02F2F005 00C7E4FA 'p&.............

从smss进程的这些页表,我们很容易知道ntdll.dll第1至3个4K均驻留于物理内存地址中,因为它们都是有效的硬件PTE,而第四个PTE(00C7E4FA),虽然其是一个无效PTE(bit 0为0),但由于其是一个指向PPTE的PTE(bit 10为1),所以我们不能仅凭此PTE是个无效PTE,就断定ntdll.dll的第4个4K就不在物理内存中。我们要进一步的分析这个PTE,找出指向的PPTE判断这第4个4K是不是真的就是在磁盘中。OK,通过上面提及的算法,我们很容易的算出PPTE Address为E131F9F4,我们来看看这个PPTE的值:

:dd e131f9f4 l 4

0010:E131F9F4 02F30121 02F31121 02F32121 02F33121 !...!...!!..!1..

从值02F30121我们这时就可以判定这第4个4K也存在于物理地址中,位于Page Frame Number为02F30的物理内存中,剩下的就是查PFN Database了。

我们也可以来查看查看explorer进程的ntdll.dll映射情况,来验证一下这种情况:

:addr explorer

:dd 1df*1000+350*4+c0000000 l 4

0010:C01DFD40 02267025 02F2E025 02F2F025 02F30025 %p&.%...%...%...

这回清楚了吧。文章开头我提及:“我们不需要更新所有引用这一页面的进程的硬件PTE,因为此时所有进程的PTE均指向PPTE,我们只要更新PPTE就能达到目的了”。从中我们也可以看到ntdll.dll的第4个4K实际上位于物理内存中,但Windows 2000/XP并没有更新每个引用此页面的PTE,就正如smss进程一样。而PPTE却已经指向其实际地址了。当smss进程首次访问这个区域时,内存管理器才将02F30025(假设属性与explorer进程使用这页的属性一样且为考虑访问位标志)这个有效的硬件PTE更新上面的00C7E4FA,现在一切都明朗了吧。

本文虽然着重点在于介绍PPTE,但实际上我已将Section对象的内部机制说得非常清楚。这也是我原先将文章标题定为剖析Section之类的。关于PPTE,我的理解也经历了较多时间,主要是目前这部分资料实在是没有,仅有的《Inside Windows 2000》在没深入介绍的同时其指向PPTE的无效PTE格式未明确指出(特别是加上0xE1000000,这让我吃尽了苦头),本文介绍的这个格式我已经在Windows 2000及XP上测试过,实际上本文的两个例子一个是在Windows 2000 Server Build 2195,另一个在XP专业版Build 2600上演示的。

在这次介绍PPTE后,我们来回顾一下内存管理器内部的几个千丝万缕的联系:

FILEOBJECT的SECTION_OBJECT_POINTERS->DataSectionObject或SECTION_OBJECT_POINTERS->ImageSectionObject(决定于Section对象映射的文件的打开方式)指向Control Area,同时进程描述这文件映射的虚拟地址的VAD的MMCI成员(SoftICE叫法)也指向这个Control Area,Control Area底下存在一至多个SubSection,SubSection指向PPTE,PPTE table一般位于Control Area指向的Segment结构的底部。Section对象指向Segment;进程Page Table指向PPTE;这一切现在已描述的比较清楚了。还有一个主要的联系,即PFN Entry的Restore PTE(Original PTE)指向Subsection,这个关系我将在下次予以介绍。

从《小议Windows NT/2000分页机制》到今天这篇介绍PPTE,我对Windows 2000/XP的内存管理部分才有了比较深入的理解,至于未提及到的Working Set等概念也是非常重要的。经历过很多的模糊,对内存管理器也总算有了些许概念了。所有讨论均基于自己的理解,对错请多多指教(tsu00@263.net)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有