@@ -194,6 +194,48 @@ 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 (UMONITOR, UMWAIT and TPAUSE).
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+ // - TPAUSE 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+ // See Intel SDM vol.3 for more details of the behavior of these instructions in VMX
214+ // non-root operation.
215+ //
216+ // MONITOR/MWAIT instructions are the privileged variant of UMONITOR/UMWAIT and are
217+ // unconditionally emulated as NOP by KVM.
218+ // https://github.com/torvalds/linux/commit/87c00572ba05aa8c9db118da75c608f47eb10b9e
219+ //
220+ // When UMONITOR/UMWAIT/TPAUSE were initially introduced, KVM clears the WAITPKG CPUID bit
221+ // in KVM_GET_SUPPORTED_CPUID by default, and KVM exposed them to guest only when VMM
222+ // explicitly set the bit via KVM_SET_CPUID2 API.
223+ // https://github.com/torvalds/linux/commit/e69e72faa3a0709dd23df6a4ca060a15e99168a1
224+ // However, since v5.8, if the processor supports "enable user wait and pause" in Intel VMX,
225+ // KVM_GET_SUPPORTED_CPUID sets the bit to 1 to let VMM know that it is available. So if the
226+ // returned value is passed to KVM_SET_CPUID2 API as it is, guests are able to execute them.
227+ // https://github.com/torvalds/linux/commit/0abcc8f65cc23b65bc8d1614cc64b02b1641ed7c
228+ //
229+ // Similar to MONITOR/MWAIT, we disable the guest's WAITPKG in order to prevent a guest from
230+ // executing those instructions and putting a physical processor to an idle state which may
231+ // lead to an overhead of waking it up when scheduling another guest on it. By clearing the
232+ // WAITPKG bit in KVM_SET_CPUID2 API, KVM does not set the "enable user wait and pause" bit
233+ // (bit 26) of the secondary processor-based VM-execution control, which makes guests get
234+ // #UD when attempting to executing those instructions.
235+ //
236+ // Note that the WAITPKG bit is reserved on AMD.
237+ set_bit ( & mut leaf_7_0. result . ecx , 5 , false ) ;
238+
197239 Ok ( ( ) )
198240 }
199241
@@ -419,6 +461,7 @@ mod tests {
419461 . unwrap ( ) ;
420462 assert ! ( ( leaf_7_0. result. ebx & ( 1 << 6 ) ) > 0 ) ;
421463 assert ! ( ( leaf_7_0. result. ebx & ( 1 << 13 ) ) > 0 ) ;
464+ assert_eq ! ( ( leaf_7_0. result. ecx & ( 1 << 5 ) ) , 0 ) ;
422465 }
423466
424467 #[ test]
0 commit comments