[v7,1/3] KVM: x86: add support for user wait instructions
diff mbox series

Message ID 20190712082907.29137-2-tao3.xu@intel.com
State New
Headers show
Series
  • KVM: x86: Enable user wait instructions
Related show

Commit Message

Tao Xu July 12, 2019, 8:29 a.m. UTC
UMONITOR, UMWAIT and TPAUSE are a set of user wait instructions.
This patch adds support for user wait instructions in KVM. Availability
of the user wait instructions is indicated by the presence of the CPUID
feature flag WAITPKG CPUID.0x07.0x0:ECX[5]. User wait instructions may
be executed at any privilege level, and use IA32_UMWAIT_CONTROL MSR to
set the maximum time.

The behavior of user wait instructions in VMX non-root operation is
determined first by the setting of the "enable user wait and pause"
secondary processor-based VM-execution control bit 26.
	If the VM-execution control is 0, UMONITOR/UMWAIT/TPAUSE cause
an invalid-opcode exception (#UD).
	If the VM-execution control is 1, treatment is based on the
setting of the “RDTSC exiting” VM-execution control. Because KVM never
enables RDTSC exiting, if the instruction causes a delay, the amount of
time delayed is called here the physical delay. The physical delay is
first computed by determining the virtual delay. If
IA32_UMWAIT_CONTROL[31:2] is zero, the virtual delay is the value in
EDX:EAX minus the value that RDTSC would return; if
IA32_UMWAIT_CONTROL[31:2] is not zero, the virtual delay is the minimum
of that difference and AND(IA32_UMWAIT_CONTROL,FFFFFFFCH).

Because umwait and tpause can put a (psysical) CPU into a power saving
state, by default we dont't expose it to kvm and enable it only when
guest CPUID has it.

Detailed information about user wait instructions can be found in the
latest Intel 64 and IA-32 Architectures Software Developer's Manual.

Co-developed-by: Jingqi Liu <jingqi.liu@intel.com>
Signed-off-by: Jingqi Liu <jingqi.liu@intel.com>
Signed-off-by: Tao Xu <tao3.xu@intel.com>
---

Changes in v7:
    - Add nested support for user wait instructions (Paolo)
---
 arch/x86/include/asm/vmx.h |  1 +
 arch/x86/kvm/cpuid.c       |  2 +-
 arch/x86/kvm/vmx/nested.c  |  1 +
 arch/x86/kvm/vmx/vmx.c     | 20 ++++++++++++++++++++
 4 files changed, 23 insertions(+), 1 deletion(-)

Comments

Sean Christopherson July 12, 2019, 3:13 p.m. UTC | #1
On Fri, Jul 12, 2019 at 04:29:05PM +0800, Tao Xu wrote:
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index 46af3a5e9209..a4d5da34b306 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -2048,6 +2048,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
>  				  SECONDARY_EXEC_ENABLE_INVPCID |
>  				  SECONDARY_EXEC_RDTSCP |
>  				  SECONDARY_EXEC_XSAVES |
> +				  SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
>  				  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
>  				  SECONDARY_EXEC_APIC_REGISTER_VIRT |
>  				  SECONDARY_EXEC_ENABLE_VMFUNC);
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index d98eac371c0a..f411c9ae5589 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -2247,6 +2247,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
>  			SECONDARY_EXEC_RDRAND_EXITING |
>  			SECONDARY_EXEC_ENABLE_PML |
>  			SECONDARY_EXEC_TSC_SCALING |
> +			SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
>  			SECONDARY_EXEC_PT_USE_GPA |
>  			SECONDARY_EXEC_PT_CONCEAL_VMX |
>  			SECONDARY_EXEC_ENABLE_VMFUNC |
> @@ -3984,6 +3985,25 @@ static void vmx_compute_secondary_exec_control(struct vcpu_vmx *vmx)
>  		}
>  	}
>  
> +	if (vmcs_config.cpu_based_2nd_exec_ctrl &
> +		SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE) {

This should be aligned with the beginning of the conditional.
Alternatively, add a vmx_waitpkg_supported() helper, which is fairly
ubiquitous even when there is only a single call site.

> +		/* Exposing WAITPKG only when WAITPKG is exposed */
No need for this comment.  It's also oddly worded, e.g. the second
"exposed" should probably be "enabled"?

> +		bool waitpkg_enabled =
> +			guest_cpuid_has(vcpu, X86_FEATURE_WAITPKG);
> +
> +		if (!waitpkg_enabled)
> +			exec_control &= ~SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
> +
> +		if (nested) {
> +			if (waitpkg_enabled)
> +				vmx->nested.msrs.secondary_ctls_high |=
> +					SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
> +			else
> +				vmx->nested.msrs.secondary_ctls_high &=
> +					~SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
> +		}
> +	}
> +
>  	vmx->secondary_exec_control = exec_control;
>  }
>  
> -- 
> 2.20.1
>
Tao Xu July 15, 2019, 1:11 a.m. UTC | #2
On 7/12/2019 11:13 PM, Sean Christopherson wrote:
> On Fri, Jul 12, 2019 at 04:29:05PM +0800, Tao Xu wrote:
>> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
>> index 46af3a5e9209..a4d5da34b306 100644
>> --- a/arch/x86/kvm/vmx/nested.c
>> +++ b/arch/x86/kvm/vmx/nested.c
>> @@ -2048,6 +2048,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
>>   				  SECONDARY_EXEC_ENABLE_INVPCID |
>>   				  SECONDARY_EXEC_RDTSCP |
>>   				  SECONDARY_EXEC_XSAVES |
>> +				  SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
>>   				  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
>>   				  SECONDARY_EXEC_APIC_REGISTER_VIRT |
>>   				  SECONDARY_EXEC_ENABLE_VMFUNC);
>> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
>> index d98eac371c0a..f411c9ae5589 100644
>> --- a/arch/x86/kvm/vmx/vmx.c
>> +++ b/arch/x86/kvm/vmx/vmx.c
>> @@ -2247,6 +2247,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
>>   			SECONDARY_EXEC_RDRAND_EXITING |
>>   			SECONDARY_EXEC_ENABLE_PML |
>>   			SECONDARY_EXEC_TSC_SCALING |
>> +			SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
>>   			SECONDARY_EXEC_PT_USE_GPA |
>>   			SECONDARY_EXEC_PT_CONCEAL_VMX |
>>   			SECONDARY_EXEC_ENABLE_VMFUNC |
>> @@ -3984,6 +3985,25 @@ static void vmx_compute_secondary_exec_control(struct vcpu_vmx *vmx)
>>   		}
>>   	}
>>   
>> +	if (vmcs_config.cpu_based_2nd_exec_ctrl &
>> +		SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE) {
> 
> This should be aligned with the beginning of the conditional.
> Alternatively, add a vmx_waitpkg_supported() helper, which is fairly
> ubiquitous even when there is only a single call site.
> 

OK, Thank you for your suggestion.
>> +		/* Exposing WAITPKG only when WAITPKG is exposed */
> No need for this comment.  It's also oddly worded, e.g. the second
> "exposed" should probably be "enabled"?
> 
>> +		bool waitpkg_enabled =
>> +			guest_cpuid_has(vcpu, X86_FEATURE_WAITPKG);
>> +
>> +		if (!waitpkg_enabled)
>> +			exec_control &= ~SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
>> +
>> +		if (nested) {
>> +			if (waitpkg_enabled)
>> +				vmx->nested.msrs.secondary_ctls_high |=
>> +					SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
>> +			else
>> +				vmx->nested.msrs.secondary_ctls_high &=
>> +					~SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
>> +		}
>> +	}
>> +
>>   	vmx->secondary_exec_control = exec_control;
>>   }
>>   
>> -- 
>> 2.20.1
>>

Patch
diff mbox series

diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index a39136b0d509..8f00882664d3 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -69,6 +69,7 @@ 
 #define SECONDARY_EXEC_PT_USE_GPA		0x01000000
 #define SECONDARY_EXEC_MODE_BASED_EPT_EXEC	0x00400000
 #define SECONDARY_EXEC_TSC_SCALING              0x02000000
+#define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE	0x04000000
 
 #define PIN_BASED_EXT_INTR_MASK                 0x00000001
 #define PIN_BASED_NMI_EXITING                   0x00000008
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 4992e7c99588..7d2cd4066f64 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -402,7 +402,7 @@  static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
 		F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ |
 		F(AVX512_VPOPCNTDQ) | F(UMIP) | F(AVX512_VBMI2) | F(GFNI) |
 		F(VAES) | F(VPCLMULQDQ) | F(AVX512_VNNI) | F(AVX512_BITALG) |
-		F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B);
+		F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B) | 0 /*WAITPKG*/;
 
 	/* cpuid 7.0.edx*/
 	const u32 kvm_cpuid_7_0_edx_x86_features =
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 46af3a5e9209..a4d5da34b306 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -2048,6 +2048,7 @@  static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
 				  SECONDARY_EXEC_ENABLE_INVPCID |
 				  SECONDARY_EXEC_RDTSCP |
 				  SECONDARY_EXEC_XSAVES |
+				  SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
 				  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
 				  SECONDARY_EXEC_APIC_REGISTER_VIRT |
 				  SECONDARY_EXEC_ENABLE_VMFUNC);
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index d98eac371c0a..f411c9ae5589 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -2247,6 +2247,7 @@  static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
 			SECONDARY_EXEC_RDRAND_EXITING |
 			SECONDARY_EXEC_ENABLE_PML |
 			SECONDARY_EXEC_TSC_SCALING |
+			SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
 			SECONDARY_EXEC_PT_USE_GPA |
 			SECONDARY_EXEC_PT_CONCEAL_VMX |
 			SECONDARY_EXEC_ENABLE_VMFUNC |
@@ -3984,6 +3985,25 @@  static void vmx_compute_secondary_exec_control(struct vcpu_vmx *vmx)
 		}
 	}
 
+	if (vmcs_config.cpu_based_2nd_exec_ctrl &
+		SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE) {
+		/* Exposing WAITPKG only when WAITPKG is exposed */
+		bool waitpkg_enabled =
+			guest_cpuid_has(vcpu, X86_FEATURE_WAITPKG);
+
+		if (!waitpkg_enabled)
+			exec_control &= ~SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
+
+		if (nested) {
+			if (waitpkg_enabled)
+				vmx->nested.msrs.secondary_ctls_high |=
+					SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
+			else
+				vmx->nested.msrs.secondary_ctls_high &=
+					~SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE;
+		}
+	}
+
 	vmx->secondary_exec_control = exec_control;
 }