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.

However untidy the construction of the MMPFN, all known versions have recognisably the same pointer-sized field at offset 0x00. As a type, this field is an unnamed union. Members have come and gone and been narrowed or widened, but some have been present through the whole history.

Public symbol files for the kernel, starting with Windows 2000 SP3, name this field as u1. Before Windows 10, it’s a direct member of the MMPFN. For Windows 10, talk of it as an MMPFN member is loose in that it is wrapped into an unnamed structure in another unnamed union, and it is the latter that is directly the MMPFN member. Still, this complex nesting does take the trouble to keep u1 at offset 0x00, compatibly with its having been a direct member all along. That the union existed right from the start is certain, since the kernel from version 3.10 uses the space variously as the Flink, WsIndex and Event (at least).

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

The WsIndex is a 0-based index into an array of MMWSLE structures. This index was widened from 32 bits to 64 for 64-bit Windows 8.1. Microsoft almost certainly defines a type for this index. The KDEXTS.DLL debugger extension confirms with high confidence that Microsoft’s name for this type is WSLE_NUMBER. It is originally a ULONG but becomes a ULONG_PTR for version 6.3 and higher.