MMPFN Union 1

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.

All known versions of the MMPFN have a u1 member at offset 0x00. As a type, it’s an unnamed union. Members have come and gone and been reordered. That it orginated as a union is certain: even version 3.10 uses the space variously as the Flink, WsIndex and Event (at least).

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
SINGLE_LIST_ENTRY NextSlistPfn;
1709 and higher
0x00 0x00
PVOID Next;
1709 and higher
0x00 0x00
PFN_NUMBER Flink;
3.10 and higher (x86);
late 5.2 to 6.1 (x64)
struct {
    ULONGLONG Flink : 36;
    ULONGLONG NodeFlinkHigh : 28;
};
6.2 and higher (x64)
0x00 0x00
struct {
    ULONG MustNotBeZero : 2;
    ULONG Age : 3;
} PageTableWsle;
1703 only
0x00 0x00
ULONG WsIndex;
3.10 to 6.2
ULONG_PTR WsIndex;
6.3 to 1703
0x00 0x00
KEVENT *Event;
3.10 to 1703
0x00 0x00
NTSTATUS ReadStatus;
5.0 to 5.2
0x00 0x00
PVOID Next;
6.0 to 1703
0x00 0x00
PVOID volatile VolatileNext;
6.0 to 1703
0x00 0x00
KTHREAD *KernelStackOwner;
6.0 to 1703
0x00 0x00
MMPFN *NextStackPfn;
5.0 only
SINGLE_LIST_ENTRY NextStackPfn;
5.1 to 1703
0x00 0x00
MI_ACTIVE_PFN Active;
1709 and higher

The Flink 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 PFN of the next physical page on the same list. While 32-bit and 64-bit Windows need deal only with 36-bit and 48-bit physical addresses, a PFN uses only 24 or 36 bits of its integral type: excess bits can be used for other purposes concurrently. 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 Flink coexists with what might be named NodeFlink except that the latter’s 36 bits are separated into a NodeFlinkHigh and a NodeFlinkLow. Only the high 28 bits are crammed in with the intact 36-bit Flink at offset 0x00. The low 8 overlay the ViewCount in the MMPFN directly.