MMSUPPORT
Though it’s hardly clear from its name, the MMSUPPORT structure (formally _MMSUPPORT) is the Memory Manager’s highest-level implementation of a Working Set. It may best be thought of as an organising container. The main work is implemented in the MMWSL (Working Set List) structure and its potentially large array of MMWSLE (Working Set List Entry) structures.
Working sets come in five types. An MMSUPPORT for a process working set is embedded in each EPROCESS as the Vm member. A session working set is represented by an MMSUPPORT structure in the session’s MM_SESSION_SPACE (again as a member named Vm). Three system-wide working sets have MMSUPPORT structures in the kernel’s data section, as the internal variables that symbol files for the kernel used to name MmSystemCacheWs, MmPagedPoolWs and MmSystemPtesWs.
The 1607 release of Windows 10 discontinues the MMSUPPORT structure with exactly this name. The structure survives but is named MMSUPPORT_FULL and combines new MMSUPPORT_INSTANCE and MMSUPPORT_SHARED structures which each have a different selection of the old MMSUPPORT members.
Variability
As an internal structure with little, if any, visibility outside the kernel, the MMSUPPORT varies greatly between versions and even between builds. In the following table of sizes, different builds of the same version are distinguished as early and late because they are known to vary the structure even if they don’t change the size. These descriptions, as early and late, are then used throughout the article as a shorthand.
Version | Size (x86) | Size (x64) |
---|---|---|
3.10 to 4.0 | 0x30 | |
5.0 | 0x48 | |
5.1 | 0x40 | |
early 5.2 (before SP1) | 0x60 | |
late 5.2 (SP1 and higher) | 0x48 | 0x58 |
early 6.0 (before SP1) late 6.0 (SP1 and higher) |
0x48 | 0x68 |
6.1 | 0x6C | 0x88 |
6.2 | 0x70 | 0x90 |
6.3 | 0x70 | 0xD8 |
10.0 to 1511 | 0x80 | 0xF8 |
Layout
These sizes, and the names, offsets and types in the tables that follow, are from Microsoft’s symbol files for the kernel starting with Windows 2000 SP3.
Windows 7 and Higher
The MMSUPPORT varies enough between versions that it seems simpler to present its current form and then a separate history. Windows 7 is here taken as a convenient break. Much of the structure was reordered for Windows 7, both on a large scale and small. For instance, the first three members were at the very end of the structure when version 6.0 introduced them, but version 6.1 doesn’t move them as one block: it also swaps two of them. On the plus side for presentation, although there have since been insertions, deletions and changes of type (notably because support in 64-bit Windows 8.1 for more than 4G pages requires the widening of many members from 32 bits), those reorderings for Windows 7 were the last until the structure was split.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 | 0x00 |
EX_PUSH_LOCK WorkingSetMutex; |
6.1 to 6.3 | previously 0x40 and 0x58 |
LONG volatile WorkingSetLock; |
10.0 to 1511 | next at 0x00 in MMSUPPORT_SHARED | ||
0x04 | 0x08 |
KGATE *ExitGate; |
6.1 to 6.3 | previously 0x3C and 0x50 |
KGATE *ExitOutswapGate; |
10.0 to 1511 | next at 0x34 and 0x60 in MMSUPPORT_INSTANCE | ||
0x08 | 0x10 |
PVOID AccessLog; |
6.1 to 1511 | previously 0x44 and 0x60; next at 0x14 and 0x28 in MMSUPPORT_SHARED |
0x0C | 0x18 |
LIST_ENTRY WorkingSetExpansionLinks; |
6.1 to 1511 | previously 0x00; next at 0x10 and 0x18 in MMSUPPORT_INSTANCE |
0x14 | 0x28 |
ULONG AgeDistribution [7]; |
6.1 to 6.2 | |
ULONG_PTR AgeDistribution [7]; |
6.3 to 1511 | next at 0x18 and 0x28 in MMSUPPORT_INSTANCE | ||
0x30 | 0x44 (6.1 to 6.2); 0x60 |
ULONG MinimumWorkingSetSize; |
6.1 to 6.2 | previously 0x1C and 0x24 |
ULONG_PTR MinimumWorkingSetSize; |
6.3 to 1511 | next at 0x38 and 0x68 in MMSUPPORT_INSTANCE | ||
0x34 | 0x68 |
ULONG_PTR WorkingSetLeafSize; |
10.0 to 1511 | next at 0x3C and 0x70 in MMSUPPORT_INSTANCE |
0x38 | 0x70 |
ULONG_PTR WorkingSetLeafPrivateSize; |
10.0 to 1511 | next at 0x40 and 0x78 in MMSUPPORT_INSTANCE |
0x34 (6.1 to 6.3); 0x3C |
0x48 (6.1 to 6.2); 0x68 (6.3); 0x78 |
ULONG WorkingSetSize; |
6.1 to 6.2 | previously 0x38 and 0x48 |
ULONG_PTR WorkingSetSize; |
6.3 to 1511 | next at 0x44 and 0x80 in MMSUPPORT_INSTANCE | ||
0x38 (6.1 to 6.3); 0x40 |
0x4C (6.1 to 6.2); 0x70 (6.3); 0x80 |
ULONG WorkingSetPrivateSize; |
6.1 to 6.2 | previously 0x30 and 0x40 |
ULONG_PTR WorkingSetPrivateSize; |
6.3 to 1511 | next at 0x48 and 0x88 in MMSUPPORT_INSTANCE | ||
0x3C (6.1 to 6.3); 0x44 |
0x50 (6.1 to 6.2); 0x78 (6.3); 0x88 |
ULONG MaximumWorkingSetSize; |
6.1 to 6.2 | previously 0x20 and 0x28 |
ULONG_PTR MaximumWorkingSetSize; |
6.3 to 1511 | next at 0x4C and 0x90 in MMSUPPORT_INSTANCE | ||
0x40 (6.1 to 6.3); 0x48 |
0x54 (6.1 to 6.2); 0x80 (6.3); 0x90 |
ULONG ChargedWslePages; |
6.1 to 6.2 | previously 0x18 and 0x20 |
ULONG_PTR ChargedWslePages; |
6.3 to 1511 | next at 0x18 and 0x30 in MMSUPPORT_SHARED | ||
0x44 (6.1 to 6.3); 0x4C |
0x58 (6.1 to 6.2); 0x88 (6.3); 0x98 |
ULONG ActualWslePages; |
6.1 to 6.2 | previously 0x2C and 0x3C |
ULONG_PTR ActualWslePages; |
6.3 to 1511 | next at 0x1C and 0x38 in MMSUPPORT_SHARED | ||
0x48 (6.1 to 6.3); 0x50 |
0x5C (6.1 to 6.2); 0x90 (6.3); 0xA0 |
ULONG WorkingSetSizeOverhead; |
6.1 to 6.2 | previously 0x34 and 0x44 |
ULONG_PTR WorkingSetSizeOverhead; |
6.3 to 1511 | next at 0x20 and 0x40 in MMSUPPORT_SHARED | ||
0x4C (6.1 to 6.3); 0x54 |
0x60 (6.1 to 6.2); 0x98 (6.3); 0xA8 |
ULONG PeakWorkingSetSize; |
6.1 to 6.2 | previously 0x14 and 0x1C |
ULONG_PTR PeakWorkingSetSize; |
6.3 to 1511 | next at 0x50 and 0x98 in MMSUPPORT_INSTANCE | ||
0x50 (6.1 to 6.3); 0x58 |
0x64 (6.1 to 6.2); 0xA0 (6.3); 0xB0 |
ULONG HardFaultCount; |
6.1 to 1511 | next at 0x54 and 0xA0 in MMSUPPORT_INSTANCE |
0xB4 |
USHORT PartitionId; |
10.0 to 1511 | next at 0xA4 in MMSUPPORT_INSTANCE | |
0xB6 |
USHORT Pad0; |
10.0 to 1511 | next at 0xA6 in MMSUPPORT_INSTANCE | |
0x54 (6.1 to 6.3); 0x5C |
0x68 (6.1 to 6.2); 0xA8 (6.3); 0xB8 |
MMWSL *VmWorkingSetList; |
6.1 to 1511 | previously 0x24 and 0x30; next at 0x0C and 0x10 in MMSUPPORT_INSTANCE |
0x58 (6.1 to 6.3); 0x60 |
0x70 (6.1 to 6.2); 0xB0 (6.3); 0xC0 |
USHORT NextPageColor; |
6.1 to 1511 | previously 0x0A and 0x12; next at 0x00 in MMSUPPORT_INSTANCE |
0x5A (6.1 to 6.3); 0x62 |
0x72 (6.1 to 6.2); 0xB2 (6.3); 0xC2 |
USHORT LastTrimStamp; |
6.1 to 1511 | previously 0x08 and 0x10; next at 0x02 in MMSUPPORT_INSTANCE |
0x5C (6.1 to 6.3); 0x64 |
0x74 (6.1 to 6.2); 0xB4 (6.3); 0xC4 |
ULONG PageFaultCount; |
6.1 to 1511 | previously 0x10 and 0x18; next at 0x04 in MMSUPPORT_INSTANCE |
0x60 (6.1) | 0x78 (6.1) |
ULONG RepurposeCount; |
6.1 only | |
0x60 (6.2 to 6.3); 0x68 |
0x78 (6.2); 0xB8 (6.3); 0xC8 |
ULONG TrimmedPageCount; |
6.2 only | |
ULONG_PTR TrimmedPageCount; |
6.3 to 1511 | next at 0x08 in MMSUPPORT_INSTANCE | ||
0x64 (6.1) | 0x7C (6.1 to 6.2) |
ULONG Spare [1]; |
6.1 only (x86) | |
ULONG Spare [2]; |
6.1 only (x64) | |||
ULONG Spare; |
6.2 only (x64) | |||
0x64 (6.2 to 6.3); 0x6C |
0x80 (6.2); 0xC0 (6.3); 0xD0 |
ULONG ForceTrimPages; |
6.2 only | |
ULONG_PTR ForceTrimPages; |
6.3 to 1511 | |||
0x68 (6.1 to 6.3); 0x70 |
0x84 (6.1 to 6.2); 0xC8 (6.3); 0xD8 |
MMSUPPORT_FLAGS Flags; |
6.1 to 1511 | previously 0x0C and 0x14; next at 0x60 and 0xB8 in MMSUPPORT_INSTANCE; last member in 6.1 |
0x74 | 0xE0 |
ULONG_PTR ReleasedCommitDebt; |
10.0 to 1511 | next at 0x04 and 0x08 in MMSUPPORT_SHARED |
0x6C (6.2 to 6.3); 0x78 |
0x88 (6.2); 0xD0 (6.3); 0xE8 |
PVOID WsSwapSupport; |
6.2 to 1511 | next at 0x0C and 0x18 in MMSUPPORT_SHARED;
last member in 6.2 and 6.3 |
0x7C | 0xF0 |
PVOID CommitReAcquireFailSupport; |
10.0 to 1511 | last member in 10.0 and 1511 |
Original
Very many of the members have an earlier history, often all the way back to version 3.10, but with such extensive reordering for version 6.1 that separate presentation is all but necessary. Versions 5.1 and 5.2 reorder MMSUPPORT members too, so that the following table necessarily lists some members twice.
For versions that predate the availability of type information in public symbol files, what’s known of Microsoft’s names and types is something of a guess. Where use of a member corresponds closely with that of a version for which Microsoft’s symbols are available, it seems reasonable to suppose continuity. Some use, however, has no correspondence, the code having changed too much. Even where the use hasn’t changed, tracking it down exhaustively would be difficult, if not impossible, even with source code.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 (5.2 to 6.0) |
0x00 (5.2 to 6.0) |
LIST_ENTRY WorkingSetExpansionLinks; |
5.2 to 6.0 | previously 0x24 |
0x00 (3.10 to 5.1); 0x08 (5.2) |
0x10 (5.2) |
LARGE_INTEGER LastTrimTime; |
3.10 to 5.2 | |
0x08 (3.10 to 5.0) |
ULONG LastTrimFaultCount; |
3.10 to 5.0 | ||
0x08 (6.0) | 0x10 (6.0) |
USHORT LastTrimStamp; |
6.0 | next at 0x5A and 0x72 |
0x0A (6.0) | 0x12 (6.0) |
USHORT NextPageColor; |
6.0 | next at 0x58 and 0x70 |
0x08 (5.1); 0x10 (5.2); 0x0C (6.0) |
0x18 (5.2); 0x14 (6.0) |
MMSUPPORT_FLAGS Flags; |
5.1 to 6.0 | previously 0x30; next at 0x68 and 0x84 |
0x0C (3.10 to 5.1); 0x14 (5.2); 0x10 (6.0) |
0x1C (5.2); 0x18 (6.0) |
ULONG PageFaultCount; |
3.10 to 6.0 | next at 0x5C and 0x74 |
0x10 (3.10 to 5.1); 0x18 (5.2); 0x14 (6.0) |
0x20 (5.2); 0x1C (6.0) |
ULONG PeakWorkingSetSize; |
3.10 to 6.0 | next at 0x4C and 0x60 |
0x14 (3.10 to 5.1) |
ULONG WorkingSetSize; |
3.10 to 5.1 | next at 0x3C | |
0x1C (5.2) | 0x24 (5.2) |
ULONG GrowthSinceLastEstimate; |
5.2 only | previously 0x3C |
0x18 (6.0) | 0x20 (6.0) |
ULONG Spare0; |
early 6.0 | |
ULONG ChargedWslePages; |
late 6.0 | next at 0x40 and 0x54 | ||
0x18 (3.10 to 5.1); 0x20 (5.2); 0x1C (6.0) |
0x28 (5.2); 0x24 (6.0) |
ULONG MinimumWorkingSetSize; |
3.10 only | |
USHORT MinimumWorkingSetSize; |
3.50 only | |||
ULONG MinimumWorkingSetSize; |
3.51 to 6.0 | next at 0x30 and 0x44 | ||
0x1C (3.10); 0x1A (3.50); 0x1C (3.51 to 5.1); 0x24 (5.2); 0x20 (6.0) |
0x2C (5.2); 0x28 (6.0) |
ULONG MaximumWorkingSetSize; |
3.10 only | |
USHORT MaximumWorkingSetSize; |
3.50 only | |||
ULONG MaximumWorkingSetSize; |
3.51 to 6.0 | next at 0x3C and 0x50 |
For the several members whose names tell of a size, the size is a count of pages. All are 32-bit counts, except that version 3.50 reduces the MinimumWorkingSetSize and MaximumWorkingSetSize to allow only 16 bits (but still counting pages). The reason is not known. The immediately adjacent change is the squeezing in of the VmWorkingSetList (next). This has the the merit of making no other rearrangement, but since the structure had otherwise unused alignment space at offset 0x2C, the new member could have been added without any rearrangement at all. More archaeology is required!
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x1C (3.50); 0x20 (3.51 to 5.1); 0x28 (5.2); 0x24 (6.0) |
0x30 (5.2 to 6.0) |
MMWSL *VmWorkingSetList; |
3.50 to 6.0 | next at 0x54 and 0x68 |
0x20 (3.10 to 3.50); 0x24 (3.51 to 5.1) |
LIST_ENTRY WorkingSetExpansionLinks; |
3.10 to 5.1 | next at 0x00 | |
0x28 (3.10 to 3.50); 0x2C (3.51 to 5.0) |
UCHAR AllowWorkingSetAdjustment; |
3.10 to 5.0 | next in Flags | |
0x29 (3.10 to 3.50); 0x2D (3.51 to 5.0) |
BOOLEAN AddressSpaceBeingDeleted; |
3.10 to 5.0 | next in Flags | |
0x2A (3.10 to 3.50); 0x2E (3.51 to 5.0) |
UCHAR ForegroundSwitchCount; |
3.10 to 5.0 | last member in 3.10 | |
0x2B (3.50); 0x2F (3.51 to 5.0) |
UCHAR MemoryPriority; |
3.50 to 5.0 | next in Flags; last member in 3.50 to 4.0 |
|
0x30 (5.0) |
union { ULONG LongFlags; MMSUPPORT_FLAGS Flags; } u; |
5.0 only | next at 0x08 and 0x18 | |
0x34 (5.0); 0x2C (5.1 to 5.2); 0x28 (6.0) |
0x38 (5.2 to 6.0) |
ULONG Claim; |
5.0 to 6.0 | |
0x2C (6.0) | 0x3C (6.0) |
ULONG Spare [1]; |
early 6.0 | |
ULONG ActualWslePages; |
late 6.0 | next at 0x44 and 0x58 | ||
0x38 (5.0); 0x30 (5.1 to 5.2) |
0x3C (5.2) |
ULONG NextEstimationSlot; |
5.0 to 5.2 | |
0x3C (5.0); 0x34 (5.1 to 5.2) |
0x40 (5.2) |
ULONG NextAgingSlot; |
5.0 to 5.2 | |
0x40 (5.0); 0x38 (5.1 to 5.2) |
0x44 (5.2) |
ULONG EstimatedAvailable; |
5.0 to 5.2 | |
0x44 (5.0); 0x3C (5.1) |
ULONG GrowthSinceLastEstimate; |
5.0 to 5.1 | next at 0x1C; last member in 5.0 and 5.1 |
|
0x30 (6.0) | 0x40 (6.0) |
ULONG WorkingSetPrivateSize; |
6.0 only | next at 0x38 and 0x4C |
0x34 (6.0) | 0x44 (6.0) |
ULONG WorkingSetSizeOverhead; |
6.0 only | next at 0x48 and 0x5C |
0x3C (5.2); 0x38 (6.0) |
0x48 (5.2 to 6.0) |
ULONG WorkingSetSize; |
5.2 to 6.0 | previously 0x14; next at 0x34 and 0x48 |
0x3C (6.0) | 0x50 (6.0) |
KEVENT *ExitEvent; |
early 6.0 | |
KGATE *ExitGate; |
late 6.0 | next at 0x04 and 0x08 | ||
0x40 (5.2 to 6.0) |
KGUARDED_MUTEX WorkingSetMutex; |
early 5.2 | last member in early 5.2 | |
0x50 (5.2); 0x58 (6.0) |
EX_PUSH_LOCK WorkingSetMutex; |
late 5.2 to 6.0 | next at 0x00; last member in late 5.2 |
|
0x44 (6.0) | 0x60 (6.0) |
PVOID AccessLog; |
6.0 only | next at 0x08 and 0x10; last member in 6.0 |