前面<
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