Commit 80edc49f authored by Vitaly Kuznetsov's avatar Vitaly Kuznetsov Committed by Paolo Bonzini

KVM: VMX: Resurrect vmcs_conf sanitization for KVM-on-Hyper-V

Commit 9bcb9065 ("KVM: VMX: Get rid of eVMCS specific VMX controls
sanitization") dropped 'vmcs_conf' sanitization for KVM-on-Hyper-V because
there's no known Hyper-V version which would expose a feature
unsupported in eVMCS in VMX feature MSRs. This works well for all
currently existing Hyper-V version, however, future Hyper-V versions
may add features which are supported by KVM and are currently missing
in eVMCSv1 definition (e.g. APIC virtualization, PML,...). When this
happens, existing KVMs will get broken. With the inverted 'unsupported
by eVMCSv1' checks, we can resurrect vmcs_conf sanitization and make
KVM future proof.
Signed-off-by: default avatarVitaly Kuznetsov <vkuznets@redhat.com>
Message-Id: <20221104144708.435865-5-vkuznets@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent c128d3fd
// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) "kvm/hyper-v: " fmt
#include <linux/errno.h>
#include <linux/smp.h>
......@@ -504,6 +506,38 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
return 0;
}
#if IS_ENABLED(CONFIG_HYPERV)
/*
* KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption
* is: in case a feature has corresponding fields in eVMCS described and it was
* exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a
* feature which has no corresponding eVMCS field, this likely means that KVM
* needs to be updated.
*/
#define evmcs_check_vmcs_conf(field, ctrl) \
do { \
typeof(vmcs_conf->field) unsupported; \
\
unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \
if (unsupported) { \
pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\
(u64)unsupported); \
vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \
} \
} \
while (0)
__init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
{
evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL);
evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL);
evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC);
evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC);
evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL);
evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL);
}
#endif
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
uint16_t *vmcs_version)
{
......
......@@ -273,6 +273,7 @@ static inline void evmcs_load(u64 phys_addr)
vp_ap->enlighten_vmentry = 1;
}
__init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
#else /* !IS_ENABLED(CONFIG_HYPERV) */
static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
static inline void evmcs_write32(unsigned long field, u32 value) {}
......
......@@ -2752,6 +2752,11 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
vmcs_conf->vmentry_ctrl = _vmentry_control;
vmcs_conf->misc = misc_msr;
#if IS_ENABLED(CONFIG_HYPERV)
if (enlightened_vmcs)
evmcs_sanitize_exec_ctrls(vmcs_conf);
#endif
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment