MMSUPPORT_FLAGS

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.

Documentation Status

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.

History

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.

Layout

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.