KVM: x86: SVM: don't set VMLOAD/VMSAVE intercepts on vCPU reset
Commit adc2a23734ac ("KVM: nSVM: improve SYSENTER emulation on AMD"), made init_vmcb set vmload/vmsave intercepts unconditionally, and relied on svm_vcpu_after_set_cpuid to clear them when possible. However init_vmcb is also called when the vCPU is reset, and it is not followed by another call to svm_vcpu_after_set_cpuid because the CPUID is already set. This mistake makes the VMSAVE/VMLOAD intercept to be set when it is not needed, and harms performance of the nested guest. Extract the relevant parts of svm_vcpu_after_set_cpuid so that they can be called again on reset. Fixes: adc2a23734ac ("KVM: nSVM: improve SYSENTER emulation on AMD") Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
4c84926e22
commit
36e8194dcd
@ -1161,6 +1161,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);
|
||||
@ -1307,6 +1339,7 @@ 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);
|
||||
|
||||
@ -4043,33 +4076,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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user