Skip to content

Commit 31de3d2

Browse files
vittyvkbonzini
authored andcommitted
x86/kvm/hyper-v: move VMX controls sanitization out of nested_enable_evmcs()
With fine grained VMX feature enablement QEMU>=4.2 tries to do KVM_SET_MSRS with default (matching CPU model) values and in case eVMCS is also enabled, fails. It would be possible to drop VMX feature filtering completely and make this a guest's responsibility: if it decides to use eVMCS it should know which fields are available and which are not. Hyper-V mostly complies to this, however, there are some problematic controls: SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES VM_{ENTRY,EXIT}_LOAD_IA32_PERF_GLOBAL_CTRL which Hyper-V enables. As there are no corresponding fields in eVMCS, we can't handle this properly in KVM. This is a Hyper-V issue. Move VMX controls sanitization from nested_enable_evmcs() to vmx_get_msr(), and do the bare minimum (only clear controls which are known to cause issues). This allows userspace to keep setting controls it wants and at the same time hides them from the guest. Signed-off-by: Vitaly Kuznetsov <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 8f79b06 commit 31de3d2

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

arch/x86/kvm/vmx/evmcs.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,32 @@ uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu)
346346
return 0;
347347
}
348348

349+
void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
350+
{
351+
u32 ctl_low = (u32)*pdata;
352+
u32 ctl_high = (u32)(*pdata >> 32);
353+
354+
/*
355+
* Hyper-V 2016 and 2019 try using these features even when eVMCS
356+
* is enabled but there are no corresponding fields.
357+
*/
358+
switch (msr_index) {
359+
case MSR_IA32_VMX_EXIT_CTLS:
360+
case MSR_IA32_VMX_TRUE_EXIT_CTLS:
361+
ctl_high &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL;
362+
break;
363+
case MSR_IA32_VMX_ENTRY_CTLS:
364+
case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
365+
ctl_high &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
366+
break;
367+
case MSR_IA32_VMX_PROCBASED_CTLS2:
368+
ctl_high &= ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
369+
break;
370+
}
371+
372+
*pdata = ctl_low | ((u64)ctl_high << 32);
373+
}
374+
349375
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
350376
uint16_t *vmcs_version)
351377
{
@@ -356,11 +382,5 @@ int nested_enable_evmcs(struct kvm_vcpu *vcpu,
356382
if (vmcs_version)
357383
*vmcs_version = nested_get_evmcs_version(vcpu);
358384

359-
vmx->nested.msrs.pinbased_ctls_high &= ~EVMCS1_UNSUPPORTED_PINCTRL;
360-
vmx->nested.msrs.entry_ctls_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL;
361-
vmx->nested.msrs.exit_ctls_high &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL;
362-
vmx->nested.msrs.secondary_ctls_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC;
363-
vmx->nested.msrs.vmfunc_controls &= ~EVMCS1_UNSUPPORTED_VMFUNC;
364-
365385
return 0;
366386
}

arch/x86/kvm/vmx/evmcs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,5 +201,6 @@ bool nested_enlightened_vmentry(struct kvm_vcpu *vcpu, u64 *evmcs_gpa);
201201
uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
202202
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
203203
uint16_t *vmcs_version);
204+
void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata);
204205

205206
#endif /* __KVM_X86_VMX_EVMCS_H */

arch/x86/kvm/vmx/vmx.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,8 +1853,20 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
18531853
case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
18541854
if (!nested_vmx_allowed(vcpu))
18551855
return 1;
1856-
return vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index,
1857-
&msr_info->data);
1856+
if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index,
1857+
&msr_info->data))
1858+
return 1;
1859+
/*
1860+
* Enlightened VMCS v1 doesn't have certain fields, but buggy
1861+
* Hyper-V versions are still trying to use corresponding
1862+
* features when they are exposed. Filter out the essential
1863+
* minimum.
1864+
*/
1865+
if (!msr_info->host_initiated &&
1866+
vmx->nested.enlightened_vmcs_enabled)
1867+
nested_evmcs_filter_control_msr(msr_info->index,
1868+
&msr_info->data);
1869+
break;
18581870
case MSR_IA32_RTIT_CTL:
18591871
if (pt_mode != PT_MODE_HOST_GUEST)
18601872
return 1;

0 commit comments

Comments
 (0)