@@ -194,6 +194,46 @@ impl super::IntelCpuid {
194194 set_bit ( & mut leaf_7_0. result . ebx , 6 , true ) ;
195195 set_bit ( & mut leaf_7_0. result . ebx , 13 , true ) ;
196196
197+ // CPUID.(EAX=07H,ECX=0):ECX[5] (Mnemonic: WAITPKG)
198+ //
199+ // WAITPKG indicates support of user wait instructions (TPAUSE, UMONITOR and UMWAIT).
200+ // - UMONITOR arms address monitoring hardware that checks for store operations on the
201+ // specified address range.
202+ // - UMWAIT instructs the processor to enter an implementation-dependent optimized state
203+ // (either a light-weight power/performance optimized state (C0.1 idle state) or an
204+ // improved power/performance optimized state (C0.2 idle state)) while monitoring the
205+ // address range specified in UMONITOR. The instruction wakes up when the time-stamp
206+ // counter reaches or exceeds the implicit EDX:EAX 64-bit input value.
207+ // - TPSUSE instructs the processor to enter an implementation-dependent optimized state.
208+ // The instruction wakes up when the time-stamp counter reaches or exceeds the implict
209+ // EDX:EAX 64-bit input value.
210+ //
211+ // These instructions may be executed at any privilege level. Even when UMWAIT/TPAUSE are
212+ // executed within a guest, the *physical* processor enters the requested optimized state.
213+ //
214+ // MONITOR/MWAIT instructions are the privileged variant of UMONITOR/UMWAIT and are
215+ // unconditionally emulated as NOP by KVM.
216+ // https://github.com/torvalds/linux/commit/87c00572ba05aa8c9db118da75c608f47eb10b9e
217+ //
218+ // When UMONITOR/UMWAIT/TPAUSE were initially introduced, KVM clears the WAITPKG CPUID bit
219+ // in KVM_GET_SUPPORTED_CPUID by default, and KVM exposes them to guest only when VMM
220+ // explicitly sets the bit via KVM_SET_CPUID2 API.
221+ // https://github.com/torvalds/linux/commit/e69e72faa3a0709dd23df6a4ca060a15e99168a1
222+ // However, since v5.8, if the processor supports "enable user wait and pause" in Intel VMX,
223+ // KVM_GET_SUPPORTEDC_CPUID sets the bit to 1. So if the return value is passed to
224+ // KVM_SET_CPUID2 API as it is, guests are able to execute them.
225+ // https://github.com/torvalds/linux/commit/0abcc8f65cc23b65bc8d1614cc64b02b1641ed7c
226+ //
227+ // Similar to MONITOR/MWAIT, we disbale the guest WAITPKG in order to prevent guests from
228+ // executing those instructions and putting a physical processor to an idle state which may
229+ // lead to an overhead of waking it up when scheduling another guest on it. By clearing the
230+ // WAITPKG bit in KVM_SET_CPUID2 API, KVM does not set the "enable user wait and pause" bit
231+ // (bit 26) of the secondary processor-based VM-execution control, which makes guests get
232+ // #UD when attempting to executing those instructions.
233+ //
234+ // Note that the WAITPKG bit is reserved on AMD.
235+ set_bit ( & mut leaf_7_0. result . ecx , 5 , false ) ;
236+
197237 Ok ( ( ) )
198238 }
199239
@@ -419,6 +459,7 @@ mod tests {
419459 . unwrap ( ) ;
420460 assert ! ( ( leaf_7_0. result. ebx & ( 1 << 6 ) ) > 0 ) ;
421461 assert ! ( ( leaf_7_0. result. ebx & ( 1 << 13 ) ) > 0 ) ;
462+ assert_eq ! ( ( leaf_7_0. result. ecx & ( 1 << 5 ) ) , 0 ) ;
422463 }
423464
424465 #[ test]
0 commit comments