Prototype PTE

来源:互联网 发布:java调用c语言 编辑:程序博客网 时间:2024/05/29 08:26
#define MM_DEFAULT_PAGED_POOL_START (0xE1000000) #define MiPteToProto(lpte) (DWORD)((DWORD)(((((lpte)) >> 11) << 9) +  \                (((((lpte))) << 24) >> 23) + \                MM_DEFAULT_PAGED_POOL_START))int main(int argc, _TCHAR* argv[]){    DWORD PTE=0x00938c9c;    DWORD BASE=MM_DEFAULT_PAGED_POOL_START;    cout<<std::hex<<MiPteToProto(PTE)<<endl;    cin.get();    }
#define MiProtoAddressForPte(proto_va)  \   ((((((ULONG)proto_va - MmProtopte_Base) >> 1) & (ULONG)0x000000FE)   | \    (((((ULONG)proto_va - MmProtopte_Base) << 2) & (ULONG)0xfffff800))) | \    MM_PTE_PROTOTYPE_MASK)// 依据ProtoAddress还原PTE


依据PTE计算出PPTE—ADDRESS

如上图:

DD  dd c01de478
0x00938c9c  依据PTE的标记位为0 无效

 

PPTE-ADDRESS=0xe124e338

kd> dd e124e338
e124e338  17cfa121 176bb121 17def121 17c70860
e124e348  17d71860 17fb2860 17bb3860 17cb4860
e124e358  17f75860 17d36860 11d43860 12f44860
e124e368  11245121 11a46121 14707121 17fbc121
e124e378  181fd860 18a7e860 16fff121 16f40860
e124e388  17d41860 17f42121 17183121 188a2860
e124e398  18ae3121 18964121 18765121 18926121
e124e3a8  18827121 18868860 18d29860 18cb88a0

 

经过PAGE异常后

 

kd> dd c01de478
c01de478  17cfa025 176bb025 17def025 00000000
c01de488  00000000 00000000 00000000 00000000
c01de498  00000000 00000000 00000000 00000000
c01de4a8  11245025 11a46025 14707025 17fbc025
c01de4b8  00000000 00000000 16fff025 00000000
c01de4c8  00000000 17f42025 17183025 00938cca
c01de4d8  18ae3025 18964025 18765025 18926025
c01de4e8  18827025 00938cd6 00938cd8 181ba867

进程1第一次将一些可以被共享的内容读入一个物理页。于是进程1相应的PTE有效,并指向这个物理页。被共享的物理页对应的 PFN DataBase Entry 状态为 Active(Valid) ,share count 值为1。

进程2需要共享这个物理页,于是进程2相应的PTE有效,并指向这个物理页。由于这个物理页现在被进程1和进程2共享,所以对应的 PFN DataBase Entry 的 share count 的值加1,变为2。

进程3需要共享这个物理页,于是进程3相应的PTE有效,并指向这个物理页。这个物理页对应的 PFN DataBase Entry 的 share count 的值加1,变为3。

进程2修整 Working Set (工作集),决定把该页从自己的 Working Set 中移出,于是相应的PTE无效。这个物理页对应的 PFN DataBase Entry 的 share count 的值减1,变为2。

进程1结束,这个物理页对应的 PFN DataBase Entry 的 share count 的值又减1,变为1。

进程2又需要访问这个共享页。于是PTE重新有效,并指向这个物理页。物理页的 share count 加1,又变为2。

进程2,进程3,修整 Working Set (工作集),都把这页从 Working Set 中移出,于是两个进程相应的PTE都无效。物理页的 share count 从 2 变成了 0。当变成0时,该物理页的状态从 Active(Valid) 变成了 Standby,链入了 Standby 链,不过该物理页中的内容不会被改变。

进程2又需要访问这个共享页。由于该物理页在 Standby 链上,内容没有被改变。于是直接取回该物理页,PTE重新有效并指向这个物理页。物理页状态从 Standby 变为 Active(Valid) , share count 变为1。

进程2又修整 Working Set (工作集),决定把该页从自己的 Working Set 中移出,于是相应的PTE无效。这个物理页的 share count 的值减1,变为0。当变成0时,该物理页的状态从 Active(Valid) 变成了 Standby,链入了 Standby 链,不过该物理页中的内容不会被改变。

系统需要内存,从 Standby 链上取走了该物理页。

进程2又需要访问这个共享页。没有物理页有原来的数据了,于是分配一个新的物理页,从文件中将数据读入。于是进程2相应的PTE有效,并指向这个新的物理页。这个物理页对应的 PFN DataBase Entry 状态为Active(Valid) ,share count 值为1。

    需要强调的一点是,只有被共享的物理页的 share count 减为 0 时,才能被移入 Standby 链,然后被用来做其他事。如果 share count 不为0,就说明还有进程在使用这个物理页,如果这时把这个物理页移入 Standby 链,可能会有非常严重的后果。比如放着被共享的dll的程序代码的一个物理页,被多个进程共享,而其中一个结束,share count 减1但不为0,这时如果把这个物理页移入 Standby 链,系统又把这个物理页给清零,放入 Zeroed 链中待用。而这时其他几个进程的相应的PTE仍然是有效的,并且指向这个本来该是程序代码的物理页。当这几个进程执行这里的代码的时候,将会彻底出错。如果 share count 为0 ,所有进程相应的 PTE 都已经无效了。

    共享机制还有一个问题。一个被共享的物理页 share count 为0 ,并且已经被用来做其他事,所有进程相应的 PTE 都已经无效了。当一个进程访问相应 PTE 对应的地址空间,系统会分配一个新的物理页,从文件中将数据读入新的物理页,相应的PTE有效,并指向这个新的物理页,这样这个进程就可以访问这个共享页。但是其他的进程无法知道这个新的物理页,他们相应的PTE仍然无效。他们如果也重新访问这个共享页,他们将如何得知新的物理页来填入PTE?Win2k 使用 Prototype PTE 来解决这个问题。

    对于一个载入内存的应用程序,载入内存的动态链接库,或者一个文件映射,他们都有可能被共享。比如一个可能被共享的东西,映射到地址空间,需要100页,那么每页都有一个相应的 Prototype PTE (4个字节)。一个进程把这个100页的共享的东西映射到地址空间,需要用100个PTE。这100个PTE中,有效的PTE指向共享的物理页,无效的PTE将指向相应的 Prototype PTE ,Prototype PTE 指向物理页。这样一来,当遇到前面的问题,一个进程重新访问一个共享页,而这个共享页原来映射的物理页已经做其他事,系统分配新的物理页,把进程相应的PTE指向新的物理页,并把PTE变为有效之后,也把 Prototype PTE 指向新的物理页。其他的进程重新访问这个共享页时,他们的PTE是无效的,并且指向 Prototype PTE ,而 Prototype PTE 这时就已经指向了新的物理页,于是他们就可以把相应的PTE指向新的物理页,并把PTE变为有效。

    载入内存的应用程序,载入内存的动态链接库,或者一个文件映射,他们都位于用户地址空间。为了描述方便我们把这些都叫做共享的东西。一个共享的东西都会有一个位于系统地址空间的 Segment 结构,这个共享的东西的 Prototype PTE 都顺序的放在这个 Segment 结构的 ProtoPtes数组中。比如一个共享的东西,映射到地址空间需要100页,那么它就有100个 Prototype PTE 放在它的 Segment 结构的 ProtoPtes数组中,并且它的第0页对应的 Prototype PTE 在数组的第0项,它的第1页对应的 Prototype PTE 在数组的第1项。Segment 结构0x38字节长,其中比较重要的是偏移+34处的 4个字节长的 ProtoPtes。ProtoPtes 中为 ProtoPtes数组 的首地址,不过通常情况下,ProtoPtes数组 就紧跟在 0x38字节长的 Segment 结构之后。Segment 结构偏移+8处4个字节长的 Total Ptes 指明了 ProtoPtes数组 中元素的个数。Segment 结构偏移+0处的4个字节长的 ControlArea,是一个指向 ControlArea 结构的指针,ControlArea 结构是一个很重要的结构,通过它我们可以找到相应的 File Object ,ControlArea 结构还有指回 Segment 结构 的指针

 

原创粉丝点击