Geoff Chappell - Software Analyst
The MMPFN (Memory Manager Page Frame Number) structure is the key to pretty much everything that the Memory Manager knows about a page of physical memory that is in general use. Since an array of these structures for all physical memory needs to be kept in physical memory, the MMPFN is its own substantial overhead. Presumably to keep this down, ever more gets packed in to the MMPFN ever more intricately.
However untidy the construction of the MMPFN, it has several fields that are recognisably the same through all versions. A field that public symbol files (starting with Windows 2000 SP3) name as u1 is reliably at the start of the MMPFN. Another, named u2, is similarly ancient but has moved around within the MMPFN:
MMPFN Offset (x86) | MMPFN Offset (x64) |
---|---|
0x08 (3.10 to 5.2); 0x04 (6.0 to 6.3); 0x10 |
0x10 (late 5.2); 0x08 (6.0 to 6.3); 0x18 |
As a type, u2 is an unnamed union until Windows 10 turns into an MIPFNBLINK structure (formally _MIPFNBLINK) whose one direct member is the unnamed union. Either way, the unnamed union’s members are:
Definition | Versions |
---|---|
PFN_NUMBER Blink; |
3.10 to 6.1 |
struct { /* see below: Blink Bits */ }; |
6.2 and higher |
MMPTE *ImageProtoPte; |
6.0 to 6.3 |
ULONG_PTR ShareCount; |
3.10 to 6.3 |
struct { /* see below: ShareCount Bits */ }; |
10.0 and higher |
ULONG SecondaryColorFlink; |
5.0 only |
ULONG_PTR EntireField; |
10.0 and higher |
union { LONG_PTR volatile Lock; struct { /* see below: Lock Bits */ }; }; |
10.0 and higher |
The Blink is meaningful when the physical page represented by the MMPFN is on any of several lists, e.g., of free pages. It is specifically the Page Frame Number (PFN) of the previous physical page on the same list.
While 32-bit and 64-bit Windows need deal only with 36-bit and 48-bit physical addresses, pages of physical memory need only 24 or 36 bits of the ULONG or ULONGLONG that Microsoft defines for the PFN_NUMBER. Use for the excess bits was found for Windows 8.
Starting with 64-bit Windows 8, pages on a standby list can also be linked in a list just of pages that are on the same NUMA node. The ancient Blink coexists with what might be named NodeBlink except that its 36 bits are separated into NodeBlinkHigh and NodeBlinkLow. The high 20 bits are crammed into the one ULONGLONG with all 36 bits of the Blink. The low 16 bits replace the UsedPageTableEntries in the MMPFN directly.
Mask (x86) | Mask (x64) | Definition | Versions |
---|---|---|---|
0x01FFFFFF (6.2); 0x00FFFFFF |
0x0000000F`FFFFFFFF |
ULONG_PTR Blink : 25; |
6.2 only (x86) |
ULONG_PTR Blink : 24; |
6.3 and higher (x86) | ||
ULONG_PTR Blink : 36; |
6.2 and higher (x64) | ||
0x00FFFFF0`00000000 |
ULONG_PTR NodeBlinkHigh : 20; |
6.2 and higher | |
0x1E000000 (6.2); 0x0F000000 |
0x0F000000`00000000 |
ULONG_PTR TbFlushStamp : 4; |
6.2 and higher |
ULONG_PTR SpareBlink : 3; |
6.2 to 6.3 (x86) | ||
ULONG_PTR SpareBlink : 4; |
6.2 to 6.3 (x64) | ||
ULONG_PTR Unused : 2; |
10.0 and higher | ||
0x40000000 | 0x40000000`00000000 |
ULONG_PTR PageBlinkDeleteBit : 1; |
10.0 and higher |
0x80000000 | 0x80000000`00000000 |
ULONG_PTR PageBlinkLockBit : 1; |
10.0 and higher |
It’s not ordinarily a concern for these notes to track the masks of those bits that Microsoft labels spare, reserved or unused, but note that the narrowing of Blink by one bit for 32-bit Windows 8.1 is not accompanied by a widening of SpareBlink, which then does not account for all the spare bits. The highest two bits become meaningful in Windows 10 and are defined in all three sets of u2 bit fields, i.e., in union with Blink and ShareCount (where they apparently just mark space) and Lock (where they are meant to be used).
The ShareCount in Windows 10 loses the highest two bits to the Lock:
Mask (x86) | Mask (x64) | Definition | Versions |
---|---|---|---|
0x3FFFFFFF | 0x3FFFFFFF`FFFFFFFF |
ULONG ShareCount : 30; |
10.0 and higher (x86) |
ULONGLONG ShareCount : 62; |
10.0 and higher (x64) | ||
0x40000000 | 0x40000000`00000000 |
ULONG_PTR PageShareCountDeleteBit : 1; |
10.0 and higher |
0x80000000 | 0x80000000`00000000 |
ULONG_PTR PageShareCountLockBit : 1; |
10.0 and higher |
Although the Lock is newly in u2 for Windows 10, it developed from the use in version 6.1 of the low bit of the PteAddress as a lock that must be held while setting the PteAddress. The adaptation for Windows 10 uses the highest two bits. Even this may be just a formality, no use yet being known for the second bit. The lock itself is much like a KSPIN_LOCK but with no instrumentation and using the high bit instead of the low.
Mask (x86) | Mask (x64) | Definition | Versions |
---|---|---|---|
0x3FFFFFFF | 0x3FFFFFFF`FFFFFFFF |
ULONG LockNotUsed : 30; |
10.0 and higher (x86) |
ULONGLONG LockNotUsed : 62; |
10.0 and higher (x64) | ||
0x40000000 | 0x40000000`00000000 |
ULONG_PTR DeleteBit : 1; |
10.0 and higher |
0x80000000 | 0x80000000`00000000 |
ULONG_PTR LockBit : 1; |
10.0 and higher |