Geoff Chappell - Software Analyst
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); 0x00FFFFFF |
0x01FFFFFF`FFFFFFFF (late 5.2); 0x000FFFFF`FFFFFFFF (6.0 to 6.1); 0x0000000F`FFFFFFFF |
ULONG_PTR PteFrame : PFN_BITS; |
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 |
0x00000040`00000000 |
ULONG_PTR Unused1 : 1; |
6.3 and higher | |
0x00000080`00000000 |
ULONG_PTR Unused2 : 1; |
6.3 and higher | |
0x0003FF00`00000000 |
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); 0x00040000`00000000 |
ULONG_PTR FileOnly : 1; |
10.0 and higher | |
0x00400000`00000000 (6.2); 0x00200000`00000000 (6.3 to 1903); 0x00080000`00000000 |
ULONG_PTR PfnExists : 1; |
6.2 and higher | |
0x0FF00000`00000000 |
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 |
0x0C000000 |
ULONG_PTR ModifiedListBucketIndex : 2; |
2004 and higher | |
0x06000000 (6.2); 0x07000000 (6.3 to 1903); 0x70000000 |
0x01800000`00000000 (6.2); 0x01C00000`00000000 (6.3 to 1903); 0x70000000`00000000 |
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); 0x01000000`00000000 |
ULONG_PTR AweAllocation : 1; |
late 5.1 to 6.1 |
0x08000000 (6.0 to 1903); 0x80000000 |
0x02000000`00000000 (6.0 to 1903); 0x80000000`00000000 |
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.