HARDWARE_PTE

The HARDWARE_PTE structure, including its early variants HARDWARE_PTE_X86 and HARDWARE_PTE_X86PAE, is Microsoft’s representation of a Page Table Entry (PTE) as described in Intel’s manuals. In Intel’s terminology, this structure applies only when the PTE has a set P bit (masked by 0x01) to denote that the corresponding page of linear address space has physical memory.

Introduction for Windows 2000 of separate kernels that do and don’t use Physical Page Extension (PAE) brought separate definitions for the HARDWARE_PTE. These were at first given separate names, HARDWARE_PTE_X86 for the four-byte PTE when not using PAE and HARDWARE_PTE_X86PAE for the eight-byte PTE when using PAE. This separation of names was discontinued by the version 5.1 from Windows XP SP1.

Names and types in the following tables are from public symbol files for the kernel, starting with Windows 2000 SP3. That these names were in use for at least one earlier version is confirmed from the output of the !dso command as implemented by the USEREXTS debugger extension from the Device Driver Kit (DDK) for Windows NT 4.0.

32-Bit PTE

For the x86 builds that do not use Physical Address Extension, page table entries are four bytes. The whole HARDWARE_PTE is a structure of ULONG bit fields:

Mask Definition Versions Remarks
0x00000001
ULONG Valid : 1;
all Intel’s P;
must be set for processor to interpret any other bits
0x00000002
ULONG Write : 1;
all Intel’s R/W
0x00000004
ULONG Owner : 1;
all Intel’s U/S
0x00000008
ULONG WriteThrough : 1;
all Intel’s PWT
0x00000010
ULONG CacheDisable : 1;
all Intel’s PCD
0x00000020
ULONG Accessed : 1;
all Intel’s A
0x00000040
ULONG Dirty : 1;
all Intel’s D in PTE for 4KB page or 4MB page;
ignored in PDE
0x00000080
ULONG LargePage : 1;
all Intel’s PAT in PTE for 4KB page;
else Intel’s PS;
set in PTE for 4MB page;
clear in PDE
0x00000100
ULONG Global : 1;
all Intel’s G in PTE for 4KB page or 4MB page;
ignored in PDE
0x00000200
ULONG CopyOnWrite : 1;
all ignored by processor
0x00000400
ULONG Prototype : 1;
all ignored by processor
 
ULONG reserved : 1;
all ignored by processor
0xFFFFF000
ULONG PageFrameNumber : 20;
all  

The CopyOnWrite and Prototype bits are how Windows uses two of the three that Intel leaves as available. Note that Prototype is preserved in the various PTE interpretations that Microsoft applies when physical memory is not present.

64-Bit PTE

For 64-bit Windows but also for the x86 builds that use PAE, page table entries are eight bytes. The HARDWARE_PTE is a structure of ULONGLONG bit fields in 64-bit Windows. To the 32-bit PAE kernel, however, the HARDWARE_PTE is a union of two structures, one to define the bit fields, the other to provide for accessing bits together in 32-bit parts.

typedef union _HARDWARE_PTE {
    struct {
        /*  bit fields, see below  */
    };
    struct {
        ULONG LowPart;
        ULONG HighPart;
    };
} HARDWARE_PTE;

Bit Fields

The low 12 bits of the 64-bit PTE, whether for PAE and x64, match closely those of the 32-bit PTE:

Mask Definition Versions Remarks
0x00000000`00000001
ULONGLONG Valid : 1;
all Intel’s P;
must be set for processor to interpret any other bits
0x00000000`00000002
ULONGLONG Write : 1;
all Intel’s R/W;
reserved in PDPTE (PAE)
0x00000000`00000004
ULONGLONG Owner : 1;
all Intel’s U/S;
reserved in PDPTE (PAE)
0x00000000`00000008
ULONGLONG WriteThrough : 1;
all Intel’s PWT
0x00000000`00000010
ULONGLONG CacheDisable : 1;
all Intel’s PCD
0x00000000`00000020
ULONGLONG Accessed : 1;
all Intel’s A;
reserved in PDPTE (PAE)
0x00000000`00000040
ULONGLONG Dirty : 1;
all Intel’s D in PTE for 4KB page, 2MB page or 1GB page;
ignored in PDE;
reserved in PDPTE (PAE);
ignored in PDPTE (x64);
ignored in PML4E
0x00000000`00000080
ULONGLONG LargePage : 1;
all Intel’s PAT in PTE for 4KB page;
else Intel’s PS;
set in PTE for 2MB page or 1GB page;
clear in PDE;
reserved in PDPTE (PAE);
clear in PDPTE (x64);
reserved in PML4E
0x00000000`00000100
ULONGLONG Global : 1;
all Intel’s G in PTE for 4KB page, 2MB page or 1GB page;
ignored in PDE;
reserved in PDPTE (PAE);
ignored in PDPTE (x64);
reserved in PML4E
0x00000000`00000200
ULONGLONG CopyOnWrite : 1;
all ignored by processor
0x00000000`00000400
ULONGLONG Prototype : 1;
all ignored by processor
 
ULONGLONG reserved0 : 1;
all ignored by processor

The remaining bits differ significantly, not just from the 32-bit PTE but between the PAE and x64 implementations:

Mask (PAE) Definition Versions Remarks
0x0000000F`FFFFF000 (5.0);
0x0000003F`FFFFF000
ULONGLONG PageFrameNumber  : 24;
5.0  
ULONGLONG PageFrameNumber : 26;
5.1 and higher  
 
ULONGLONG reserved1 : 28;
5.0  
ULONGLONG reserved1 : 26;
5.1 to 1607  
ULONGLONG reserved1 : 25;
1703 and higher  
0x80000000`00000000
ULONGLONG NoExecute : 1;
1703 and higher Intel’s XD

In the first PAE kernels, the PageFrameNumber can describe 16M pages, as if for 36 address lines and 64GB of physical memory. Version 5.1 raises this to 64M pages, as if for 38 address lines. This would allow 256GB of physical memory, even though 32-bit Windows cannot possibly support so much. (It has a long-standing architectural limit of 128GB caused by needing kernel-mode address space for an array of MMPFN structures, one per page of physical memory. At 0x1C bytes per MMPFN, even 128GB of physical memory requires 896MB for the MMPFN array when at most 1GB can be available.)

Mask (x64) Definition Versions Remarks
0x000000FF`FFFFF000 (late 5.2 to 6.1);
0x0000FFFF`FFFFF000
ULONGLONG PageFrameNumber : 28;
late 5.2 to early 6.1  
ULONGLONG PageFrameNumber : 36;
late 6.1 and higher  
 
ULONGLONG reserved1 : 12;
late 5.2 to early 6.1  
ULONGLONG reserved1 : 4;
late 6.1 and higher  
0x7FF00000`00000000
ULONGLONG SoftwareWsIndex : 11;
all ignored by processor (see note)
0x80000000`00000000
ULONGLONG NoExecute : 1;
all Intel’s XD

The first 64-bit kernels provide for 256M pages, as if for 40 address lines and 1TB of physical memory. Raising this waited for the version 6.1 from Windows 7 SP1, whose widened PageFrameNumber allows 48 address lines and thus 256TB of physical memory. Note that the PageFrameNumber in the otherwise very close MMPTE_HARDWARE got this same widening in the version 6.0 from Windows Vista SP1. It is not known whether the lag in updating the HARDWARE_PTE had real-world consequence.

In the high dword, 64-bit Windows defines SoftwareWsIndex as using all 11 bits that Intel leaves as available if the processor is not using protection keys.

Note that for both the PAE and x64 kernels, the HARDWARE_PTE leaves unspecified that not all the bits of the PageFrameNumber are meaningful in a PTE for a large page. In a PTE for a 2MB page—or, if you prefer, a PDE for which LargePage is set—the lowest bit of the PageFrameNumber is Intel’s PAT and the next eight are reserved, i.e., must be zero. This applies also in 64-bit Windows to a PTE for a 1GB page, i.e., a PDPTE for which LargePage is set, except that nine more bits are reserved.