I am exploring the usage of MONITOR
instruction (or the equivalent intrinsic, _mm_monitor
). Although I found literature describing them, I could not find any concrete examples/samples on how to use it.
Can anyone share an example of how this instruction/intrinsic would be used in a driver? Essentially, I would like to use it to watch memory ranges.
The
monitor
instruction arms the address monitoring hardware using the address specified inRAX/EAX/AX
.Quote from IntelThe state of the monitor is used by the instruction
mwait
.The effective address size used (16, 32 or 64-bit) depends on the effective address size of the encoded instruction (i.e. it can be overridden with the
67h
prefix and by default it is the same as the code size).The address given in
rax/eax/ax
is the offset part of the logical address from which the linear address used to arm the monitor is computed.The segment part is
ds
by default, segment override prefixes can be applied to change segment.Being a linear address used for the monitor, paging doesn't affect the monitoring.
The availability of the
monitor
(andmwait
) instruction is indicated by the bit CPUID.01H:ECX.MONITOR[bit 3]1.It is a privileged instruction but Intel claims:
The suggested method to detect such condition is to try to execute
monitor
and handle the eventual #UD exception (in the custom way to OS reports it to a userland program).The address range monitored must be write-back cacheable.
Due to the involvement with the cache and cache coherence subsystems the size of the address range is given in term of the minimal and maximal sizes.
CPUID.01H:EAX[bit 15:0] gives the minimal range size. This is the length of the region monitored by the hardware monitor.
However, cache coherence traffic may work with "chunks" (lines) of bigger size and a write adjacent to the monitored region would trigger it nonetheless if the latter is included in the former.
This gives rise to the maximum range size, it can be found in CPUID.01H:EBX[bit 15:0].
To properly use
monitor
make sure that the data structure monitored fits the minimal range size but also make sure that no agents write in the addresses next to it up to the maximal range size.For example, if the minimal range size is 8 bytes and the maximal size is 16 bytes, make sure that the structure watched fits 8 bytes but pad it with eight more bytes to reach a total of sixteen so that no write from the 8-th to the 16-th byte occurs.
In a single cluster system, the two values above are equal. Mine are both 64 bytes.
The BIOS is responsible for reporting the cache coherence line size in
IA32_MONITOR_FILTER_LINE_SIZE
in multi-clustered systems.For the purpose of instruction ordering and access right,
monitor
is a load.monitor
allows the programmer to specify hints and extensions.Extensions are specified in
ecx
while hints are inedx
.Unsupported extensions raise a #GP exception, unsupported hints are ignored.
I'm not aware of any extension or hint for
monitor
, the Intel manual reportsI believe that line is true in general, it just has an outdated processor model in it.
Further, the pseudo code for
monitor
report a #GPIf ECX ≠ 0.
Arming the monitor without checking its state afterwards (with
mwait
) doesn't cause any harm.The intrinsic is
void _mm_monitor(void const *p, unsigned extensions,unsigned hints)
.Once the monitor is armed, it can be trigger by different conditions:
The state of the monitor is not visible to the programmer but it can be tested with
mwait
.mwait
enters an implementation-defined low power state until the monitor is in a triggered state.If the monitor is not into an armed state or if it is already triggered
mwait
is anop
otherwise it makes the processor stop executing instructions until the monitor is triggered.mwait
can also be given extensions and hints.Extensions are set in
ecx
and hints ineax
.At the time of writing the only extension is:
The hints lets the programmer specify the implementation defined low power mode.
The number of sub-states of a C-mode (and thus is availability) is given in CPUID.05h.EDX:
Note that putting the CPU into a state higher than C1 disable other threads too, so the write that triggers the monitor must come from other agents.
The intrinsic is
void _mm_mwait(unsigned extensions, unsigned hints)
.The
monitor
/mwait
machinery was introduced to help synchronisation between threads, it is not well suited for monitoring accesses to a memory range because the trigger conditions include frequently occurring events.After a
mwait
is always mandatory to check if the monitored range was written to.There is an example here where the pattern is as follow:
monitor
/mwait
pair is used.mwait
"returns", the watched structure value is compared to 1 (a write occurred) and if it is not equal execution jump back to 2.Some sample, untested pseudo-code may be:
Care must be taken to ensure that the exit condition of
mwait
was a write and not one of the other events.That's the reason for the function pointer
event
.For monitoring writes/reads to linear address an alternative can be the use of the debugging registers.
See chapter 17 of Intel manual 3 and check your OS documentation for the proper use of those registers.
1 Meaning: Execute
cpuid
witheax
set to 01h and test the bit 3 ofecx
afterward. Note thatIA32_MISC_ENABLE
allows the OS or the firmware to disablemonitor/mwait
.