MMPFN Union 2

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.

Blink Bits

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).

ShareCount Bits

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

Lock Bits

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