天天看点

XpSp3(未开启PAE模式)内存管理之系统PTE区域 下

    前面<

​​XpSp3(未开启PAE模式)内存管理之系统PTE区域 上​​>的结尾部分留了一个疑问:系统空闲PTE链表的结尾部分和全局变量nt!MmSystemPtesEnd中保存的值不同。

这篇尝试解释是什么导致了这样的差异。

    系统启动阶段时会调用nt!MiInitializeSystemPtes来初始化系统PTE区域。就如神话故事中天地是混在一起的一样,初始时,MmFirstFreeSystemPte指向的空闲链表中只有一个PTE节点,节点中共包含0xa244个系统PTE:

kd> bu nt!MiReserveAlignedSystemPtes ;内核调试时windbg第一次中断,此时系统还没有加载,因此只能下延迟断点。
kd> g ;系统调用nt!MiInitializeSystemPtes初始化系统PTE区域时会调用nt!MiReserveAlignedSystemPtes 参见<windows内核原理与实现>
Breakpoint 1 hit
nt!MiReserveAlignedSystemPtes:
8054bf66 8bff            mov     edi,edi
kd> kb ;回溯函数调用栈
ChildEBP RetAddr  Args to Child              
f7c55768 8054c040 --->00000020<---请求PTE的数量为0x20 00000000 00000000 nt!MiReserveAlignedSystemPtes
f7c5578c 80509e17 00000020 00000000 00000400 nt!MiReserveSystemPtes+0xab
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for BOOTVID.dll - 
f7c557f0 f7c4691b 000a0000 00000000 00020000 nt!MmMapIoSpace+0xb1
WARNING: Stack unwind information not available. Following frames may be wrong.
f7c55824 806ab5a7 806a2c01 00000000 806a2c01 BOOTVID!VidInitialize+0xe7
f7c55838 806a23be 80087000 00000013 00000000 nt!InbvDriverInitialize+0x6c
f7c55dac 8057beff 80087000 00000000 00000000 nt!Phase1Initialization+0xcb <----2 系统初始化阶段
f7c55ddc 804f98ea 806a22fa 80087000 00000000 nt!PspSystemThreadStartup+0x34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16 <---------1
kd> x nt!MmFirstFreeSystemPte ;查看此时系统空闲PTE链表
805609c0 nt!MmFirstFreeSystemPte = <no type information>
kd> dd 805609c0 L1
805609c0  ed400000 ;这个节点是空闲链表中的第一个节点
kd> ?? 0xc0000000+4*(0xed400000>>0x0c)
unsigned int 0xc03b5000
kd> dt ntoskrnl!_MMPTE_LIST 0xc03b5000
   +0x000 Valid            : 0y0
   +0x000 OneEntry         : 0y0 ;这个系统PTE的OneEntry位域==0,因此下一个PTE的NextEntry包含了整个PTE簇的数量
   +0x000 filler0          : 0y00000000 (0)
   +0x000 Prototype        : 0y0
   +0x000 filler1          : 0y0
   +0x000 NextEntry        : 0y11111111111111111111 (0xfffff) ;下一个节点为-1,即空
kd> dt ntoskrnl!_MMPTE_LIST 0xc03b5004 ;
   +0x000 Valid            : 0y0
   +0x000 OneEntry         : 0y0
   +0x000 filler0          : 0y00000000 (0)
   +0x000 Prototype        : 0y0
   +0x000 filler1          : 0y0
   +0x000 NextEntry        : 0y00001010001001000100 (0xa244) ;整个PTE簇的数量是0xa244      

    我们再来看看当前系统PTE区域中PTE的数量和0xC03B5004中显示的数值是否一致:

kd> x nt!MmTotalFreeSystemPtes
8055bdf0 nt!MmTotalFreeSystemPtes = <no type information>
kd> dd 8055bdf0 
8055bdf0  0000a244 <----      

    两者一致,这充分说明了当前系统中只有一个系统PTE簇。

    正如书上讲的那样,在我调试过程中发现每次调用nt!MiReserveAlignedSystemPtes函数都会从系统PTE区域的尾部抽取足够数量的PTE来满足调用者的请求。

kd> gu ;执行直到退出函数nt!MiReserveAlignedSystemPtes
nt!MiReserveSystemPtes+0xab:
8054c040 85c0            test    eax,eax
kd> dd nt!MmSystemPtesStart L1 ;系统PTE区域的起始地址并没有改变还是0xc03b5000
8055bde8  c03b5000
kd> x nt!MmFirstFreeSystemPte
805609c0 nt!MmFirstFreeSystemPte = <no type information>
kd> dd 805609c0 L1 ;空闲链表仍指向ed400000
805609c0  ed400000
kd> dt ntoskrnl!_MMPTE_LIST 0xc03b5000
   +0x000 Valid            : 0y0
   +0x000 OneEntry         : 0y0
   +0x000 filler0          : 0y00000000 (0)
   +0x000 Prototype        : 0y0
   +0x000 filler1          : 0y0
   +0x000 NextEntry        : 0y11111111111111111111 (0xfffff) ;下一个空闲PTE簇为-1,即为空
;这表明系统中仍只有一个系统PTE簇
kd> dd nt!MmTotalFreeSystemPtes L1
8055bdf0  0000a224 ;之前是0xa244,之前调用MiReserveAlignedSystemPtes请求0x20个PTE,现在还结余0xa224      

继续阅读