diff options
Diffstat (limited to 'arch/x86/kvm/svm/svm.c')
| -rw-r--r-- | arch/x86/kvm/svm/svm.c | 178 | 
1 files changed, 121 insertions, 57 deletions
| diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 989685098b3e..b36ca4e476c2 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -25,6 +25,7 @@  #include <linux/pagemap.h>  #include <linux/swap.h>  #include <linux/rwsem.h> +#include <linux/cc_platform.h>  #include <asm/apic.h>  #include <asm/perf_event.h> @@ -36,6 +37,7 @@  #include <asm/spec-ctrl.h>  #include <asm/cpu_device_id.h>  #include <asm/traps.h> +#include <asm/fpu/api.h>  #include <asm/virtext.h>  #include "trace.h" @@ -186,6 +188,13 @@ module_param(vls, int, 0444);  static int vgif = true;  module_param(vgif, int, 0444); +/* enable/disable LBR virtualization */ +static int lbrv = true; +module_param(lbrv, int, 0444); + +static int tsc_scaling = true; +module_param(tsc_scaling, int, 0444); +  /*   * enable / disable AVIC.  Because the defaults differ for APICv   * support between VMX and SVM we cannot use module_param_named. @@ -455,7 +464,7 @@ static int has_svm(void)  		return 0;  	} -	if (sev_active()) { +	if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {  		pr_info("KVM is unsupported when running as an SEV guest\n");  		return 0;  	} @@ -466,7 +475,7 @@ static int has_svm(void)  static void svm_hardware_disable(void)  {  	/* Make sure we clean up behind us */ -	if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) +	if (tsc_scaling)  		wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT);  	cpu_svm_disable(); @@ -509,6 +518,10 @@ static int svm_hardware_enable(void)  	wrmsrl(MSR_VM_HSAVE_PA, __sme_page_pa(sd->save_area));  	if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { +		/* +		 * Set the default value, even if we don't use TSC scaling +		 * to avoid having stale value in the msr +		 */  		wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT);  		__this_cpu_write(current_tsc_ratio, TSC_RATIO_DEFAULT);  	} @@ -929,6 +942,9 @@ static __init void svm_set_cpu_caps(void)  		if (npt_enabled)  			kvm_cpu_cap_set(X86_FEATURE_NPT); +		if (tsc_scaling) +			kvm_cpu_cap_set(X86_FEATURE_TSCRATEMSR); +  		/* Nested VM can receive #VMEXIT instead of triggering #GP */  		kvm_cpu_cap_set(X86_FEATURE_SVME_ADDR_CHK);  	} @@ -976,10 +992,15 @@ static __init int svm_hardware_setup(void)  	if (boot_cpu_has(X86_FEATURE_FXSR_OPT))  		kvm_enable_efer_bits(EFER_FFXSR); -	if (boot_cpu_has(X86_FEATURE_TSCRATEMSR)) { -		kvm_has_tsc_control = true; -		kvm_max_tsc_scaling_ratio = TSC_RATIO_MAX; -		kvm_tsc_scaling_ratio_frac_bits = 32; +	if (tsc_scaling) { +		if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) { +			tsc_scaling = false; +		} else { +			pr_info("TSC scaling supported\n"); +			kvm_has_tsc_control = true; +			kvm_max_tsc_scaling_ratio = TSC_RATIO_MAX; +			kvm_tsc_scaling_ratio_frac_bits = 32; +		}  	}  	tsc_aux_uret_slot = kvm_add_user_return_msr(MSR_TSC_AUX); @@ -1059,6 +1080,13 @@ static __init int svm_hardware_setup(void)  			pr_info("Virtual GIF supported\n");  	} +	if (lbrv) { +		if (!boot_cpu_has(X86_FEATURE_LBRV)) +			lbrv = false; +		else +			pr_info("LBR virtualization supported\n"); +	} +  	svm_set_cpu_caps();  	/* @@ -1109,7 +1137,9 @@ static u64 svm_get_l2_tsc_offset(struct kvm_vcpu *vcpu)  static u64 svm_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu)  { -	return kvm_default_tsc_scaling_ratio; +	struct vcpu_svm *svm = to_svm(vcpu); + +	return svm->tsc_ratio_msr;  }  static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) @@ -1121,7 +1151,7 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)  	vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS);  } -static void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier) +void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier)  {  	wrmsrl(MSR_AMD64_TSC_RATIO, multiplier);  } @@ -1150,6 +1180,38 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu,  	}  } +static inline void init_vmcb_after_set_cpuid(struct kvm_vcpu *vcpu) +{ +	struct vcpu_svm *svm = to_svm(vcpu); + +	if (guest_cpuid_is_intel(vcpu)) { +		/* +		 * We must intercept SYSENTER_EIP and SYSENTER_ESP +		 * accesses because the processor only stores 32 bits. +		 * For the same reason we cannot use virtual VMLOAD/VMSAVE. +		 */ +		svm_set_intercept(svm, INTERCEPT_VMLOAD); +		svm_set_intercept(svm, INTERCEPT_VMSAVE); +		svm->vmcb->control.virt_ext &= ~VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK; + +		set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_EIP, 0, 0); +		set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_ESP, 0, 0); +	} else { +		/* +		 * If hardware supports Virtual VMLOAD VMSAVE then enable it +		 * in VMCB and clear intercepts to avoid #VMEXIT. +		 */ +		if (vls) { +			svm_clr_intercept(svm, INTERCEPT_VMLOAD); +			svm_clr_intercept(svm, INTERCEPT_VMSAVE); +			svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK; +		} +		/* No need to intercept these MSRs */ +		set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_EIP, 1, 1); +		set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_ESP, 1, 1); +	} +} +  static void init_vmcb(struct kvm_vcpu *vcpu)  {  	struct vcpu_svm *svm = to_svm(vcpu); @@ -1296,11 +1358,25 @@ static void init_vmcb(struct kvm_vcpu *vcpu)  	}  	svm_hv_init_vmcb(svm->vmcb); +	init_vmcb_after_set_cpuid(vcpu);  	vmcb_mark_all_dirty(svm->vmcb);  	enable_gif(svm); +} + +static void __svm_vcpu_reset(struct kvm_vcpu *vcpu) +{ +	struct vcpu_svm *svm = to_svm(vcpu); +	svm_vcpu_init_msrpm(vcpu, svm->msrpm); + +	svm_init_osvw(vcpu); +	vcpu->arch.microcode_version = 0x01000065; +	svm->tsc_ratio_msr = kvm_default_tsc_scaling_ratio; + +	if (sev_es_guest(vcpu->kvm)) +		sev_es_vcpu_reset(svm);  }  static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) @@ -1311,6 +1387,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)  	svm->virt_spec_ctrl = 0;  	init_vmcb(vcpu); + +	if (!init_event) +		__svm_vcpu_reset(vcpu);  }  void svm_switch_vmcb(struct vcpu_svm *svm, struct kvm_vmcb_info *target_vmcb) @@ -1346,10 +1425,10 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)  		/*  		 * SEV-ES guests maintain an encrypted version of their FPU  		 * state which is restored and saved on VMRUN and VMEXIT. -		 * Free the fpu structure to prevent KVM from attempting to -		 * access the FPU state. +		 * Mark vcpu->arch.guest_fpu->fpstate as scratch so it won't +		 * do xsave/xrstor on it.  		 */ -		kvm_free_guest_fpu(vcpu); +		fpstate_set_confidential(&vcpu->arch.guest_fpu);  	}  	err = avic_init_vcpu(svm); @@ -1370,24 +1449,13 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)  	svm->vmcb01.ptr = page_address(vmcb01_page);  	svm->vmcb01.pa = __sme_set(page_to_pfn(vmcb01_page) << PAGE_SHIFT); +	svm_switch_vmcb(svm, &svm->vmcb01);  	if (vmsa_page)  		svm->vmsa = page_address(vmsa_page);  	svm->guest_state_loaded = false; -	svm_switch_vmcb(svm, &svm->vmcb01); -	init_vmcb(vcpu); - -	svm_vcpu_init_msrpm(vcpu, svm->msrpm); - -	svm_init_osvw(vcpu); -	vcpu->arch.microcode_version = 0x01000065; - -	if (sev_es_guest(vcpu->kvm)) -		/* Perform SEV-ES specific VMCB creation updates */ -		sev_es_create_vcpu(svm); -  	return 0;  error_free_vmsa_page: @@ -1447,7 +1515,7 @@ static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)  		vmsave(__sme_page_pa(sd->save_area));  	} -	if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { +	if (tsc_scaling) {  		u64 tsc_ratio = vcpu->arch.tsc_scaling_ratio;  		if (tsc_ratio != __this_cpu_read(current_tsc_ratio)) {  			__this_cpu_write(current_tsc_ratio, tsc_ratio); @@ -2657,6 +2725,11 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)  	struct vcpu_svm *svm = to_svm(vcpu);  	switch (msr_info->index) { +	case MSR_AMD64_TSC_RATIO: +		if (!msr_info->host_initiated && !svm->tsc_scaling_enabled) +			return 1; +		msr_info->data = svm->tsc_ratio_msr; +		break;  	case MSR_STAR:  		msr_info->data = svm->vmcb01.ptr->save.star;  		break; @@ -2806,6 +2879,19 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)  	u32 ecx = msr->index;  	u64 data = msr->data;  	switch (ecx) { +	case MSR_AMD64_TSC_RATIO: +		if (!msr->host_initiated && !svm->tsc_scaling_enabled) +			return 1; + +		if (data & TSC_RATIO_RSVD) +			return 1; + +		svm->tsc_ratio_msr = data; + +		if (svm->tsc_scaling_enabled && is_guest_mode(vcpu)) +			nested_svm_update_tsc_ratio_msr(vcpu); + +		break;  	case MSR_IA32_CR_PAT:  		if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))  			return 1; @@ -2918,7 +3004,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)  		svm->tsc_aux = data;  		break;  	case MSR_IA32_DEBUGCTLMSR: -		if (!boot_cpu_has(X86_FEATURE_LBRV)) { +		if (!lbrv) {  			vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n",  				    __func__, data);  			break; @@ -3278,11 +3364,13 @@ int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)  	return svm_exit_handlers[exit_code](vcpu);  } -static void svm_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2, +static void svm_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, +			      u64 *info1, u64 *info2,  			      u32 *intr_info, u32 *error_code)  {  	struct vmcb_control_area *control = &to_svm(vcpu)->vmcb->control; +	*reason = control->exit_code;  	*info1 = control->exit_info_1;  	*info2 = control->exit_info_2;  	*intr_info = control->exit_int_info; @@ -3299,7 +3387,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)  	struct kvm_run *kvm_run = vcpu->run;  	u32 exit_code = svm->vmcb->control.exit_code; -	trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM); +	trace_kvm_exit(vcpu, KVM_ISA_SVM);  	/* SEV-ES guests must use the CR write traps to track CR registers. */  	if (!sev_es_guest(vcpu->kvm)) { @@ -3312,7 +3400,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)  	if (is_guest_mode(vcpu)) {  		int vmexit; -		trace_kvm_nested_vmexit(exit_code, vcpu, KVM_ISA_SVM); +		trace_kvm_nested_vmexit(vcpu, KVM_ISA_SVM);  		vmexit = nested_svm_exit_special(svm); @@ -3780,8 +3868,6 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)  	pre_svm_run(vcpu); -	WARN_ON_ONCE(kvm_apicv_activated(vcpu->kvm) != kvm_vcpu_apicv_active(vcpu)); -  	sync_lapic_to_cr8(vcpu);  	if (unlikely(svm->asid != svm->vmcb->control.asid)) { @@ -4001,6 +4087,8 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)  	svm->nrips_enabled = kvm_cpu_cap_has(X86_FEATURE_NRIPS) &&  			     guest_cpuid_has(vcpu, X86_FEATURE_NRIPS); +	svm->tsc_scaling_enabled = tsc_scaling && guest_cpuid_has(vcpu, X86_FEATURE_TSCRATEMSR); +  	svm_recalc_instruction_intercepts(vcpu, svm);  	/* For sev guests, the memory encryption bit is not reserved in CR3.  */ @@ -4027,33 +4115,7 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)  			kvm_request_apicv_update(vcpu->kvm, false,  						 APICV_INHIBIT_REASON_NESTED);  	} - -	if (guest_cpuid_is_intel(vcpu)) { -		/* -		 * We must intercept SYSENTER_EIP and SYSENTER_ESP -		 * accesses because the processor only stores 32 bits. -		 * For the same reason we cannot use virtual VMLOAD/VMSAVE. -		 */ -		svm_set_intercept(svm, INTERCEPT_VMLOAD); -		svm_set_intercept(svm, INTERCEPT_VMSAVE); -		svm->vmcb->control.virt_ext &= ~VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK; - -		set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_EIP, 0, 0); -		set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_ESP, 0, 0); -	} else { -		/* -		 * If hardware supports Virtual VMLOAD VMSAVE then enable it -		 * in VMCB and clear intercepts to avoid #VMEXIT. -		 */ -		if (vls) { -			svm_clr_intercept(svm, INTERCEPT_VMLOAD); -			svm_clr_intercept(svm, INTERCEPT_VMSAVE); -			svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK; -		} -		/* No need to intercept these MSRs */ -		set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_EIP, 1, 1); -		set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SYSENTER_ESP, 1, 1); -	} +	init_vmcb_after_set_cpuid(vcpu);  }  static bool svm_has_wbinvd_exit(void) @@ -4520,6 +4582,8 @@ static int svm_vm_init(struct kvm *kvm)  }  static struct kvm_x86_ops svm_x86_ops __initdata = { +	.name = "kvm_amd", +  	.hardware_unsetup = svm_hardware_teardown,  	.hardware_enable = svm_hardware_enable,  	.hardware_disable = svm_hardware_disable, |