关于PFN DataBase
页帧号数据库 ( PFN DataBase ) 概述
物理内存被分页,对于32位的CPU来说,每个物理页大小是4K。对于每一个物理页,系统使用一个24字节长的结构来保存它的相关信息,比如该物理页是否已经被使用。为了便于描述,我们把这个结构叫做PfnDataBaseEntry ,页帧号数据库项。页帧号数据库就是一个 PfnDataBaseEntry 数组,这个数组的每一项对应一个物理页。比如 PfnDataBase 数组第0项,对应物理页0,也就是页帧号为0的物理页。第1项,对应物理1,也就是页帧号为1的物理页。系统把PfnDataBase的首地址保存在全局变量 MmPfnDatabase 中。现在我们来分析一下 物理页的页帧号(PFN),物理页的物理地址范围,物理页的页帧号数据库项之间的关系。对于物理页i,它的页帧号是i。由物理地址从i*0x1000到i*0x1000+0xFFF,这4KB物理内存单元组成。对应的页帧号数据库项为第i项,虚拟地址为 *MmPfnDatabase+i*0x18。比如在当前我所在的Win2k中,对于物理页3,它的页帧号是3,由物理地址0x3000-0x3FFF这4k的物理内存单元组成,当前我的 MmPfnDatabase 中的值为 0x81456000,即PfnDataBase 的首地址为 0x81456000,所以对应的 PfnDataBaseEntry 虚拟地址为 0x81456000 + 3*0x18 = 0x81456048。
PfnDataBaseEntry 的具体内容如下
struct PfnDataBaseEntry (大小24个字节,即0x18个字节)
/*00*/ uint32 flink
/*04*/ uint32 pteaddress
/*08*/ uint32 blink / share count
/*0C*/ byte flags
/*0D*/ byte page state
/*0E*/ uint16 reference count
/*10*/ uint32 restore pte
/*14*/ uint32 containing page
/*00*/ uint32 flink
链上前一个 PfnDataBaseEntry 的页帧号,如果为 0xFFFFFFFF 表示没有前一个 PfnDataBaseEntry。
/*08*/ uint32 blink / share count
对于使用链表链在一起的物理页,表示后一个 PfnDataBaseEntry 的页帧号,如果为 0xFFFFFFFF 表示没有后一个 PfnDataBaseEntry。对于没有使用链表链在一起的物理页,表示共享计数。
/*0C*/ byte flags
一些标志信息。
/*0D*/ byte page state
指出物理页的状态,就是从这里判断一个物理页是否已经被使用。物理页共有8种不同的状态。
Active(Valid):
这个物理页在某个进程的 Working Set 中,该进程的一个有效的页表项中的高20bit正是这个物理页的PFN。
Transition:
系统正在从一个文件将内容读入该物理页,或者正在向一个文件写出该物理页内容。
Standby:
这个物理页曾经在某个进程的 Working Set 中,并且物理页中的内容在被该进程使用时没有被改变过。但是现在已经被移出该进程的 Working Set,不过物理页中的内容仍是在该进程 Working Set 中时的内容。该进程相应的PTE中的高20bit仍然是这个物理页的页帧号,只是该PTE被标为 invalid 和 transition。当该进程需要再次访问这一页的内容时,只需要重新设定该PTE的标志,并把该PTE变为有效。把该物理页从 Standby 状态变为Active(Valid) 状态就可以了。
Modified:
这个物理页曾经在某个进程的 Working Set 中,并且物理页中的内容在被该进程使用时被改变过。但是现在已经被移出了该进程的 Working Set,不过物理页中的内容仍是被移出时的内容。该进程相应的PTE中的高20bit仍然是这个物理页的页帧号,只是该PTE被标为 invalid 和 transition。当该进程需要再次访问这一页的内容时,只需要重新设定该PTE的标志,并把该PTE变为有效。把该物理页从 Modified 状态变为Active(Valid) 状态就可以了。在该物理页被系统作为其他用途使用之前,该物理页中的内容需要被写入硬盘中的交换文件的相应页。
Modified no-write:
内存管理器的 Modified Page Writer 将不会把这种物理页写入硬盘,其他和 Modified 物理页一样。比如,NTFS使用这个状态来保证在log之前,该页不会被写入硬盘。
Free:
该物理页中的内容不再被需要,比如一个进程结束,这个进程所使用的一些物理页就会变为 Free 状态。(由于安全的原因,这些页需要被用零初始化,才能给一个用户进程使用)
Zeroed:
该页free并且已经被用零初始化。
Bad:
该页存在硬件错误,不能被使用。
其中 Zeroed,Free,Standby,Modified,ModifiedNoWrite,Bad 这6种状态的 PfnDataBaseEntry 使用PfnDataBaseEntry 的 flink,blink 链在该状态的 PfnDataBaseEntry链上。系统通过全局变量MmZeroedPageListHead,MmFreePageListHead,MmStandbyPageListHead,MmModifiedPageListHead,MmModifiedNoWritePageListHead,MmBadPageListHead 可以找到这6个链。这样当需要使用物理页的时候系统就可以很快的从相应的链中取出物理页。Active(Valid) 和 Transition 状态的 PfnDataBaseEntry 没有被任何链表链在一起,但是通过各个进程的PTE我们就可以找到,PTE的高20bit就是一个页帧号。