Geoff Chappell - Software Analyst
The MMSUPPORT_FLAGS structure (formally _MMSUPPORT_FLAGS) is a container for four bytes of flags in the MMSUPPORT structure, historically, but nowadays in the MMSUPPORT_INSTANCE. The MMSUPPORT is the Memory Manager’s highest-level modelling of a Working Set and the MMSUPPORT_FLAGS record simple properties of the corresponding Working Set’s state.
The MMSUPPORT_FLAGS are not formally documented. Neither is the structure known to have been declared in any header file that Microsoft has published to support Windows programming. The flags are not secret, however, just undocumented. Type information, which is for almost all purposes equivalent to a C/C++ definition, is available in public symbol files starting with Windows 2000 SP3.
It is here thought that the MMSUPPORT_FLAGS were introduced for version 5.0. Before this version, each process had an MMSUPPORT in its EPROCESS and the kernel had one more as an internal variable. The introduction of sessions for version 5.0 meant that an MMSUPPORT could also be in an MM_SESSION_SPACE. Easily distinguishing whether a given MMSUPPORT is for a process or a session would be useful and this is here thought to have motivated giving the MMSUPPORT some bit flags: it’s surely no accident that the first, named SessionSpace, provides exactly this distinction.
The MMSUPPORT_FLAGS structure is four bytes in all versions of 32-bit and 64-bit Windows that have it, but as implementation details of an implementation detail, the bit flags within the structure vary between Windows versions and even between builds. Moreover, it is not just that flags change position within the bit mask or that particular bits change interpretation. Different versions construct the bits differently—and not just with such simple variation as UINT bit fields in one version but UCHAR bit fields in another.
The original architecture was straightforward. Symbol files for Windows 2000 SP3 show an MMSUPPORT member named u which is an unnamed union of an MMSUPPORT_FLAGS named Flags and a ULONG named LongFlags. The MMSUPPORT_FLAGS were then a simple structure of UINT bit fields:
struct _MMSUPPORT_FLAGS { /* UINT bit fields */ };
Version 5.2 unpicked the union, making Flags directly an MMSUPPORT member, but it remade the MMSUPPORT_FLAGS structure into a mixure of UCHAR and USHORT bit fields:
struct _MMSUPPORT_FLAGS { /* 16 bits of UCHAR bit fields */ /* 16 bits of USHORT bit fields */ };
By version 6.0, the structure has only UCHAR bit fields:
struct _MMSUPPORT_FLAGS { /* UCHAR bit fields */ };
Among the UCHAR bit fields, however, is an 8-bit field aligned to a whole byte. Version 6.3 formalised that this field is the whole of its byte:
struct _MMSUPPORT_FLAGS { /* 16 bits of UCHAR bit fields */ /* one whole UCHAR */ /* 8 bits of UCHAR bit fields */ };
The 1607 release of version 10.0 keeps to this but organises the bit fields into unions. The bit fields in the first two bytes are in union with a USHORT named u1; those in the last byte are in union with a UCHAR named u2:
struct _MMSUPPORT_FLAGS { union { struct { /* 16 bits of UCHAR bit fields */ }; USHORT u1; }; UCHAR MemoryPriority; union { struct { /* 7 or 8 bits of UCHAR bit fields */ }; UCHAR u2; }; };
The table below aims to extract the masks (as must be known when interpreting the flags while debugging) from the dressing (as must be known to Microsoft’s programmers when reading or writing the code):
Offset / Mask | Definition | Versions | Remarks |
---|---|---|---|
0x00000001 (5.0 to 5.1); 0x00 / 0x01 (5.2 to 6.0) |
UINT SessionSpace : 1; |
5.0 to 5.1 | |
UCHAR SessionSpace : 1; |
5.2 to 6.0 | ||
0x00000002 (5.0 to 5.1); 0x00 / 0x02 (5.2) |
UINT BeingTrimmed : 1; |
5.0 to 5.1 | |
UCHAR BeingTrimmed : 1; |
5.2 only | ||
0x00000004 (5.0) |
UINT ProcessInSession : 1; |
5.0 only | |
0x00000008 (5.0); 0x00000004 (5.1); 0x00 / 0x04 (5.2) |
UINT SessionLeader : 1; |
5.0 to 5.1 | |
UCHAR SessionLeader : 1; |
5.2 only | ||
0x00 / 0x07 |
UCHAR WorkingSetType : 3; |
6.1 and higher | |
0x00 / 0x02 (6.0); 0x00 / 0x08 (6.1) |
UCHAR ModwriterAttached : 1; |
6.0 to 6.1 | |
0x00000010 (5.0); 0x00000008 (5.1); 0x00 / 0x08 (5.2); 0x00 / 0x04 (6.0); 0x00 / 0x10 (6.1) |
UINT TrimHard : 1; |
5.0 to 5.1 | |
UCHAR TrimHard : 1; |
5.2 to 6.1 | ||
0x00000020 (5.0); 0x00000010 (5.1) |
UINT WorkingSetHard : 1; |
5.0 to 5.1 | |
0x00000040 (5.0) |
UINT WriteWatch : 1; |
5.0 only | |
0x00000020 (5.1) |
UINT AddressSpaceBeingDeleted : 1; |
5.1 only | previously BOOLEAN in MMSUPPORT |
0x00 / 0x38 |
UCHAR ForceCredits : 3; |
6.2 to 10.0 | |
UCHAR Reserved0 : 3; |
1511 and higher | ||
0x00 / 0x10 (5.2); 0x00 / 0x08 (6.0); 0x00 / 0x20 (6.1); 0x00 / 0x40 |
UCHAR MaximumWorkingSetHard : 1; |
5.2 and higher | |
0x00 / 0x20 (5.2); 0x00 / 0x10 (6.0); 0x00 / 0x40 (6.1) |
UCHAR ForceTrim : 1; |
5.2 to 6.1 | |
0x00 / 0x40 (5.2); 0x00 / 0x20 (6.0); 0x00 / 0x80 |
UCHAR MinimumWorkingSetHard : 1; |
5.2 and higher | |
0x00 / 0x40 (6.0) 0x01 / 0x01 |
UCHAR SessionMaster : 1; |
6.0 and higher | |
0x00 / 0x80 (6.0) |
UCHAR TrimmerAttached : 1; |
6.0 only | |
0x01 / 0x01 (6.0) |
UCHAR TrimmerDetaching : 1; |
6.0 only | |
0x01 / 0x06 |
UCHAR TrimmerState : 2; |
6.1 and higher | |
0xFFFFFF80 (5.0); 0x0000FFC0 (5.1); 0x00 / 0x80 (5.2); 0x01 / 0xFE (early 6.0); 0x01 / 0x0E (late 6.0); 0x01 / 0x08 |
UINT Filler : 25; |
5.0 only | last member in 5.0 |
UINT Available : 10; |
5.1 only | ||
UCHAR Available0 : 1; |
5.2 only | ||
UCHAR Reserved : 7; |
early 6.0 | ||
UCHAR Reserved : 3; |
late 6.0 | ||
UCHAR Reserved : 1; |
6.1 and higher | ||
0x01 / 0xF0 |
UCHAR PageStealers : 4; |
late 6.0 and higher | |
0x00FF0000 (5.1) |
UINT AllowWorkingSetAdjustment : 8; |
5.1 only | previously UCHAR in MMSUPPORT |
0xFF000000 (5.1); 0x01 / 0xFF (5.2); 0x02 / 0xFF |
UINT MemoryPriority : 8; |
5.1 only | previously UCHAR in MMSUPPORT;
last member in 5.1 |
UCHAR MemoryPriority : 8; |
5.2 to 6.2 | ||
UCHAR MemoryPriority; |
6.3 and higher | ||
0x02 / 0x0001 (5.2) |
USHORT GrowWsleHash : 1; |
5.2 only | |
0x02 / 0x0002 (5.2) |
USHORT AcquiredUnsafe : 1; |
5.2 only | |
0x03 / 0x01 |
UCHAR WsleDeleted : 1; |
6.0 and higher | |
0x03 / 0x02 (6.0 to 1607) |
UCHAR VmExiting : 1; |
6.0 to 1607 | |
0x03 / 0x04 (late 6.0 to 1607) |
UCHAR ExpansionFailed : 1; |
late 6.0 to 1607 | |
0x03 / 0x08 (6.3 to 1607); 0x03 / 0x02 |
UCHAR SvmEnabled : 1; |
6.3 and higher | |
0x02 / 0xFFFC (5.2); 0x03 / 0xFC (early 6.0); 0x03 / 0xF8 (late 6.0 to 6.2); 0x03 / 0xF0 (6.3) |
USHORT Available : 14; |
5.2 only | last member in 5.2 |
UCHAR Available : 6; |
early 6.0 | last member in early 6.0 | |
UCHAR Available : 5; |
late 6.0 to 6.2 | last member in late 6.0 to 6.2 | |
UCHAR Available : 4; |
6.3 only | last member in 6.3 | |
0x03 / 0x10 (6.3 to 1607); 0x03 / 0x04 |
UCHAR ForceAge : 1; |
10.0 and higher | |
0x03 / 0x08 |
UCHAR ForceTrim : 1; |
1703 and higher | |
0x03 / 0x10 (1703) |
UCHAR UnlockInProgress : 1; |
1703 only | |
0x03 / 0x20 (10.0 to 1703); 0x03 / 0x10 |
UCHAR NewMaximum : 1; |
10.0 and higher | |
0x03 / 0xC0 (10.0 to 1703); 0x03 / 0x60 |
UCHAR CommitReleaseState : 2; |
10.0 and higher | last member in 10.0 and higher |
See that discontinuing UnlockInProgress for the 1709 release of Windows 10, and consequently shifting two higher-placed fields, leaves the structure’s highest bit not just reserved or available but undefined.
The 3-bit WorkingSetType that was introduced for version 6.1 takes its values from the WORKING_SET_TYPE enumeration. The original five types distinguish the containing MMSUPPORT as a working set for a process or for a session or for one of three special cases that the kernel keeps internally. With the addition of three internal types for the 1803 release of Windows 10, the 3-bit mask is fully used.