6 《Undocumented Windows 2000 Secrets》翻译 --- 第四章

第四章 探索 Windows 2000 的内存管理机制
翻译: Kendiv( fcczj@263.net)
更新: Sunday, February 17, 2005
声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利 。
IOCTL 函数 SPY_IO_PDE_ARRAY
SPY_IO_PDE_ARRAY 是另一个普通的函数,它只是简单的把整个页目录(开始于地址 0xC0300000 )复制到调用者提供的输出缓冲区中 。该缓冲区采用 列表 4-21 所示的 SPY_PDE_ARRAY 结构 。你可能已猜到,该结构的大小正好是 4KB,它由 1,024 个 32 位的 PDE 组成 。X86_PE 结构将在这里使用,X86_PE 结构代表一个一般化的页项( page entry ),可在 列表 4-3 中找到该结构的定义,常量 X86_PAGES_4M 定义在 列表 4-5。SPY_PDE_ARRAY 的结构体成员总是页目录项( PDE ),X86_PE 结构可以是 X86_PDE_4M 类型,也可以是 X86_PDE_4KB 类型,这取决于 PDE 的 PS 位的取值 。
在无法保证源数据页存在于物理内存时,就开始复制内存中的数据通常并不是一个好主意 。不过,页目录是少数列外中的一个 。在当前任务处于运行状态时,它的页目录总是存在于物理内存中 。它不会被置换到页面文件中,除非另一个任务被置换进来 。这就是为什么 CPU 的页目录基地址寄存器( PDBR )没有 P ( present )位的原因,PDE 和 PTE 也类似 。请参考 列表 4-3 中的 X86_PDBR 结构的定义,以验证这一点 。
typedef struct _SPY_PDE_ARRAY
{
X86_PE apde [X86_PAGES_4M];
}
SPY_PDE_ARRAY, *PSPY_PDE_ARRAY, **PPSPY_PDE_ARRAY;
#define SPY_PDE_ARRAY_ sizeof (SPY_PDE_ARRAY)
列表 4-21. SPY_PDE_ARRY 结构的定义
IOCTL 函数 SPY_IO_PAGE_ENTRY
如果你对给定线性地址的 page entry 感兴趣的话,这个函数就是一个很好的选择 。列表 4-22 给出了 SpyMemoryPageEntry() 的内部细节,该函数就是用来处理 SPY_IO_PAGE_ENTRY 请求的 。该函数返回的 SPY_PAGE_ENTRY 结构本质上是一个 X86_PE page entry (定义于 列表 4-3 ),不过这里增加了两个新成员(为了使用方便): dSize 和 fPresent。其中 dSize 成员用于说明页的大小(以字节为单位),其值不是 X86_PAGE_4KB ( 4,096 字节)就是 X86_PAGE_4MB ( 4,194,304 字节); fPresent 成员用来说明页是否存在于物理内存中 。这个标志必须和 SpyMemoryPageEntry() 自身的返回值进行对比,即使 fPresent 为 FALSE,函数自身的返回值也可为 TRUE。此时,提供的线性地址时有效的,但它指向的数据页已被置换到了页面文件中 。这种情况可通过设置 page entry 的第 10 位(即 列表 4-22 中出现的 PageFile )来表示 。当 P 位(该位属于 X86_PNPE 结构)被置 0 时,PageFile 就会被设置 。请参考本章稍早讨论过的 X86_PNPE 结构的细节 。X86_PNPE 结构代表一个 page-not-persent entry,该结构定义于 列表 4-3。
SpyMemoryPageEntry() 首先假定目标页是 4MB 页,然后,从系统的 PDE 数组(此数组起始于 0xC0300000 )中复制指定线性地址的 PDE 到 SPY_PAGE_ENTRY 结构体的 pe 成员 。如果 P 位不为 0,则肯定存在下一级的页或页表,所以接下来检查 PS 位以确定页面大小 。如果 PS 位不为 0,则表示此 PDE 指向一个 4MB 数据页,工作到此就可结束了 ------SpyMemoryPageEntry() 返回 TRUE,并且 SPY_PAGE_ENTRY 结构体的 fPresent 成员也同时被设为 TRUE。如果 PS 位为 0,则 PDE 指向的是一个 PTE,所以代码从起始于 0xC0000000 的数组中提取该 PTE,并检查它的 P 位 。如果不为 0,则包含指定线性地址的 4KB 页存在于物理内存中,此时,SpyMemoryPageEntry() 和 fPresent 都会报告 TRUE。否则,找到的必定是一个 page-not-present entry,因此 SpyMemoryPageEntry() 返回 TRUE,不过仅当 PageFile 位不为 0 时,fPresent 成员才会被设为 FALSE。
typedef struct _SPY_PAGE_ENTRY

推荐阅读