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 originated as a union is certain: even version 3.10 uses the space variously as the Flink, WsIndex and Event (at least).

Definition Versions
1709 and higher
1709 and higher
all (x86);
late 5.2 to 6.1 (x64)
struct {
    ULONGLONG Flink : 36;
    ULONGLONG NodeFlinkHigh : 28;
6.2 and higher (x64)
struct {
    ULONG MustNotBeZero : 2;
    ULONG Age : 3;
} PageTableWsle;
1703 only
ULONG WsIndex;
3.10 to 6.2
6.3 to 1703
KEVENT *Event;
3.10 to 1703
NTSTATUS ReadStatus;
5.0 to 5.2
6.0 to 1703
PVOID volatile VolatileNext;
6.0 to 1703
KTHREAD *KernelStackOwner;
6.0 to 1703
MMPFN *NextStackPfn;
5.0 only
5.1 to 1703
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.