MMPFNENTRY

The MMPFNENTRY structure (formally _MMPFNENTRY) is nowadays a set of bit flags that are thought to exist only in the u3 member of an MMPFN. The 32-bit u3 is in essence 16 bits of flags and a 16-bit reference count, in that order originally, but later reversed.

For its original placement in u3, dating from version 4.0, the MMPFNENTRY is the 4-byte e1 branch. Though the flags are all in the word at offset 0x0C in the MMPFN, they are formally ULONG bit fields with space for the reference count left at the end as one 16-bit field named DontUse. The reference count is instead accessed through the e2 branch of the union, also 4 bytes, but defining the ReferenceCount as a USHORT (at offset 0x0E in the MMPFN) after leaving space for the flags as a USHORT named ShortFlags.

The flags and reference count are swapped for the version 5.2 from Windows Server 2003 SP1, and in all versions since. This change reduced the MMPFNENTRY to two bytes. It then is just 16 bits of flags that follow the ReferenceCount. The flags were not rearranged, but they formally change type to be USHORT bit fields. Version 6.0 reorganises them into two bytes of UCHAR bit fields. The 1607 release of Windows 10 discontinues the MMPFNENTRY in favour of separating the two bytes of flags into their own structures, named MMPFNENTRY1 and MMPFNENTRY3.

The MMPFNENTRY has so long been a container just for 16 bits of flags that it’s only natural to wonder in what sense are they any sort of entry. For that, look back to when the MMPFN has neither a u3 nor bit flags at offset 0x0C. Before version 4.0, its only bit flags are at offset 0x14 in combination with the PteFrame. This dword is in the style of a Page Table Entry (PTE), with a 20-bit Page Frame Number (PFN) in the high bits, leaving the low 12 bits for flags. It is here thought that this combination is the original MMPFNENTRY and that when version 4.0 moved these flags to offset 0x0C and left the PteFrame behind, the name MMPFNENTRY followed the flags.

Inevitably, pressure for more flags kept building. Whatever was gained by separating the old flags from PteFrame, it left 12 bits spare at offset 0x14. By version 5.1, PteFrame is recast into another union, u4, with new flags in the high bits. Some flags that moved with the MMPFNENTRY then move back to their old site.

Four-Byte Original

The MMPFNENTRY starts as a four-byte structure of ULONG bit fields before 64-bit Windows exists. It is the whole dword at offset 0x14 in the MMPFN before version 4.0 and then moved to offset 0x0C in u3.

Mask Definition Versions Remarks
0x00000001
ULONG Modified : 1;
3.10 to early 5.2  
0x00000002
ULONG ReadInProgress : 1;
3.10 to early 5.2  
0x00000004
ULONG WriteInProgress : 1;
3.10 to early 5.2  
0x00000008
ULONG PrototypePte : 1;
3.10 to early 5.2  
0x00000070 (3.10 to 5.1);
0x000000F0
ULONG PageColor : 3;
3.10 to 5.1  
ULONG PageColor : 4;
early 5.2 only  
0x00000080 (3.10 to 5.1)
ULONG ParityError : 1;
3.10 to 5.1 next as 0x00008000
0x00000700
ULONG PageLocation : 3;
3.10 to early 5.2  
0x00000800 (3.10 to 5.0)
ULONG InPageError : 1;
3.10 to 5.0 next in u4
0x00001000 (5.0)
ULONG VerifierAllocation : 1;
5.0 only next in u4
0x00002000 (5.0);
0x00000800
ULONG RemovalRequested : 1;
5.0 to early 5.2  
0x00003000
ULONG CacheAttribute : 2;
5.1 to early 5.2  
 
ULONG Reserved : 4;
4.0 only  
ULONG Reserved : 1;
5.0 only  
0x00004000
ULONG Rom : 1;
5.1 to early 5.2  
0x00008000
ULONG LockCharged : 1;
5.0 to 5.1 next in u4
ULONG ParityError : 1;
early 5.2 only previously 0x00000080
0xFFFFF000 (3.10 to 3.51);
0xFFFF0000
ULONG PteFrame : 20;
3.10 to 3.51 next in MMPFN
ULONG DontUse : 16;
4.0 to early 5.2  

The multi-bit PageLocation and CacheAttribute take their values from the MMLISTS and MI_PFN_CACHE_ATTRIBUTE enumerations, respectively.

When version 4.0 moved 12 bits of flags from the dword at offset 0x14 to the word at offset 0x0C without rearrangement, it gained 4 bits of space but is not known to have defined any of these bits. Version 5.0 is known (from public symbol files) to define one of the new four as Reserved, apparently having found use for only three. Presumably, those that are not used in version 4.0 are also defined as Reserved.

Windows Server 2003 SP1

The version 5.2 from Windows Server 2003 SP1 reduced the MMPFNENTRY to a two-byte structure of USHORT bit fields. That each bit retained its position from the four-byte MMPFNENTRY was very short-lived: the few that Windows Vista didn’t rearrange (see next section) were instead moved away:

Mask Definition Versions Remarks
0x0001
USHORT Modified : 1;
late 5.2 only next as 0x10 in first byte
0x0002
USHORT ReadInProgress : 1;
late 5.2 only next as 0x20 in first byte
0x0004
USHORT WriteInProgress : 1;
late 5.2 only next as 0x08 in first byte
0x0008
USHORT PrototypePte : 1;
late 5.2 only next in u4
0x00F0
USHORT PageColor : 4;
late 5.2 only next in u4
0x0700
USHORT PageLocation : 3;
late 5.2 only next as 0x07 in first byte
0x0800
USHORT RemovalRequested : 1;
late 5.2 only next as 0x40 in second byte
0x3000
USHORT CacheAttribute : 2;
late 5.2 only next as 0xC0 in first byte
0x4000
USHORT Rom : 1;
late 5.2 only next as 0x08 in second byte
0x8000
USHORT ParityError : 1;
late 5.2 only next as 0x80 in second byte

Windows Vista and Higher

Windows Vista reorganised the MMPFNENTRY into a two-byte structure of UCHAR bit fields. The 1607 release of Windows 10 then redefines each byte as its own structure, MMPFNENTRY1 and MMPFNENTRY3 respectively, each still as UCHAR bit fields.

First Byte

The flags in the new MMPFNENTRY1 or in the first byte of the two-byte MMPFNENTRY are accessed from an MMPFN through its u3.e1 nesting.

Offset / Mask Definition Versions Remarks
0x00 / 0x07
UCHAR PageLocation : 3;
6.0 and higher previously 0x0700
0x00 / 0x08
UCHAR WriteInProgress : 1;
6.0 and higher previously 0x0004
0x00 / 0x10
UCHAR Modified : 1;
6.0 and higher previously 0x0001
0x00 / 0x20
UCHAR ReadInProgress : 1;
6.0 and higher previously 0x0002
0x00 / 0xC0
UCHAR CacheAttribute : 2;
6.0 and higher previously 0x3000

All these flags were previously USHORT bit fields in the two-byte MMPFNENTRY.

Second Byte

The flags in the new MMPFNENTRY3 are accessed from an MMPFN through its u3.e3 nesting. Before 1607, these flags are in the second byte of the two-byte MMPFNENTRY and are accessed through u3.e1, just like the flags in the first byte.

Offset / Mask Definition Versions Remarks
0x01 / 0x07
UCHAR Priority : 3;
6.0 and higher previously in u4
0x01 / 0x08
UCHAR Rom : 1;
6.0 to 6.1 previously 0x4000
UCHAR OnProtectedStandby;
6.2 and higher  
0x01 / 0x10
UCHAR InPageError : 1;
6.0 and higher previously in u4
0x01 / 0x20
UCHAR KernelStack : 1;
6.0 to 6.1 previously in u4
UCHAR Spare : 1;
6.2 to 6.3  
UCHAR SystemChargedPage : 1;
10.0 and higher  
0x01 / 0x40
UCHAR RemovalRequested : 1;
6.0 and higher previously 0x0800
0x01 / 0x80
UCHAR ParityError : 1;
6.0 and higher previously 0x8000

Of the several flags that version 6.0 moves to the MMPFNENTRY from u4, the ancient InPageError is special for moving back and forth. It moved with the MMPFNENTRY when version 4.0 separated the flags from the PteFrame. It rejoined the PteFrame in u4 for version 5.1. Its move for version 6.0 is a coming home.