MMPFN Union 4

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.

That space is tight in the MMPFN is demonstrated well by the very last of its fields. Its location within the MMPFN is the same in all versions:

MMPFN Offset (x86) MMPFN Offset (PAE) MMPFN Offset (x64)
0x14 0x18 0x28

Also in all versions, the largest part of this last field is the PteFrame. This is the Page Frame Number (PFN) of what the !pfn command names the “containing page”. For the physical page that is described by an MMPFN to be addressable, the page’s physical address must be discoverable from at least one Page Table Entry (PTE) in some page table. This page table is also a physical page. One such page is distinguished as the containing page. Its PFN is the contained page’s PteFrame.

For the earliest versions, the PFN is only 20 bits which leaves 12 for other use. Space was tight already, and all 12 other bits were put to use. Versions 3.10 to 3.51 hold the PteFrame in something like the form of a PTE, i.e., with the PFN in the high 20 bits and bit flags in the low 12, all presumed here to have been packaged as an early form of what public symbol files later present as an MMPFNENTRY structure. When version 4.0 recovered space by narrowing a 32-bit ReferenceCount at offset 0x0C to 16 bits, the flags were moved to this new space and the PteFrame was left alone as the whole of its dword.

Still, this left 12 unused bits at offset 0x14. Pressure on space soon found use for them. When version 5.1 squeezed in two new bit fields, now as high bits, opportunity was taken to package the lot with the PteFrame and new (and future) bit fields in a union with an integral EntireFrame. See that the bit flags have nothing to do with any frame of any containing page: the frame in the name is just historical. Version 6.0 did away with it, so that u4 holds just the bit flags in an unnamed structure in the unnamed union. Version 6.2 restores access to the whole as an integral type but now with the arguably better name EntireField.

Definition Versions
ULONG_PTR EntireFrame;
5.1 to 5.2
struct {
    /*  changing bit fields, see below  */
5.1 and higher
ULONG_PTR EntireField;
6.2 and higher

While 32-bit and 64-bit Windows need deal only with 36-bit and 48-bit physical addresses, the PFN of a physical page does not need the whole ULONG or ULONGLONG that Microsoft defines for the PFN_NUMBER. Wherever a physical page number is kept in anything that’s similar to a PTE, there are always the low 12 bits for flags. What’s left for a PFN is at most 20 or 52 bits in a 4-byte or 8-byte PTE, respectively. In 64-bit Windows, and in 32-bit Windows with PAE, the paging algorithm does not (yet) support a 52-bit physical address space. Instead, a PFN can be at most 20 bits for 32-bit Windows without PAE, 24 bits for 32-bit Windows with PAE and 36 bits for 64-bit Windows. This leaves many bits for use in any container of a PFN. Finding such use in the MMPFN member that holds the particular PFN that’s named PteFrame is the reason that the u4 exists. The original name, PteFrame, survives just as the first of the chaning bit fields in u4. Its width took some time to settle:

Version PteFrame Bit Width
x86 x64
5.1 to early 5.2 26  
late 5.2 25 57
6.0 to 6.1 25 52
6.2 25 36
6.3 and higher 24 36

See that the progressive reduction in what to allow has been more about the need for creating space somewhere in the MMPFN (both here and in u1 and especially in u2) than about codifying the width that’s implied by 36-bit and 48-bit physical address spaces. The effective width of a PFN in u4 is represented below as PFN_BITS.

Mask (x86) Mask (x64) Definition Versions
0x03FFFFFF (5.1 to early 5.2);
0x01FFFFFF (late 5.2 to 6.2);
0x01FFFFFF`FFFFFFFF (late 5.2);
0x000FFFFF`FFFFFFFF (6.0 to 6.1);
5.1 and higher
  0x00000030`00000000 (6.2 to 1903)
ULONG_PTR Channel : 2;
6.2 to 1903
0x03000000 0x00000030`00000000
ULONG_PTR LargePageSize : 2;
2004 and higher
ULONG_PTR Unused1 : 1;
6.3 and higher
ULONG_PTR Unused2 : 1;
6.3 and higher
ULONG_PTR Partition : 10;
10.0 and higher
  0x00700000`00000000 (6.0 to 6.1);
0x003FFFC0`00000000 (6.2);
0x001FFF00`00000000 (6.3);
0x000C0000`00000000 (10.0 to 1903)
ULONG_PTR Unused : 3;
6.0 to 6.1
ULONG_PTR Unused : 16;
6.2 only
ULONG_PTR Unused3 : 13;
6.3 only
ULONG_PTR Spare : 2;
10.0 to 1903
  0x00100000`00000000 (10.0 to 1903);
ULONG_PTR FileOnly : 1;
10.0 and higher
  0x00400000`00000000 (6.2);
0x00200000`00000000 (6.3 to 1903);
ULONG_PTR PfnExists : 1;
6.2 and higher
ULONG Spare : 8;
2004 and higher
0x02000000 (6.0 to 6.1) 0x00800000`00000000 (6.0 to 6.1)
ULONG_PTR PfnImageVerified : 1;
6.0 to 6.1
ULONG_PTR ModifiedListBucketIndex : 2;
2004 and higher
0x06000000 (6.2);
0x07000000 (6.3 to 1903);
0x01800000`00000000 (6.2);
0x01C00000`00000000 (6.3 to 1903);
ULONG_PTR PageIdentity : 2;
6.2 only
ULONG_PTR PageIdentity : 3;
6.3 and higher
0x04000000 (5.1 to early 5.2);
0x02000000 (late 5.2)
0x02000000`00000000 (late 5.2)
ULONG_PTR InPageError : 1;
5.1 to 5.2
0x08000000 (5.1 to early 5.2);
0x04000000 (late 5.2)
0x04000000`00000000 (late 5.2)
ULONG_PTR VerifierAllocation : 1;
5.1 to 5.2
0x10000000 (late 5.1 to early 5.2);
0x08000000 (late 5.2);
0x04000000 (6.0 to 6.1)
0x08000000`00000000 (late 5.2);
ULONG_PTR AweAllocation : 1;
late 5.1 to 6.1
0x08000000 (6.0 to 1903);
0x02000000`00000000 (6.0 to 1903);
ULONG_PTR PrototypePte : 1;
6.0 and higher
0x20000000 (late 5.1 to early 5.2)  
ULONG LockCharged : 1;
late 5.1 to early 5.2
0x40000000 (late 5.1 to early 5.2)  
ULONG KernelStack : 1;
late 5.1 to early 5.2
0x70000000 (late 5.2) 0x70000000`00000000 (late 5.2)
ULONG_PTR Priority : 3;
late 5.2 only
0x80000000 (5.2) 0x80000000`00000000 (late 5.2)
ULONG_PTR MustBeCached : 1;
5.2 only
0xF0000000 (6.0 to 1903) 0xFC000000`00000000 (6.0 to 1903)
ULONG_PTR PageColor : 4;
6.0 to 1903 (x86)
ULONG_PTR PageColor : 6;
6.0 to 1903
0xF0000000 (early 5.1);
0x80000000 (late 5.1)
ULONG Reserved : 4;
early 5.1 only
ULONG Reserved : 1;
late 5.1 only

Several of the bit fields move between this union and the MMPFNENTRY structure:

The ModifiedListBucketIndex is new to this union in the 32-bit Windows 10 Version 2004 but the 64-bit build has it as 4 bits at offset 0x27 in the MMPFN.