Ideas to make Hyper-V emulation by KVM optional were expressed in the past
so I've decided to take a look at what would it take us to implement it.
Turns out it's quite a lot of code churn but the gain is also significant.
Just comparing the resulting module sizes, I can see:
# CONFIG_KVM_HYPERV is not set
# CONFIG_HYPERV is not set
-rw-r--r--. 1 user user 3612632 Oct 10 16:53 arch/x86/kvm/kvm-amd.ko
-rw-r--r--. 1 user user 5343968 Oct 10 16:53 arch/x86/kvm/kvm-intel.ko
CONFIG_KVM_HYPERV=y
# CONFIG_HYPERV is not set
-rw-r--r--. 1 user user 3925704 Oct 10 16:51 arch/x86/kvm/kvm-amd.ko
-rw-r--r--. 1 user user 5819192 Oct 10 16:51 arch/x86/kvm/kvm-intel.ko
# CONFIG_KVM_HYPERV is not set
CONFIG_HYPERV=m
-rw-r--r--. 1 user user 3928440 Oct 10 16:40 arch/x86/kvm/kvm-amd.ko
-rw-r--r--. 1 user user 8156464 Oct 10 16:40 arch/x86/kvm/kvm-intel.ko
CONFIG_KVM_HYPERV=y
CONFIG_HYPERV=m
-rw-r--r--. 1 user user 4245440 Oct 10 16:37 arch/x86/kvm/kvm-amd.ko
-rw-r--r--. 1 user user 8583872 Oct 10 16:37 arch/x86/kvm/kvm-intel.ko
While code churn is certainly something we can survive, adding more CONFIG
options always comes with a risk of a broken build somewhere in the future.
Early RFC. I have only compile tested these patches in these four
configurations and I'd like to get your opinion on whether it's worth it or
not.
The first patch of the series is not Hyper-V related but as I hide Hyper-V
emulation context under CONFIG_KVM_HYPERV I think it would make sense to
do the same for Xen.
Vitaly Kuznetsov (11):
KVM: x86: xen: Remove unneeded xen context from struct kvm_arch when
!CONFIG_KVM_XEN
KVM: x86: hyper-v: Move Hyper-V partition assist page out of Hyper-V
emulation context
KVM: VMX: Split off vmx_onhyperv.{ch} from hyperv.{ch}
KVM: x86: hyper-v: Introduce kvm_hv_synic_auto_eoi_set()
KVM: x86: hyper-v: Introduce kvm_hv_synic_has_vector()
KVM: VMX: Split off hyperv_evmcs.{ch}
KVM: x86: Make Hyper-V emulation optional
KVM: nVMX: hyper-v: Introduce nested_vmx_evmptr() accessor
KVM: nVMX: hyper-v: Introduce nested_vmx_evmcs() accessor
KVM: nVMX: hyper-v: Hide more stuff under CONFIG_KVM_HYPERV
KVM: nSVM: hyper-v: Hide more stuff under
CONFIG_KVM_HYPERV/CONFIG_HYPERV
arch/x86/include/asm/kvm_host.h | 11 +-
arch/x86/kvm/Kconfig | 9 +
arch/x86/kvm/Makefile | 19 +-
arch/x86/kvm/cpuid.c | 6 +
arch/x86/kvm/hyperv.h | 39 ++-
arch/x86/kvm/irq.c | 2 +
arch/x86/kvm/irq_comm.c | 9 +-
arch/x86/kvm/lapic.c | 5 +-
arch/x86/kvm/svm/hyperv.h | 7 +
arch/x86/kvm/svm/nested.c | 22 +-
arch/x86/kvm/svm/svm.h | 2 +
arch/x86/kvm/svm/svm_onhyperv.c | 2 +-
arch/x86/kvm/svm/svm_onhyperv.h | 2 +
arch/x86/kvm/vmx/hyperv.c | 447 --------------------------------
arch/x86/kvm/vmx/hyperv.h | 191 ++------------
arch/x86/kvm/vmx/hyperv_evmcs.c | 311 ++++++++++++++++++++++
arch/x86/kvm/vmx/hyperv_evmcs.h | 162 ++++++++++++
arch/x86/kvm/vmx/nested.c | 94 ++++---
arch/x86/kvm/vmx/nested.h | 3 +-
arch/x86/kvm/vmx/vmx.c | 6 +-
arch/x86/kvm/vmx/vmx.h | 2 +
arch/x86/kvm/vmx/vmx_onhyperv.c | 36 +++
arch/x86/kvm/vmx/vmx_onhyperv.h | 125 +++++++++
arch/x86/kvm/vmx/vmx_ops.h | 2 +-
arch/x86/kvm/x86.c | 60 +++--
25 files changed, 885 insertions(+), 689 deletions(-)
create mode 100644 arch/x86/kvm/vmx/hyperv_evmcs.c
create mode 100644 arch/x86/kvm/vmx/hyperv_evmcs.h
create mode 100644 arch/x86/kvm/vmx/vmx_onhyperv.c
create mode 100644 arch/x86/kvm/vmx/vmx_onhyperv.h
--
2.41.0
As a preparation to making Hyper-V emulation optional, create a dedicated
kvm_hv_synic_auto_eoi_set() helper to avoid extra ifdefs in lapic.c
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/kvm/hyperv.h | 5 +++++
arch/x86/kvm/lapic.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index f83b8db72b11..1897a219981d 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -105,6 +105,11 @@ int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages);
+static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector)
+{
+ return to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap);
+}
+
void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
bool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index dcd60b39e794..0e80c1fdf899 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2899,7 +2899,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
*/
apic_clear_irr(vector, apic);
- if (to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap)) {
+ if (kvm_hv_synic_auto_eoi_set(vcpu, vector)) {
/*
* For auto-EOI interrupts, there might be another pending
* interrupt above PPR, so check whether to raise another
--
2.41.0
There's a number of 'vmx->nested.hv_evmcs' accesses in nested.c, introduce
'nested_vmx_evmcs()' accessor to hide them all in !CONFIG_KVM_HYPERV case.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/kvm/vmx/hyperv.h | 8 ++++++++
arch/x86/kvm/vmx/nested.c | 33 ++++++++++++++++++---------------
2 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
index 6ca5c8c5be9c..b07131a23250 100644
--- a/arch/x86/kvm/vmx/hyperv.h
+++ b/arch/x86/kvm/vmx/hyperv.h
@@ -25,6 +25,10 @@ struct vcpu_vmx;
#ifdef CONFIG_KVM_HYPERV
static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return vmx->nested.hv_evmcs_vmptr; }
+static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
+{
+ return vmx->nested.hv_evmcs;
+}
u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
@@ -35,6 +39,10 @@ bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
#else
static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return EVMPTR_INVALID; };
+static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
+{
+ return NULL;
+}
static inline u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { return EVMPTR_INVALID; }
static inline void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) {}
static inline bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index e6476f8e2ccd..d539904d8f1e 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -574,7 +574,6 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
int msr;
unsigned long *msr_bitmap_l1;
unsigned long *msr_bitmap_l0 = vmx->nested.vmcs02.msr_bitmap;
- struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
struct kvm_host_map *map = &vmx->nested.msr_bitmap_map;
/* Nothing to do if the MSR bitmap is not in use. */
@@ -590,10 +589,13 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
* - Nested hypervisor (L1) has enabled 'Enlightened MSR Bitmap' feature
* and tells KVM (L0) there were no changes in MSR bitmap for L2.
*/
- if (!vmx->nested.force_msr_bitmap_recalc && evmcs &&
- evmcs->hv_enlightenments_control.msr_bitmap &&
- evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP)
- return true;
+ if (!vmx->nested.force_msr_bitmap_recalc) {
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
+
+ if (evmcs && evmcs->hv_enlightenments_control.msr_bitmap &&
+ evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP)
+ return true;
+ }
if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->msr_bitmap), map))
return false;
@@ -1584,7 +1586,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
{
struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
- struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(&vmx->vcpu);
/* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE */
@@ -1828,7 +1830,7 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields
static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
{
struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
- struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
/*
* Should not be changed by KVM:
@@ -2412,7 +2414,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
{
- struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs;
+ struct hv_enlightened_vmcs *hv_evmcs = nested_vmx_evmcs(vmx);
if (!hv_evmcs || !(hv_evmcs->hv_clean_fields &
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2)) {
@@ -2544,6 +2546,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
enum vm_entry_failure_code *entry_failure_code)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
bool load_guest_pdptrs_vmcs12 = false;
if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(nested_vmx_evmptr(vmx))) {
@@ -2551,8 +2554,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
vmx->nested.dirty_vmcs12 = false;
load_guest_pdptrs_vmcs12 = !evmptr_is_valid(nested_vmx_evmptr(vmx)) ||
- !(vmx->nested.hv_evmcs->hv_clean_fields &
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
+ !(evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
}
if (vmx->nested.nested_run_pending &&
@@ -2674,8 +2676,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
* here.
*/
if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
- vmx->nested.hv_evmcs->hv_clean_fields |=
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
+ evmcs->hv_clean_fields |= HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
return 0;
}
@@ -3600,7 +3601,9 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
return nested_vmx_failInvalid(vcpu);
if (evmptr_is_valid(nested_vmx_evmptr(vmx))) {
- copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields);
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
+
+ copy_enlightened_to_vmcs12(vmx, evmcs->hv_clean_fields);
/* Enlightened VMCS doesn't have launch state */
vmcs12->launch_state = !launch;
} else if (enable_shadow_vmcs) {
@@ -5335,7 +5338,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
vmptr + offsetof(struct vmcs12,
launch_state),
&zero, sizeof(zero));
- } else if (vmx->nested.hv_evmcs && vmptr == nested_vmx_evmptr(vmx)) {
+ } else if (nested_vmx_evmcs(vmx) && vmptr == nested_vmx_evmptr(vmx)) {
nested_release_evmcs(vcpu);
}
@@ -5413,7 +5416,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
/* Read the field, zero-extended to a u64 value */
- value = evmcs_read_any(vmx->nested.hv_evmcs, field, offset);
+ value = evmcs_read_any(nested_vmx_evmcs(vmx), field, offset);
}
/*
--
2.41.0
hyperv.{ch} is currently a mix of stuff which is needed by both Hyper-V on
KVM and KVM on Hyper-V. As a preparation to making Hyper-V emulation
optional, put KVM-on-Hyper-V specific code into dedicated files.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/kvm/Makefile | 4 +
arch/x86/kvm/vmx/hyperv.c | 139 --------------------
arch/x86/kvm/vmx/hyperv.h | 217 ++++++++++++++++----------------
arch/x86/kvm/vmx/vmx.c | 1 +
arch/x86/kvm/vmx/vmx_onhyperv.c | 36 ++++++
arch/x86/kvm/vmx/vmx_onhyperv.h | 124 ++++++++++++++++++
arch/x86/kvm/vmx/vmx_ops.h | 2 +-
7 files changed, 271 insertions(+), 252 deletions(-)
create mode 100644 arch/x86/kvm/vmx/vmx_onhyperv.c
create mode 100644 arch/x86/kvm/vmx/vmx_onhyperv.h
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index 80e3fe184d17..a99ffc3f3a3f 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -26,6 +26,10 @@ kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
vmx/hyperv.o vmx/nested.o vmx/posted_intr.o
kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
+ifdef CONFIG_HYPERV
+kvm-intel-y += vmx/vmx_onhyperv.o
+endif
+
kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \
svm/sev.o svm/hyperv.o
diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c
index 313b8bb5b8a7..de13dc14fe1d 100644
--- a/arch/x86/kvm/vmx/hyperv.c
+++ b/arch/x86/kvm/vmx/hyperv.c
@@ -13,111 +13,6 @@
#define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK
-/*
- * Enlightened VMCSv1 doesn't support these:
- *
- * POSTED_INTR_NV = 0x00000002,
- * GUEST_INTR_STATUS = 0x00000810,
- * APIC_ACCESS_ADDR = 0x00002014,
- * POSTED_INTR_DESC_ADDR = 0x00002016,
- * EOI_EXIT_BITMAP0 = 0x0000201c,
- * EOI_EXIT_BITMAP1 = 0x0000201e,
- * EOI_EXIT_BITMAP2 = 0x00002020,
- * EOI_EXIT_BITMAP3 = 0x00002022,
- * GUEST_PML_INDEX = 0x00000812,
- * PML_ADDRESS = 0x0000200e,
- * VM_FUNCTION_CONTROL = 0x00002018,
- * EPTP_LIST_ADDRESS = 0x00002024,
- * VMREAD_BITMAP = 0x00002026,
- * VMWRITE_BITMAP = 0x00002028,
- *
- * TSC_MULTIPLIER = 0x00002032,
- * PLE_GAP = 0x00004020,
- * PLE_WINDOW = 0x00004022,
- * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
- *
- * Currently unsupported in KVM:
- * GUEST_IA32_RTIT_CTL = 0x00002814,
- */
-#define EVMCS1_SUPPORTED_PINCTRL \
- (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
- PIN_BASED_EXT_INTR_MASK | \
- PIN_BASED_NMI_EXITING | \
- PIN_BASED_VIRTUAL_NMIS)
-
-#define EVMCS1_SUPPORTED_EXEC_CTRL \
- (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
- CPU_BASED_HLT_EXITING | \
- CPU_BASED_CR3_LOAD_EXITING | \
- CPU_BASED_CR3_STORE_EXITING | \
- CPU_BASED_UNCOND_IO_EXITING | \
- CPU_BASED_MOV_DR_EXITING | \
- CPU_BASED_USE_TSC_OFFSETTING | \
- CPU_BASED_MWAIT_EXITING | \
- CPU_BASED_MONITOR_EXITING | \
- CPU_BASED_INVLPG_EXITING | \
- CPU_BASED_RDPMC_EXITING | \
- CPU_BASED_INTR_WINDOW_EXITING | \
- CPU_BASED_CR8_LOAD_EXITING | \
- CPU_BASED_CR8_STORE_EXITING | \
- CPU_BASED_RDTSC_EXITING | \
- CPU_BASED_TPR_SHADOW | \
- CPU_BASED_USE_IO_BITMAPS | \
- CPU_BASED_MONITOR_TRAP_FLAG | \
- CPU_BASED_USE_MSR_BITMAPS | \
- CPU_BASED_NMI_WINDOW_EXITING | \
- CPU_BASED_PAUSE_EXITING | \
- CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
-
-#define EVMCS1_SUPPORTED_2NDEXEC \
- (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
- SECONDARY_EXEC_WBINVD_EXITING | \
- SECONDARY_EXEC_ENABLE_VPID | \
- SECONDARY_EXEC_ENABLE_EPT | \
- SECONDARY_EXEC_UNRESTRICTED_GUEST | \
- SECONDARY_EXEC_DESC | \
- SECONDARY_EXEC_ENABLE_RDTSCP | \
- SECONDARY_EXEC_ENABLE_INVPCID | \
- SECONDARY_EXEC_ENABLE_XSAVES | \
- SECONDARY_EXEC_RDSEED_EXITING | \
- SECONDARY_EXEC_RDRAND_EXITING | \
- SECONDARY_EXEC_TSC_SCALING | \
- SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
- SECONDARY_EXEC_PT_USE_GPA | \
- SECONDARY_EXEC_PT_CONCEAL_VMX | \
- SECONDARY_EXEC_BUS_LOCK_DETECTION | \
- SECONDARY_EXEC_NOTIFY_VM_EXITING | \
- SECONDARY_EXEC_ENCLS_EXITING)
-
-#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
-
-#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
- (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
- VM_EXIT_SAVE_DEBUG_CONTROLS | \
- VM_EXIT_ACK_INTR_ON_EXIT | \
- VM_EXIT_HOST_ADDR_SPACE_SIZE | \
- VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
- VM_EXIT_SAVE_IA32_PAT | \
- VM_EXIT_LOAD_IA32_PAT | \
- VM_EXIT_SAVE_IA32_EFER | \
- VM_EXIT_LOAD_IA32_EFER | \
- VM_EXIT_CLEAR_BNDCFGS | \
- VM_EXIT_PT_CONCEAL_PIP | \
- VM_EXIT_CLEAR_IA32_RTIT_CTL)
-
-#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
- (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
- VM_ENTRY_LOAD_DEBUG_CONTROLS | \
- VM_ENTRY_IA32E_MODE | \
- VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
- VM_ENTRY_LOAD_IA32_PAT | \
- VM_ENTRY_LOAD_IA32_EFER | \
- VM_ENTRY_LOAD_BNDCFGS | \
- VM_ENTRY_PT_CONCEAL_PIP | \
- VM_ENTRY_LOAD_IA32_RTIT_CTL)
-
-#define EVMCS1_SUPPORTED_VMFUNC (0)
-
#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
{EVMCS1_OFFSET(name), clean_field}
@@ -608,40 +503,6 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
return 0;
}
-#if IS_ENABLED(CONFIG_HYPERV)
-DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
-
-/*
- * 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)
-
-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)
{
diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
index 9623fe1651c4..9401dbfaea7c 100644
--- a/arch/x86/kvm/vmx/hyperv.h
+++ b/arch/x86/kvm/vmx/hyperv.h
@@ -14,12 +14,113 @@
#include "vmcs.h"
#include "vmcs12.h"
-struct vmcs_config;
-
-#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
-
#define KVM_EVMCS_VERSION 1
+/*
+ * Enlightened VMCSv1 doesn't support these:
+ *
+ * POSTED_INTR_NV = 0x00000002,
+ * GUEST_INTR_STATUS = 0x00000810,
+ * APIC_ACCESS_ADDR = 0x00002014,
+ * POSTED_INTR_DESC_ADDR = 0x00002016,
+ * EOI_EXIT_BITMAP0 = 0x0000201c,
+ * EOI_EXIT_BITMAP1 = 0x0000201e,
+ * EOI_EXIT_BITMAP2 = 0x00002020,
+ * EOI_EXIT_BITMAP3 = 0x00002022,
+ * GUEST_PML_INDEX = 0x00000812,
+ * PML_ADDRESS = 0x0000200e,
+ * VM_FUNCTION_CONTROL = 0x00002018,
+ * EPTP_LIST_ADDRESS = 0x00002024,
+ * VMREAD_BITMAP = 0x00002026,
+ * VMWRITE_BITMAP = 0x00002028,
+ *
+ * TSC_MULTIPLIER = 0x00002032,
+ * PLE_GAP = 0x00004020,
+ * PLE_WINDOW = 0x00004022,
+ * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
+ *
+ * Currently unsupported in KVM:
+ * GUEST_IA32_RTIT_CTL = 0x00002814,
+ */
+#define EVMCS1_SUPPORTED_PINCTRL \
+ (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
+ PIN_BASED_EXT_INTR_MASK | \
+ PIN_BASED_NMI_EXITING | \
+ PIN_BASED_VIRTUAL_NMIS)
+
+#define EVMCS1_SUPPORTED_EXEC_CTRL \
+ (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
+ CPU_BASED_HLT_EXITING | \
+ CPU_BASED_CR3_LOAD_EXITING | \
+ CPU_BASED_CR3_STORE_EXITING | \
+ CPU_BASED_UNCOND_IO_EXITING | \
+ CPU_BASED_MOV_DR_EXITING | \
+ CPU_BASED_USE_TSC_OFFSETTING | \
+ CPU_BASED_MWAIT_EXITING | \
+ CPU_BASED_MONITOR_EXITING | \
+ CPU_BASED_INVLPG_EXITING | \
+ CPU_BASED_RDPMC_EXITING | \
+ CPU_BASED_INTR_WINDOW_EXITING | \
+ CPU_BASED_CR8_LOAD_EXITING | \
+ CPU_BASED_CR8_STORE_EXITING | \
+ CPU_BASED_RDTSC_EXITING | \
+ CPU_BASED_TPR_SHADOW | \
+ CPU_BASED_USE_IO_BITMAPS | \
+ CPU_BASED_MONITOR_TRAP_FLAG | \
+ CPU_BASED_USE_MSR_BITMAPS | \
+ CPU_BASED_NMI_WINDOW_EXITING | \
+ CPU_BASED_PAUSE_EXITING | \
+ CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
+
+#define EVMCS1_SUPPORTED_2NDEXEC \
+ (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
+ SECONDARY_EXEC_WBINVD_EXITING | \
+ SECONDARY_EXEC_ENABLE_VPID | \
+ SECONDARY_EXEC_ENABLE_EPT | \
+ SECONDARY_EXEC_UNRESTRICTED_GUEST | \
+ SECONDARY_EXEC_DESC | \
+ SECONDARY_EXEC_ENABLE_RDTSCP | \
+ SECONDARY_EXEC_ENABLE_INVPCID | \
+ SECONDARY_EXEC_ENABLE_XSAVES | \
+ SECONDARY_EXEC_RDSEED_EXITING | \
+ SECONDARY_EXEC_RDRAND_EXITING | \
+ SECONDARY_EXEC_TSC_SCALING | \
+ SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
+ SECONDARY_EXEC_PT_USE_GPA | \
+ SECONDARY_EXEC_PT_CONCEAL_VMX | \
+ SECONDARY_EXEC_BUS_LOCK_DETECTION | \
+ SECONDARY_EXEC_NOTIFY_VM_EXITING | \
+ SECONDARY_EXEC_ENCLS_EXITING)
+
+#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
+
+#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
+ (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
+ VM_EXIT_SAVE_DEBUG_CONTROLS | \
+ VM_EXIT_ACK_INTR_ON_EXIT | \
+ VM_EXIT_HOST_ADDR_SPACE_SIZE | \
+ VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
+ VM_EXIT_SAVE_IA32_PAT | \
+ VM_EXIT_LOAD_IA32_PAT | \
+ VM_EXIT_SAVE_IA32_EFER | \
+ VM_EXIT_LOAD_IA32_EFER | \
+ VM_EXIT_CLEAR_BNDCFGS | \
+ VM_EXIT_PT_CONCEAL_PIP | \
+ VM_EXIT_CLEAR_IA32_RTIT_CTL)
+
+#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
+ (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
+ VM_ENTRY_LOAD_DEBUG_CONTROLS | \
+ VM_ENTRY_IA32E_MODE | \
+ VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
+ VM_ENTRY_LOAD_IA32_PAT | \
+ VM_ENTRY_LOAD_IA32_EFER | \
+ VM_ENTRY_LOAD_BNDCFGS | \
+ VM_ENTRY_PT_CONCEAL_PIP | \
+ VM_ENTRY_LOAD_IA32_RTIT_CTL)
+
+#define EVMCS1_SUPPORTED_VMFUNC (0)
+
struct evmcs_field {
u16 offset;
u16 clean_field;
@@ -65,114 +166,6 @@ static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
return vmcs12_read_any((void *)evmcs, field, offset);
}
-#if IS_ENABLED(CONFIG_HYPERV)
-
-DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
-
-static __always_inline bool kvm_is_using_evmcs(void)
-{
- return static_branch_unlikely(&__kvm_is_using_evmcs);
-}
-
-static __always_inline int get_evmcs_offset(unsigned long field,
- u16 *clean_field)
-{
- int offset = evmcs_field_offset(field, clean_field);
-
- WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field);
- return offset;
-}
-
-static __always_inline void evmcs_write64(unsigned long field, u64 value)
-{
- u16 clean_field;
- int offset = get_evmcs_offset(field, &clean_field);
-
- if (offset < 0)
- return;
-
- *(u64 *)((char *)current_evmcs + offset) = value;
-
- current_evmcs->hv_clean_fields &= ~clean_field;
-}
-
-static __always_inline void evmcs_write32(unsigned long field, u32 value)
-{
- u16 clean_field;
- int offset = get_evmcs_offset(field, &clean_field);
-
- if (offset < 0)
- return;
-
- *(u32 *)((char *)current_evmcs + offset) = value;
- current_evmcs->hv_clean_fields &= ~clean_field;
-}
-
-static __always_inline void evmcs_write16(unsigned long field, u16 value)
-{
- u16 clean_field;
- int offset = get_evmcs_offset(field, &clean_field);
-
- if (offset < 0)
- return;
-
- *(u16 *)((char *)current_evmcs + offset) = value;
- current_evmcs->hv_clean_fields &= ~clean_field;
-}
-
-static __always_inline u64 evmcs_read64(unsigned long field)
-{
- int offset = get_evmcs_offset(field, NULL);
-
- if (offset < 0)
- return 0;
-
- return *(u64 *)((char *)current_evmcs + offset);
-}
-
-static __always_inline u32 evmcs_read32(unsigned long field)
-{
- int offset = get_evmcs_offset(field, NULL);
-
- if (offset < 0)
- return 0;
-
- return *(u32 *)((char *)current_evmcs + offset);
-}
-
-static __always_inline u16 evmcs_read16(unsigned long field)
-{
- int offset = get_evmcs_offset(field, NULL);
-
- if (offset < 0)
- return 0;
-
- return *(u16 *)((char *)current_evmcs + offset);
-}
-
-static inline void evmcs_load(u64 phys_addr)
-{
- struct hv_vp_assist_page *vp_ap =
- hv_get_vp_assist_page(smp_processor_id());
-
- if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall)
- vp_ap->nested_control.features.directhypercall = 1;
- vp_ap->current_nested_vmcs = phys_addr;
- vp_ap->enlighten_vmentry = 1;
-}
-
-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
-#else /* !IS_ENABLED(CONFIG_HYPERV) */
-static __always_inline bool kvm_is_using_evmcs(void) { return false; }
-static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
-static __always_inline void evmcs_write32(unsigned long field, u32 value) {}
-static __always_inline void evmcs_write16(unsigned long field, u16 value) {}
-static __always_inline u64 evmcs_read64(unsigned long field) { return 0; }
-static __always_inline u32 evmcs_read32(unsigned long field) { return 0; }
-static __always_inline u16 evmcs_read16(unsigned long field) { return 0; }
-static inline void evmcs_load(u64 phys_addr) {}
-#endif /* IS_ENABLED(CONFIG_HYPERV) */
-
#define EVMPTR_INVALID (-1ULL)
#define EVMPTR_MAP_PENDING (-2ULL)
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index b7dc7acf14be..04eb5d4d28bc 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -66,6 +66,7 @@
#include "vmx.h"
#include "x86.h"
#include "smm.h"
+#include "vmx_onhyperv.h"
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.c b/arch/x86/kvm/vmx/vmx_onhyperv.c
new file mode 100644
index 000000000000..b9a8b91166d0
--- /dev/null
+++ b/arch/x86/kvm/vmx/vmx_onhyperv.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "capabilities.h"
+#include "vmx_onhyperv.h"
+
+DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
+
+/*
+ * 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)
+
+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);
+}
diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h
new file mode 100644
index 000000000000..11541d272dbd
--- /dev/null
+++ b/arch/x86/kvm/vmx/vmx_onhyperv.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ARCH_X86_KVM_VMX_ONHYPERV_H__
+#define __ARCH_X86_KVM_VMX_ONHYPERV_H__
+
+#include <asm/hyperv-tlfs.h>
+
+#include <linux/jump_label.h>
+
+#include "capabilities.h"
+#include "hyperv.h"
+#include "vmcs12.h"
+
+#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
+
+#if IS_ENABLED(CONFIG_HYPERV)
+
+DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
+
+static __always_inline bool kvm_is_using_evmcs(void)
+{
+ return static_branch_unlikely(&__kvm_is_using_evmcs);
+}
+
+static __always_inline int get_evmcs_offset(unsigned long field,
+ u16 *clean_field)
+{
+ int offset = evmcs_field_offset(field, clean_field);
+
+ WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field);
+ return offset;
+}
+
+static __always_inline void evmcs_write64(unsigned long field, u64 value)
+{
+ u16 clean_field;
+ int offset = get_evmcs_offset(field, &clean_field);
+
+ if (offset < 0)
+ return;
+
+ *(u64 *)((char *)current_evmcs + offset) = value;
+
+ current_evmcs->hv_clean_fields &= ~clean_field;
+}
+
+static __always_inline void evmcs_write32(unsigned long field, u32 value)
+{
+ u16 clean_field;
+ int offset = get_evmcs_offset(field, &clean_field);
+
+ if (offset < 0)
+ return;
+
+ *(u32 *)((char *)current_evmcs + offset) = value;
+ current_evmcs->hv_clean_fields &= ~clean_field;
+}
+
+static __always_inline void evmcs_write16(unsigned long field, u16 value)
+{
+ u16 clean_field;
+ int offset = get_evmcs_offset(field, &clean_field);
+
+ if (offset < 0)
+ return;
+
+ *(u16 *)((char *)current_evmcs + offset) = value;
+ current_evmcs->hv_clean_fields &= ~clean_field;
+}
+
+static __always_inline u64 evmcs_read64(unsigned long field)
+{
+ int offset = get_evmcs_offset(field, NULL);
+
+ if (offset < 0)
+ return 0;
+
+ return *(u64 *)((char *)current_evmcs + offset);
+}
+
+static __always_inline u32 evmcs_read32(unsigned long field)
+{
+ int offset = get_evmcs_offset(field, NULL);
+
+ if (offset < 0)
+ return 0;
+
+ return *(u32 *)((char *)current_evmcs + offset);
+}
+
+static __always_inline u16 evmcs_read16(unsigned long field)
+{
+ int offset = get_evmcs_offset(field, NULL);
+
+ if (offset < 0)
+ return 0;
+
+ return *(u16 *)((char *)current_evmcs + offset);
+}
+
+static inline void evmcs_load(u64 phys_addr)
+{
+ struct hv_vp_assist_page *vp_ap =
+ hv_get_vp_assist_page(smp_processor_id());
+
+ if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall)
+ vp_ap->nested_control.features.directhypercall = 1;
+ vp_ap->current_nested_vmcs = phys_addr;
+ vp_ap->enlighten_vmentry = 1;
+}
+
+void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
+#else /* !IS_ENABLED(CONFIG_HYPERV) */
+static __always_inline bool kvm_is_using_evmcs(void) { return false; }
+static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
+static __always_inline void evmcs_write32(unsigned long field, u32 value) {}
+static __always_inline void evmcs_write16(unsigned long field, u16 value) {}
+static __always_inline u64 evmcs_read64(unsigned long field) { return 0; }
+static __always_inline u32 evmcs_read32(unsigned long field) { return 0; }
+static __always_inline u16 evmcs_read16(unsigned long field) { return 0; }
+static inline void evmcs_load(u64 phys_addr) {}
+#endif /* IS_ENABLED(CONFIG_HYPERV) */
+
+#endif /* __ARCH_X86_KVM_VMX_ONHYPERV_H__ */
diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h
index 33af7b4c6eb4..f41ce3c24123 100644
--- a/arch/x86/kvm/vmx/vmx_ops.h
+++ b/arch/x86/kvm/vmx/vmx_ops.h
@@ -6,7 +6,7 @@
#include <asm/vmx.h>
-#include "hyperv.h"
+#include "vmx_onhyperv.h"
#include "vmcs.h"
#include "../x86.h"
--
2.41.0
'hv_evmcs_vmptr'/'hv_evmcs_map'/'hv_evmcs' fields in 'struct nested_vmx'
should not be used when !CONFIG_KVM_HYPERV, hide them when
!CONFIG_KVM_HYPERV.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/kvm/vmx/nested.c | 2 ++
arch/x86/kvm/vmx/vmx.c | 3 +++
arch/x86/kvm/vmx/vmx.h | 2 ++
3 files changed, 7 insertions(+)
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index d539904d8f1e..10cb35cd7a19 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -6650,6 +6650,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
return -EINVAL;
set_current_vmptr(vmx, kvm_state->hdr.vmx.vmcs12_pa);
+#ifdef CONFIG_KVM_HYPERV
} else if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) {
/*
* nested_vmx_handle_enlightened_vmptrld() cannot be called
@@ -6659,6 +6660,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
*/
vmx->nested.hv_evmcs_vmptr = EVMPTR_MAP_PENDING;
kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
+#endif
} else {
return -EINVAL;
}
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 04eb5d4d28bc..3b1bd3d97150 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4834,7 +4834,10 @@ static void __vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmx->nested.posted_intr_nv = -1;
vmx->nested.vmxon_ptr = INVALID_GPA;
vmx->nested.current_vmptr = INVALID_GPA;
+
+#ifdef CONFIG_KVM_HYPERV
vmx->nested.hv_evmcs_vmptr = EVMPTR_INVALID;
+#endif
vcpu->arch.microcode_version = 0x100000000ULL;
vmx->msr_ia32_feature_control_valid_bits = FEAT_CTL_LOCKED;
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index c2130d2c8e24..55addb8eef01 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -241,9 +241,11 @@ struct nested_vmx {
bool guest_mode;
} smm;
+#ifdef CONFIG_KVM_HYPERV
gpa_t hv_evmcs_vmptr;
struct kvm_host_map hv_evmcs_map;
struct hv_enlightened_vmcs *hv_evmcs;
+#endif
};
struct vcpu_vmx {
--
2.41.0
Some Enlightened VMCS related code is needed both by Hyper-V on KVM and
KVM on Hyper-V. As a preparation to making Hyper-V emulation optional,
create dedicated 'hyperv_evmcs.{ch}' files which are used by both.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/kvm/Makefile | 2 +-
arch/x86/kvm/vmx/hyperv.c | 308 -------------------------------
arch/x86/kvm/vmx/hyperv.h | 163 +----------------
arch/x86/kvm/vmx/hyperv_evmcs.c | 311 ++++++++++++++++++++++++++++++++
arch/x86/kvm/vmx/hyperv_evmcs.h | 162 +++++++++++++++++
arch/x86/kvm/vmx/vmx_onhyperv.h | 3 +-
6 files changed, 477 insertions(+), 472 deletions(-)
create mode 100644 arch/x86/kvm/vmx/hyperv_evmcs.c
create mode 100644 arch/x86/kvm/vmx/hyperv_evmcs.h
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index a99ffc3f3a3f..8ea872401cd6 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -23,7 +23,7 @@ kvm-$(CONFIG_KVM_XEN) += xen.o
kvm-$(CONFIG_KVM_SMM) += smm.o
kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
- vmx/hyperv.o vmx/nested.o vmx/posted_intr.o
+ vmx/hyperv.o vmx/hyperv_evmcs.o vmx/nested.o vmx/posted_intr.o
kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
ifdef CONFIG_HYPERV
diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c
index de13dc14fe1d..fab6a1ad98dc 100644
--- a/arch/x86/kvm/vmx/hyperv.c
+++ b/arch/x86/kvm/vmx/hyperv.c
@@ -13,314 +13,6 @@
#define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK
-#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
-#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
- {EVMCS1_OFFSET(name), clean_field}
-
-const struct evmcs_field vmcs_field_to_evmcs_1[] = {
- /* 64 bit rw */
- EVMCS1_FIELD(GUEST_RIP, guest_rip,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(GUEST_RSP, guest_rsp,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
- EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
- EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_CR0, host_cr0,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_CR3, host_cr3,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_CR4, host_cr4,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_RIP, host_rip,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
- EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
- EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
- EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(GUEST_CR0, guest_cr0,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(GUEST_CR3, guest_cr3,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(GUEST_CR4, guest_cr4,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(GUEST_DR7, guest_dr7,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_RSP, host_rsp,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(EPT_POINTER, ept_pointer,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
- EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- /*
- * Not used by KVM:
- *
- * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- * EVMCS1_FIELD(0x0000682A, guest_ssp,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
- * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- * EVMCS1_FIELD(0x00006C1A, host_ssp,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- */
-
- /* 64 bit read only */
- EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- /*
- * Not defined in KVM:
- *
- * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
- * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
- * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
- * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
- */
- EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
-
- /*
- * No mask defined in the spec as Hyper-V doesn't currently support
- * these. Future proof by resetting the whole clean field mask on
- * access.
- */
- EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
-
- /* 32 bit rw */
- EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
- EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
- EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
- EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
- EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
- EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
- vm_entry_exception_error_code,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
- EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
- EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
- EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
- EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
- EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
-
- /* 32 bit read only */
- EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
-
- /* No mask defined in the spec (not used) */
- EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
-
- /* 16 bit rw */
- EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
-};
-const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
-
u64 nested_get_evmptr(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
index 9401dbfaea7c..d4ed99008518 100644
--- a/arch/x86/kvm/vmx/hyperv.h
+++ b/arch/x86/kvm/vmx/hyperv.h
@@ -2,170 +2,9 @@
#ifndef __KVM_X86_VMX_HYPERV_H
#define __KVM_X86_VMX_HYPERV_H
-#include <linux/jump_label.h>
-
-#include <asm/hyperv-tlfs.h>
-#include <asm/mshyperv.h>
-#include <asm/vmx.h>
-
-#include "../hyperv.h"
-
-#include "capabilities.h"
-#include "vmcs.h"
+#include <linux/kvm_host.h>
#include "vmcs12.h"
-#define KVM_EVMCS_VERSION 1
-
-/*
- * Enlightened VMCSv1 doesn't support these:
- *
- * POSTED_INTR_NV = 0x00000002,
- * GUEST_INTR_STATUS = 0x00000810,
- * APIC_ACCESS_ADDR = 0x00002014,
- * POSTED_INTR_DESC_ADDR = 0x00002016,
- * EOI_EXIT_BITMAP0 = 0x0000201c,
- * EOI_EXIT_BITMAP1 = 0x0000201e,
- * EOI_EXIT_BITMAP2 = 0x00002020,
- * EOI_EXIT_BITMAP3 = 0x00002022,
- * GUEST_PML_INDEX = 0x00000812,
- * PML_ADDRESS = 0x0000200e,
- * VM_FUNCTION_CONTROL = 0x00002018,
- * EPTP_LIST_ADDRESS = 0x00002024,
- * VMREAD_BITMAP = 0x00002026,
- * VMWRITE_BITMAP = 0x00002028,
- *
- * TSC_MULTIPLIER = 0x00002032,
- * PLE_GAP = 0x00004020,
- * PLE_WINDOW = 0x00004022,
- * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
- *
- * Currently unsupported in KVM:
- * GUEST_IA32_RTIT_CTL = 0x00002814,
- */
-#define EVMCS1_SUPPORTED_PINCTRL \
- (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
- PIN_BASED_EXT_INTR_MASK | \
- PIN_BASED_NMI_EXITING | \
- PIN_BASED_VIRTUAL_NMIS)
-
-#define EVMCS1_SUPPORTED_EXEC_CTRL \
- (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
- CPU_BASED_HLT_EXITING | \
- CPU_BASED_CR3_LOAD_EXITING | \
- CPU_BASED_CR3_STORE_EXITING | \
- CPU_BASED_UNCOND_IO_EXITING | \
- CPU_BASED_MOV_DR_EXITING | \
- CPU_BASED_USE_TSC_OFFSETTING | \
- CPU_BASED_MWAIT_EXITING | \
- CPU_BASED_MONITOR_EXITING | \
- CPU_BASED_INVLPG_EXITING | \
- CPU_BASED_RDPMC_EXITING | \
- CPU_BASED_INTR_WINDOW_EXITING | \
- CPU_BASED_CR8_LOAD_EXITING | \
- CPU_BASED_CR8_STORE_EXITING | \
- CPU_BASED_RDTSC_EXITING | \
- CPU_BASED_TPR_SHADOW | \
- CPU_BASED_USE_IO_BITMAPS | \
- CPU_BASED_MONITOR_TRAP_FLAG | \
- CPU_BASED_USE_MSR_BITMAPS | \
- CPU_BASED_NMI_WINDOW_EXITING | \
- CPU_BASED_PAUSE_EXITING | \
- CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
-
-#define EVMCS1_SUPPORTED_2NDEXEC \
- (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
- SECONDARY_EXEC_WBINVD_EXITING | \
- SECONDARY_EXEC_ENABLE_VPID | \
- SECONDARY_EXEC_ENABLE_EPT | \
- SECONDARY_EXEC_UNRESTRICTED_GUEST | \
- SECONDARY_EXEC_DESC | \
- SECONDARY_EXEC_ENABLE_RDTSCP | \
- SECONDARY_EXEC_ENABLE_INVPCID | \
- SECONDARY_EXEC_ENABLE_XSAVES | \
- SECONDARY_EXEC_RDSEED_EXITING | \
- SECONDARY_EXEC_RDRAND_EXITING | \
- SECONDARY_EXEC_TSC_SCALING | \
- SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
- SECONDARY_EXEC_PT_USE_GPA | \
- SECONDARY_EXEC_PT_CONCEAL_VMX | \
- SECONDARY_EXEC_BUS_LOCK_DETECTION | \
- SECONDARY_EXEC_NOTIFY_VM_EXITING | \
- SECONDARY_EXEC_ENCLS_EXITING)
-
-#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
-
-#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
- (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
- VM_EXIT_SAVE_DEBUG_CONTROLS | \
- VM_EXIT_ACK_INTR_ON_EXIT | \
- VM_EXIT_HOST_ADDR_SPACE_SIZE | \
- VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
- VM_EXIT_SAVE_IA32_PAT | \
- VM_EXIT_LOAD_IA32_PAT | \
- VM_EXIT_SAVE_IA32_EFER | \
- VM_EXIT_LOAD_IA32_EFER | \
- VM_EXIT_CLEAR_BNDCFGS | \
- VM_EXIT_PT_CONCEAL_PIP | \
- VM_EXIT_CLEAR_IA32_RTIT_CTL)
-
-#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
- (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
- VM_ENTRY_LOAD_DEBUG_CONTROLS | \
- VM_ENTRY_IA32E_MODE | \
- VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
- VM_ENTRY_LOAD_IA32_PAT | \
- VM_ENTRY_LOAD_IA32_EFER | \
- VM_ENTRY_LOAD_BNDCFGS | \
- VM_ENTRY_PT_CONCEAL_PIP | \
- VM_ENTRY_LOAD_IA32_RTIT_CTL)
-
-#define EVMCS1_SUPPORTED_VMFUNC (0)
-
-struct evmcs_field {
- u16 offset;
- u16 clean_field;
-};
-
-extern const struct evmcs_field vmcs_field_to_evmcs_1[];
-extern const unsigned int nr_evmcs_1_fields;
-
-static __always_inline int evmcs_field_offset(unsigned long field,
- u16 *clean_field)
-{
- unsigned int index = ROL16(field, 6);
- const struct evmcs_field *evmcs_field;
-
- if (unlikely(index >= nr_evmcs_1_fields))
- return -ENOENT;
-
- evmcs_field = &vmcs_field_to_evmcs_1[index];
-
- /*
- * Use offset=0 to detect holes in eVMCS. This offset belongs to
- * 'revision_id' but this field has no encoding and is supposed to
- * be accessed directly.
- */
- if (unlikely(!evmcs_field->offset))
- return -ENOENT;
-
- if (clean_field)
- *clean_field = evmcs_field->clean_field;
-
- return evmcs_field->offset;
-}
-
-static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
- unsigned long field, u16 offset)
-{
- /*
- * vmcs12_read_any() doesn't care whether the supplied structure
- * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
- * the exact offset of the required field, use it for convenience
- * here.
- */
- return vmcs12_read_any((void *)evmcs, field, offset);
-}
-
#define EVMPTR_INVALID (-1ULL)
#define EVMPTR_MAP_PENDING (-2ULL)
diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.c b/arch/x86/kvm/vmx/hyperv_evmcs.c
new file mode 100644
index 000000000000..57a2e0470ac8
--- /dev/null
+++ b/arch/x86/kvm/vmx/hyperv_evmcs.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "hyperv_evmcs.h"
+
+#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
+#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
+ {EVMCS1_OFFSET(name), clean_field}
+
+const struct evmcs_field vmcs_field_to_evmcs_1[] = {
+ /* 64 bit rw */
+ EVMCS1_FIELD(GUEST_RIP, guest_rip,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(GUEST_RSP, guest_rsp,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
+ EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
+ EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_CR0, host_cr0,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_CR3, host_cr3,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_CR4, host_cr4,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_RIP, host_rip,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
+ EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
+ EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
+ EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(GUEST_CR0, guest_cr0,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(GUEST_CR3, guest_cr3,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(GUEST_CR4, guest_cr4,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(GUEST_DR7, guest_dr7,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_RSP, host_rsp,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(EPT_POINTER, ept_pointer,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
+ EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ /*
+ * Not used by KVM:
+ *
+ * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ * EVMCS1_FIELD(0x0000682A, guest_ssp,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
+ * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ * EVMCS1_FIELD(0x00006C1A, host_ssp,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ */
+
+ /* 64 bit read only */
+ EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ /*
+ * Not defined in KVM:
+ *
+ * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
+ * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
+ * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
+ * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
+ */
+ EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+
+ /*
+ * No mask defined in the spec as Hyper-V doesn't currently support
+ * these. Future proof by resetting the whole clean field mask on
+ * access.
+ */
+ EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+
+ /* 32 bit rw */
+ EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
+ EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
+ EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
+ EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
+ EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
+ EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
+ vm_entry_exception_error_code,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
+ EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
+ EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
+ EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
+ EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
+ EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+
+ /* 32 bit read only */
+ EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+
+ /* No mask defined in the spec (not used) */
+ EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+
+ /* 16 bit rw */
+ EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
+};
+const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.h b/arch/x86/kvm/vmx/hyperv_evmcs.h
new file mode 100644
index 000000000000..11d96975e7cc
--- /dev/null
+++ b/arch/x86/kvm/vmx/hyperv_evmcs.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_X86_VMX_HYPERV_EVMCS_H
+#define __KVM_X86_VMX_HYPERV_EVMCS_H
+
+#include <asm/hyperv-tlfs.h>
+
+#include "capabilities.h"
+#include "vmcs12.h"
+
+#define KVM_EVMCS_VERSION 1
+
+/*
+ * Enlightened VMCSv1 doesn't support these:
+ *
+ * POSTED_INTR_NV = 0x00000002,
+ * GUEST_INTR_STATUS = 0x00000810,
+ * APIC_ACCESS_ADDR = 0x00002014,
+ * POSTED_INTR_DESC_ADDR = 0x00002016,
+ * EOI_EXIT_BITMAP0 = 0x0000201c,
+ * EOI_EXIT_BITMAP1 = 0x0000201e,
+ * EOI_EXIT_BITMAP2 = 0x00002020,
+ * EOI_EXIT_BITMAP3 = 0x00002022,
+ * GUEST_PML_INDEX = 0x00000812,
+ * PML_ADDRESS = 0x0000200e,
+ * VM_FUNCTION_CONTROL = 0x00002018,
+ * EPTP_LIST_ADDRESS = 0x00002024,
+ * VMREAD_BITMAP = 0x00002026,
+ * VMWRITE_BITMAP = 0x00002028,
+ *
+ * TSC_MULTIPLIER = 0x00002032,
+ * PLE_GAP = 0x00004020,
+ * PLE_WINDOW = 0x00004022,
+ * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
+ *
+ * Currently unsupported in KVM:
+ * GUEST_IA32_RTIT_CTL = 0x00002814,
+ */
+#define EVMCS1_SUPPORTED_PINCTRL \
+ (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
+ PIN_BASED_EXT_INTR_MASK | \
+ PIN_BASED_NMI_EXITING | \
+ PIN_BASED_VIRTUAL_NMIS)
+
+#define EVMCS1_SUPPORTED_EXEC_CTRL \
+ (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
+ CPU_BASED_HLT_EXITING | \
+ CPU_BASED_CR3_LOAD_EXITING | \
+ CPU_BASED_CR3_STORE_EXITING | \
+ CPU_BASED_UNCOND_IO_EXITING | \
+ CPU_BASED_MOV_DR_EXITING | \
+ CPU_BASED_USE_TSC_OFFSETTING | \
+ CPU_BASED_MWAIT_EXITING | \
+ CPU_BASED_MONITOR_EXITING | \
+ CPU_BASED_INVLPG_EXITING | \
+ CPU_BASED_RDPMC_EXITING | \
+ CPU_BASED_INTR_WINDOW_EXITING | \
+ CPU_BASED_CR8_LOAD_EXITING | \
+ CPU_BASED_CR8_STORE_EXITING | \
+ CPU_BASED_RDTSC_EXITING | \
+ CPU_BASED_TPR_SHADOW | \
+ CPU_BASED_USE_IO_BITMAPS | \
+ CPU_BASED_MONITOR_TRAP_FLAG | \
+ CPU_BASED_USE_MSR_BITMAPS | \
+ CPU_BASED_NMI_WINDOW_EXITING | \
+ CPU_BASED_PAUSE_EXITING | \
+ CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
+
+#define EVMCS1_SUPPORTED_2NDEXEC \
+ (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
+ SECONDARY_EXEC_WBINVD_EXITING | \
+ SECONDARY_EXEC_ENABLE_VPID | \
+ SECONDARY_EXEC_ENABLE_EPT | \
+ SECONDARY_EXEC_UNRESTRICTED_GUEST | \
+ SECONDARY_EXEC_DESC | \
+ SECONDARY_EXEC_ENABLE_RDTSCP | \
+ SECONDARY_EXEC_ENABLE_INVPCID | \
+ SECONDARY_EXEC_ENABLE_XSAVES | \
+ SECONDARY_EXEC_RDSEED_EXITING | \
+ SECONDARY_EXEC_RDRAND_EXITING | \
+ SECONDARY_EXEC_TSC_SCALING | \
+ SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
+ SECONDARY_EXEC_PT_USE_GPA | \
+ SECONDARY_EXEC_PT_CONCEAL_VMX | \
+ SECONDARY_EXEC_BUS_LOCK_DETECTION | \
+ SECONDARY_EXEC_NOTIFY_VM_EXITING | \
+ SECONDARY_EXEC_ENCLS_EXITING)
+
+#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
+
+#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
+ (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
+ VM_EXIT_SAVE_DEBUG_CONTROLS | \
+ VM_EXIT_ACK_INTR_ON_EXIT | \
+ VM_EXIT_HOST_ADDR_SPACE_SIZE | \
+ VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
+ VM_EXIT_SAVE_IA32_PAT | \
+ VM_EXIT_LOAD_IA32_PAT | \
+ VM_EXIT_SAVE_IA32_EFER | \
+ VM_EXIT_LOAD_IA32_EFER | \
+ VM_EXIT_CLEAR_BNDCFGS | \
+ VM_EXIT_PT_CONCEAL_PIP | \
+ VM_EXIT_CLEAR_IA32_RTIT_CTL)
+
+#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
+ (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
+ VM_ENTRY_LOAD_DEBUG_CONTROLS | \
+ VM_ENTRY_IA32E_MODE | \
+ VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
+ VM_ENTRY_LOAD_IA32_PAT | \
+ VM_ENTRY_LOAD_IA32_EFER | \
+ VM_ENTRY_LOAD_BNDCFGS | \
+ VM_ENTRY_PT_CONCEAL_PIP | \
+ VM_ENTRY_LOAD_IA32_RTIT_CTL)
+
+#define EVMCS1_SUPPORTED_VMFUNC (0)
+
+struct evmcs_field {
+ u16 offset;
+ u16 clean_field;
+};
+
+extern const struct evmcs_field vmcs_field_to_evmcs_1[];
+extern const unsigned int nr_evmcs_1_fields;
+
+static __always_inline int evmcs_field_offset(unsigned long field,
+ u16 *clean_field)
+{
+ unsigned int index = ROL16(field, 6);
+ const struct evmcs_field *evmcs_field;
+
+ if (unlikely(index >= nr_evmcs_1_fields))
+ return -ENOENT;
+
+ evmcs_field = &vmcs_field_to_evmcs_1[index];
+
+ /*
+ * Use offset=0 to detect holes in eVMCS. This offset belongs to
+ * 'revision_id' but this field has no encoding and is supposed to
+ * be accessed directly.
+ */
+ if (unlikely(!evmcs_field->offset))
+ return -ENOENT;
+
+ if (clean_field)
+ *clean_field = evmcs_field->clean_field;
+
+ return evmcs_field->offset;
+}
+
+static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
+ unsigned long field, u16 offset)
+{
+ /*
+ * vmcs12_read_any() doesn't care whether the supplied structure
+ * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
+ * the exact offset of the required field, use it for convenience
+ * here.
+ */
+ return vmcs12_read_any((void *)evmcs, field, offset);
+}
+
+#endif /* __KVM_X86_VMX_HYPERV_H */
diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h
index 11541d272dbd..eb48153bfd73 100644
--- a/arch/x86/kvm/vmx/vmx_onhyperv.h
+++ b/arch/x86/kvm/vmx/vmx_onhyperv.h
@@ -4,11 +4,12 @@
#define __ARCH_X86_KVM_VMX_ONHYPERV_H__
#include <asm/hyperv-tlfs.h>
+#include <asm/mshyperv.h>
#include <linux/jump_label.h>
#include "capabilities.h"
-#include "hyperv.h"
+#include "hyperv_evmcs.h"
#include "vmcs12.h"
#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
--
2.41.0
'vmx->nested.hv_evmcs_vmptr' accesses are all over the place so hiding
'hv_evmcs_vmptr' under 'ifdef CONFIG_KVM_HYPERV' would take a lot of
ifdefs. Introduce 'nested_vmx_evmptr()' accessor instead.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/kvm/vmx/hyperv.h | 5 +++++
arch/x86/kvm/vmx/nested.c | 44 +++++++++++++++++++--------------------
arch/x86/kvm/vmx/nested.h | 3 ++-
3 files changed, 29 insertions(+), 23 deletions(-)
diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
index 933ef6cad5e6..6ca5c8c5be9c 100644
--- a/arch/x86/kvm/vmx/hyperv.h
+++ b/arch/x86/kvm/vmx/hyperv.h
@@ -4,6 +4,7 @@
#include <linux/kvm_host.h>
#include "vmcs12.h"
+#include "vmx.h"
#define EVMPTR_INVALID (-1ULL)
#define EVMPTR_MAP_PENDING (-2ULL)
@@ -20,7 +21,10 @@ enum nested_evmptrld_status {
EVMPTRLD_ERROR,
};
+struct vcpu_vmx;
+
#ifdef CONFIG_KVM_HYPERV
+static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return vmx->nested.hv_evmcs_vmptr; }
u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
@@ -30,6 +34,7 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
#else
+static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return EVMPTR_INVALID; };
static inline u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { return EVMPTR_INVALID; }
static inline void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) {}
static inline bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index ca7e06759aa3..e6476f8e2ccd 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -179,7 +179,7 @@ static int nested_vmx_failValid(struct kvm_vcpu *vcpu,
* VM_INSTRUCTION_ERROR is not shadowed. Enlightened VMCS 'shadows' all
* fields and thus must be synced.
*/
- if (to_vmx(vcpu)->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
+ if (nested_vmx_evmptr(to_vmx(vcpu)) != EVMPTR_INVALID)
to_vmx(vcpu)->nested.need_vmcs12_to_shadow_sync = true;
return kvm_skip_emulated_instruction(vcpu);
@@ -194,7 +194,7 @@ static int nested_vmx_fail(struct kvm_vcpu *vcpu, u32 vm_instruction_error)
* can't be done if there isn't a current VMCS.
*/
if (vmx->nested.current_vmptr == INVALID_GPA &&
- !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ !evmptr_is_valid(nested_vmx_evmptr(vmx)))
return nested_vmx_failInvalid(vcpu);
return nested_vmx_failValid(vcpu, vm_instruction_error);
@@ -230,7 +230,7 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
struct vcpu_vmx *vmx = to_vmx(vcpu);
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+ if (evmptr_is_valid(nested_vmx_evmptr(vmx))) {
kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
vmx->nested.hv_evmcs = NULL;
}
@@ -2019,7 +2019,7 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
return EVMPTRLD_DISABLED;
}
- if (unlikely(evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
+ if (unlikely(evmcs_gpa != nested_vmx_evmptr(vmx))) {
vmx->nested.current_vmptr = INVALID_GPA;
nested_release_evmcs(vcpu);
@@ -2097,7 +2097,7 @@ void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
copy_vmcs12_to_enlightened(vmx);
else
copy_vmcs12_to_shadow(vmx);
@@ -2251,7 +2251,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
u32 exec_control;
u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12);
- if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(nested_vmx_evmptr(vmx)))
prepare_vmcs02_early_rare(vmx, vmcs12);
/*
@@ -2546,11 +2546,11 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
struct vcpu_vmx *vmx = to_vmx(vcpu);
bool load_guest_pdptrs_vmcs12 = false;
- if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+ if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(nested_vmx_evmptr(vmx))) {
prepare_vmcs02_rare(vmx, vmcs12);
vmx->nested.dirty_vmcs12 = false;
- load_guest_pdptrs_vmcs12 = !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) ||
+ load_guest_pdptrs_vmcs12 = !evmptr_is_valid(nested_vmx_evmptr(vmx)) ||
!(vmx->nested.hv_evmcs->hv_clean_fields &
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
}
@@ -2673,7 +2673,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
* bits when it changes a field in eVMCS. Mark all fields as clean
* here.
*/
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
vmx->nested.hv_evmcs->hv_clean_fields |=
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
@@ -3181,7 +3181,7 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
* properly reflected.
*/
if (guest_cpuid_has_evmcs(vcpu) &&
- vmx->nested.hv_evmcs_vmptr == EVMPTR_MAP_PENDING) {
+ nested_vmx_evmptr(vmx) == EVMPTR_MAP_PENDING) {
enum nested_evmptrld_status evmptrld_status =
nested_vmx_handle_enlightened_vmptrld(vcpu, false);
@@ -3551,7 +3551,7 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
load_vmcs12_host_state(vcpu, vmcs12);
vmcs12->vm_exit_reason = exit_reason.full;
- if (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (enable_shadow_vmcs || evmptr_is_valid(nested_vmx_evmptr(vmx)))
vmx->nested.need_vmcs12_to_shadow_sync = true;
return NVMX_VMENTRY_VMEXIT;
}
@@ -3584,7 +3584,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
if (CC(evmptrld_status == EVMPTRLD_VMFAIL))
return nested_vmx_failInvalid(vcpu);
- if (CC(!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) &&
+ if (CC(!evmptr_is_valid(nested_vmx_evmptr(vmx)) &&
vmx->nested.current_vmptr == INVALID_GPA))
return nested_vmx_failInvalid(vcpu);
@@ -3599,7 +3599,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
if (CC(vmcs12->hdr.shadow_vmcs))
return nested_vmx_failInvalid(vcpu);
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+ if (evmptr_is_valid(nested_vmx_evmptr(vmx))) {
copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields);
/* Enlightened VMCS doesn't have launch state */
vmcs12->launch_state = !launch;
@@ -4344,11 +4344,11 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
vmx->nested.need_sync_vmcs02_to_vmcs12_rare =
- !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
+ !evmptr_is_valid(nested_vmx_evmptr(vmx));
vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
@@ -4869,7 +4869,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
}
if ((vm_exit_reason != -1) &&
- (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)))
+ (enable_shadow_vmcs || evmptr_is_valid(nested_vmx_evmptr(vmx))))
vmx->nested.need_vmcs12_to_shadow_sync = true;
/* in case we halted in L2 */
@@ -5335,7 +5335,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
vmptr + offsetof(struct vmcs12,
launch_state),
&zero, sizeof(zero));
- } else if (vmx->nested.hv_evmcs && vmptr == vmx->nested.hv_evmcs_vmptr) {
+ } else if (vmx->nested.hv_evmcs && vmptr == nested_vmx_evmptr(vmx)) {
nested_release_evmcs(vcpu);
}
@@ -5375,7 +5375,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
/* Decode instruction info and find the field to read */
field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
- if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+ if (!evmptr_is_valid(nested_vmx_evmptr(vmx))) {
/*
* In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
* any VMREAD sets the ALU flags for VMfailInvalid.
@@ -5601,7 +5601,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER);
/* Forbid normal VMPTRLD if Enlightened version was used */
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
return 1;
if (vmx->nested.current_vmptr != vmptr) {
@@ -5664,7 +5664,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
if (!nested_vmx_check_permission(vcpu))
return 1;
- if (unlikely(evmptr_is_valid(to_vmx(vcpu)->nested.hv_evmcs_vmptr)))
+ if (unlikely(evmptr_is_valid(nested_vmx_evmptr(to_vmx(vcpu)))))
return 1;
if (get_vmx_mem_address(vcpu, exit_qual, instr_info,
@@ -6450,7 +6450,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
kvm_state.size += sizeof(user_vmx_nested_state->vmcs12);
/* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
- if (vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
+ if (nested_vmx_evmptr(vmx) != EVMPTR_INVALID)
kvm_state.flags |= KVM_STATE_NESTED_EVMCS;
if (is_guest_mode(vcpu) &&
@@ -6506,7 +6506,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
} else {
copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu));
if (!vmx->nested.need_vmcs12_to_shadow_sync) {
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
/*
* L1 hypervisor is not obliged to keep eVMCS
* clean fields data always up-to-date while
diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h
index b4b9d51438c6..b389312636e2 100644
--- a/arch/x86/kvm/vmx/nested.h
+++ b/arch/x86/kvm/vmx/nested.h
@@ -3,6 +3,7 @@
#define __KVM_X86_VMX_NESTED_H
#include "kvm_cache_regs.h"
+#include "hyperv.h"
#include "vmcs12.h"
#include "vmx.h"
@@ -57,7 +58,7 @@ static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu)
/* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
return vmx->nested.current_vmptr != -1ull ||
- vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID;
+ nested_vmx_evmptr(vmx) != EVMPTR_INVALID;
}
static inline u16 nested_get_vpid02(struct kvm_vcpu *vcpu)
--
2.41.0
'struct hv_vmcb_enlightenments' in VMCB only make sense when either
CONFIG_KVM_HYPERV or CONFIG_HYPERV is enabled.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/kvm/svm/nested.c | 20 ++++++++++++++------
arch/x86/kvm/svm/svm.h | 2 ++
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 4d8cd378a30b..5ae41a708005 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -187,7 +187,6 @@ void recalc_intercepts(struct vcpu_svm *svm)
*/
static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
{
- struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments;
int i;
/*
@@ -198,11 +197,16 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
* - Nested hypervisor (L1) is using Hyper-V emulation interface and
* tells KVM (L0) there were no changes in MSR bitmap for L2.
*/
- if (!svm->nested.force_msr_bitmap_recalc &&
- kvm_hv_hypercall_enabled(&svm->vcpu) &&
- hve->hv_enlightenments_control.msr_bitmap &&
- (svm->nested.ctl.clean & BIT(HV_VMCB_NESTED_ENLIGHTENMENTS)))
- goto set_msrpm_base_pa;
+#ifdef CONFIG_KVM_HYPERV
+ if (!svm->nested.force_msr_bitmap_recalc) {
+ struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments;
+
+ if (kvm_hv_hypercall_enabled(&svm->vcpu) &&
+ hve->hv_enlightenments_control.msr_bitmap &&
+ (svm->nested.ctl.clean & BIT(HV_VMCB_NESTED_ENLIGHTENMENTS)))
+ goto set_msrpm_base_pa;
+ }
+#endif
if (!(vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT)))
return true;
@@ -230,7 +234,9 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
svm->nested.force_msr_bitmap_recalc = false;
+#ifdef CONFIG_KVM_HYPERV
set_msrpm_base_pa:
+#endif
svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm));
return true;
@@ -378,12 +384,14 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
to->msrpm_base_pa &= ~0x0fffULL;
to->iopm_base_pa &= ~0x0fffULL;
+#ifdef CONFIG_KVM_HYPERV
/* Hyper-V extensions (Enlightened VMCB) */
if (kvm_hv_hypercall_enabled(vcpu)) {
to->clean = from->clean;
memcpy(&to->hv_enlightenments, &from->hv_enlightenments,
sizeof(to->hv_enlightenments));
}
+#endif
}
void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm,
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index be67ab7fdd10..59adff7bbf55 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -148,7 +148,9 @@ struct vmcb_ctrl_area_cached {
u64 virt_ext;
u32 clean;
union {
+#if IS_ENABLED(CONFIG_HYPERV) || IS_ENABLED(CONFIG_KVM_HYPERV)
struct hv_vmcb_enlightenments hv_enlightenments;
+#endif
u8 reserved_sw[32];
};
};
--
2.41.0
Hyper-V partition assist page is used when KVM runs on top of Hyper-V and
is not used for Windows/Hyper-V guests on KVM, this means that 'hv_pa_pg'
placement in 'struct kvm_hv' is unfortunate. As a preparation to making
Hyper-V emulation optional, move 'hv_pa_pg' to 'struct kvm_arch' and put it
under CONFIG_HYPERV.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/kvm/svm/svm_onhyperv.c | 2 +-
arch/x86/kvm/vmx/vmx.c | 2 +-
arch/x86/kvm/x86.c | 4 +++-
4 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index e5d4b8a44630..711dc880a9f0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1115,7 +1115,6 @@ struct kvm_hv {
*/
unsigned int synic_auto_eoi_used;
- struct hv_partition_assist_pg *hv_pa_pg;
struct kvm_hv_syndbg hv_syndbg;
};
@@ -1436,6 +1435,7 @@ struct kvm_arch {
#if IS_ENABLED(CONFIG_HYPERV)
hpa_t hv_root_tdp;
spinlock_t hv_root_tdp_lock;
+ struct hv_partition_assist_pg *hv_pa_pg;
#endif
/*
* VM-scope maximum vCPU ID. Used to determine the size of structures
diff --git a/arch/x86/kvm/svm/svm_onhyperv.c b/arch/x86/kvm/svm/svm_onhyperv.c
index 7af8422d3382..d19666f9b9ac 100644
--- a/arch/x86/kvm/svm/svm_onhyperv.c
+++ b/arch/x86/kvm/svm/svm_onhyperv.c
@@ -19,7 +19,7 @@ int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu)
{
struct hv_vmcb_enlightenments *hve;
struct hv_partition_assist_pg **p_hv_pa_pg =
- &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
+ &vcpu->kvm->arch.hv_pa_pg;
if (!*p_hv_pa_pg)
*p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL);
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 72e3943f3693..b7dc7acf14be 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -524,7 +524,7 @@ static int hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu)
{
struct hv_enlightened_vmcs *evmcs;
struct hv_partition_assist_pg **p_hv_pa_pg =
- &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
+ &vcpu->kvm->arch.hv_pa_pg;
/*
* Synthetic VM-Exit is not enabled in current code and so All
* evmcs in singe VM shares same assist page.
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 9f18b06bbda6..e273ce8e0b3f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -12291,7 +12291,9 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
void kvm_arch_free_vm(struct kvm *kvm)
{
- kfree(to_kvm_hv(kvm)->hv_pa_pg);
+#if IS_ENABLED(CONFIG_HYPERV)
+ kfree(kvm->arch.hv_pa_pg);
+#endif
__kvm_arch_free_vm(kvm);
}
--
2.41.0
As a preparation to making Hyper-V emulation optional, create a dedicated
kvm_hv_synic_has_vector() helper to avoid extra ifdefs in lapic.c.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/kvm/hyperv.h | 5 +++++
arch/x86/kvm/lapic.c | 3 +--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index 1897a219981d..ddb1d0b019e6 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -105,6 +105,11 @@ int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages);
+static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector)
+{
+ return to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->vec_bitmap);
+}
+
static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector)
{
return to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 0e80c1fdf899..37904c5d421b 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1475,8 +1475,7 @@ static int apic_set_eoi(struct kvm_lapic *apic)
apic_clear_isr(vector, apic);
apic_update_ppr(apic);
- if (to_hv_vcpu(apic->vcpu) &&
- test_bit(vector, to_hv_synic(apic->vcpu)->vec_bitmap))
+ if (kvm_hv_synic_has_vector(apic->vcpu, vector))
kvm_hv_synic_send_eoi(apic->vcpu, vector);
kvm_ioapic_send_eoi(apic, vector);
--
2.41.0
Saving a few bytes of memory per KVM VM is certainly great but what's more
important is the ability to see where the code accesses Xen emulation
context while CONFIG_KVM_XEN is not enabled. Currently, kvm_cpu_get_extint()
is the only such place and it is harmless: kvm_xen_has_interrupt() always
returns '0' when !CONFIG_KVM_XEN.
No functional change intended.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/include/asm/kvm_host.h | 5 +++++
arch/x86/kvm/irq.c | 2 ++
2 files changed, 7 insertions(+)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 17715cb8731d..e5d4b8a44630 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1126,6 +1126,7 @@ struct msr_bitmap_range {
unsigned long *bitmap;
};
+#ifdef CONFIG_KVM_XEN
/* Xen emulation context */
struct kvm_xen {
struct mutex xen_lock;
@@ -1137,6 +1138,7 @@ struct kvm_xen {
struct idr evtchn_ports;
unsigned long poll_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
};
+#endif
enum kvm_irqchip_mode {
KVM_IRQCHIP_NONE,
@@ -1338,7 +1340,10 @@ struct kvm_arch {
struct hlist_head mask_notifier_list;
struct kvm_hv hyperv;
+
+#ifdef CONFIG_KVM_XEN
struct kvm_xen xen;
+#endif
bool backwards_tsc_observed;
bool boot_vcpu_runs_old_kvmclock;
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index b2c397dd2bc6..ad9ca8a60144 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -118,8 +118,10 @@ static int kvm_cpu_get_extint(struct kvm_vcpu *v)
if (!lapic_in_kernel(v))
return v->arch.interrupt.nr;
+#ifdef CONFIG_KVM_XEN
if (kvm_xen_has_interrupt(v))
return v->kvm->arch.xen.upcall_vector;
+#endif
if (irqchip_split(v->kvm)) {
int vector = v->arch.pending_external_vector;
--
2.41.0
Hyper-V emulation in KVM is a fairly big chunk and in some cases it may be
desirable to not compile it in to reduce module sizes as well as attack
surface. Introduce CONFIG_KVM_HYPERV option to make it possible.
Note, there's room for further nVMX/nSVM code optimizations when
!CONFIG_KVM_HYPERV, this will be done in follow-up patches.
Signed-off-by: Vitaly Kuznetsov <[email protected]>
---
arch/x86/include/asm/kvm_host.h | 4 +++
arch/x86/kvm/Kconfig | 9 ++++++
arch/x86/kvm/Makefile | 17 +++++++---
arch/x86/kvm/cpuid.c | 6 ++++
arch/x86/kvm/hyperv.h | 29 +++++++++++++++--
arch/x86/kvm/irq_comm.c | 9 +++++-
arch/x86/kvm/svm/hyperv.h | 7 +++++
arch/x86/kvm/svm/nested.c | 2 ++
arch/x86/kvm/svm/svm_onhyperv.h | 2 ++
arch/x86/kvm/vmx/hyperv.h | 8 +++++
arch/x86/kvm/vmx/nested.c | 17 ++++++++++
arch/x86/kvm/x86.c | 56 +++++++++++++++++++++++----------
12 files changed, 143 insertions(+), 23 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 711dc880a9f0..b0a55b736b47 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1085,6 +1085,7 @@ enum hv_tsc_page_status {
HV_TSC_PAGE_BROKEN,
};
+#ifdef CONFIG_KVM_HYPERV
/* Hyper-V emulation context */
struct kvm_hv {
struct mutex hv_lock;
@@ -1117,6 +1118,7 @@ struct kvm_hv {
struct kvm_hv_syndbg hv_syndbg;
};
+#endif
struct msr_bitmap_range {
u32 flags;
@@ -1338,7 +1340,9 @@ struct kvm_arch {
/* reads protected by irq_srcu, writes by irq_lock */
struct hlist_head mask_notifier_list;
+#ifdef CONFIG_KVM_HYPERV
struct kvm_hv hyperv;
+#endif
#ifdef CONFIG_KVM_XEN
struct kvm_xen xen;
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index ed90f148140d..a06e19a8a8f6 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -129,6 +129,15 @@ config KVM_SMM
If unsure, say Y.
+config KVM_HYPERV
+ bool "Support for Microsoft Hyper-V emulation"
+ depends on KVM
+ default y
+ help
+ Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
+
+ If unsure, say "Y".
+
config KVM_XEN
bool "Support for Xen hypercall interface"
depends on KVM
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index 8ea872401cd6..ccd477178f07 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -11,7 +11,7 @@ include $(srctree)/virt/kvm/Makefile.kvm
kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \
i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
- hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \
+ debugfs.o mmu/mmu.o mmu/page_track.o \
mmu/spte.o
ifdef CONFIG_HYPERV
@@ -19,19 +19,28 @@ kvm-y += kvm_onhyperv.o
endif
kvm-$(CONFIG_X86_64) += mmu/tdp_iter.o mmu/tdp_mmu.o
+kvm-$(CONFIG_KVM_HYPERV) += hyperv.o
kvm-$(CONFIG_KVM_XEN) += xen.o
kvm-$(CONFIG_KVM_SMM) += smm.o
kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
- vmx/hyperv.o vmx/hyperv_evmcs.o vmx/nested.o vmx/posted_intr.o
+ vmx/nested.o vmx/posted_intr.o
+ifdef CONFIG_KVM_HYPERV
+kvm-intel-y += vmx/hyperv.o vmx/hyperv_evmcs.o
+endif
+
kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
ifdef CONFIG_HYPERV
-kvm-intel-y += vmx/vmx_onhyperv.o
+kvm-intel-y += vmx/vmx_onhyperv.o vmx/hyperv_evmcs.o
endif
kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \
- svm/sev.o svm/hyperv.o
+ svm/sev.o
+
+ifdef CONFIG_KVM_HYPERV
+kvm-amd-y += svm/hyperv.o
+endif
ifdef CONFIG_HYPERV
kvm-amd-y += svm/svm_onhyperv.o
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 0544e30b4946..7a3533573f94 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -314,11 +314,15 @@ EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime);
static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent)
{
+#ifdef CONFIG_KVM_HYPERV
struct kvm_cpuid_entry2 *entry;
entry = cpuid_entry2_find(entries, nent, HYPERV_CPUID_INTERFACE,
KVM_CPUID_INDEX_NOT_SIGNIFICANT);
return entry && entry->eax == HYPERV_CPUID_SIGNATURE_EAX;
+#else
+ return false;
+#endif
}
static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
@@ -441,11 +445,13 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
return 0;
}
+#ifdef CONFIG_KVM_HYPERV
if (kvm_cpuid_has_hyperv(e2, nent)) {
r = kvm_hv_vcpu_init(vcpu);
if (r)
return r;
}
+#endif
r = kvm_check_cpuid(vcpu, e2, nent);
if (r)
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index ddb1d0b019e6..3a6acd8a9fa8 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -24,6 +24,8 @@
#include <linux/kvm_host.h>
#include "x86.h"
+#ifdef CONFIG_KVM_HYPERV
+
/* "Hv#1" signature */
#define HYPERV_CPUID_SIGNATURE_EAX 0x31237648
@@ -247,5 +249,28 @@ static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu)
}
int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu);
-
-#endif
+#else /* CONFIG_KVM_HYPERV */
+static inline void kvm_hv_setup_tsc_page(struct kvm *kvm,
+ struct pvclock_vcpu_time_info *hv_clock) {}
+static inline void kvm_hv_request_tsc_page_update(struct kvm *kvm) {}
+static inline void kvm_hv_init_vm(struct kvm *kvm) {}
+static inline void kvm_hv_destroy_vm(struct kvm *kvm) {}
+static inline int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu) { return 0; }
+static inline void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu) {}
+static inline bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu) { return false; }
+static inline int kvm_hv_hypercall(struct kvm_vcpu *vcpu) { return HV_STATUS_ACCESS_DENIED; }
+static inline void kvm_hv_vcpu_purge_flush_tlb(struct kvm_vcpu *vcpu) {}
+static inline void kvm_hv_free_pa_page(struct kvm *kvm) {}
+static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector) { return false; }
+static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector) { return false; }
+static inline void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector) {}
+static inline bool kvm_hv_invtsc_suppressed(struct kvm_vcpu *vcpu) { return false; }
+static inline void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu, bool hyperv_enabled) {}
+static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu) { return false; }
+static inline bool kvm_hv_is_tlb_flush_hcall(struct kvm_vcpu *vcpu) { return false; }
+static inline bool guest_hv_cpuid_has_l2_tlb_flush(struct kvm_vcpu *vcpu) { return false; }
+static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu) { return 0; }
+static inline u32 kvm_hv_get_vpindex(struct kvm_vcpu *vcpu) { return vcpu->vcpu_idx; }
+#endif /* CONFIG_KVM_HYPERV */
+
+#endif /* __ARCH_X86_KVM_HYPERV_H__ */
diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
index 16d076a1b91a..68f3f6c26046 100644
--- a/arch/x86/kvm/irq_comm.c
+++ b/arch/x86/kvm/irq_comm.c
@@ -144,7 +144,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
return kvm_irq_delivery_to_apic(kvm, NULL, &irq, NULL);
}
-
+#ifdef CONFIG_KVM_HYPERV
static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level,
bool line_status)
@@ -154,6 +154,7 @@ static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
}
+#endif
int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level,
@@ -163,9 +164,11 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
int r;
switch (e->type) {
+#ifdef CONFIG_KVM_HYPERV
case KVM_IRQ_ROUTING_HV_SINT:
return kvm_hv_set_sint(e, kvm, irq_source_id, level,
line_status);
+#endif
case KVM_IRQ_ROUTING_MSI:
if (kvm_msi_route_invalid(kvm, e))
@@ -314,11 +317,13 @@ int kvm_set_routing_entry(struct kvm *kvm,
if (kvm_msi_route_invalid(kvm, e))
return -EINVAL;
break;
+#ifdef CONFIG_KVM_HYPERV
case KVM_IRQ_ROUTING_HV_SINT:
e->set = kvm_hv_set_sint;
e->hv_sint.vcpu = ue->u.hv_sint.vcpu;
e->hv_sint.sint = ue->u.hv_sint.sint;
break;
+#endif
#ifdef CONFIG_KVM_XEN
case KVM_IRQ_ROUTING_XEN_EVTCHN:
return kvm_xen_setup_evtchn(kvm, e, ue);
@@ -438,5 +443,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
void kvm_arch_irq_routing_update(struct kvm *kvm)
{
+#ifdef CONFIG_KVM_HYPERV
kvm_hv_irq_routing_update(kvm);
+#endif
}
diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h
index 02f4784b5d44..14eec2d9b6be 100644
--- a/arch/x86/kvm/svm/hyperv.h
+++ b/arch/x86/kvm/svm/hyperv.h
@@ -11,6 +11,7 @@
#include "../hyperv.h"
#include "svm.h"
+#ifdef CONFIG_KVM_HYPERV
static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -41,5 +42,11 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
}
void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
+#else /* CONFIG_KVM_HYPERV */
+static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {}
+static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
+static inline void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu) {}
+#endif /* CONFIG_KVM_HYPERV */
+
#endif /* __ARCH_X86_KVM_SVM_HYPERV_H__ */
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index dd496c9e5f91..4d8cd378a30b 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -487,6 +487,7 @@ static void nested_save_pending_event_to_vmcb12(struct vcpu_svm *svm,
static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
{
+#ifdef CONFIG_KVM_HYPERV
/*
* KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
* L2's VP_ID upon request from the guest. Make sure we check for
@@ -495,6 +496,7 @@ static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
*/
if (to_hv_vcpu(vcpu) && npt_enabled)
kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
+#endif
/*
* TODO: optimize unconditional TLB flush/MMU sync. A partial list of
diff --git a/arch/x86/kvm/svm/svm_onhyperv.h b/arch/x86/kvm/svm/svm_onhyperv.h
index f85bc617ffe4..c25cf56e6adb 100644
--- a/arch/x86/kvm/svm/svm_onhyperv.h
+++ b/arch/x86/kvm/svm/svm_onhyperv.h
@@ -79,6 +79,7 @@ static inline void svm_hv_vmcb_dirty_nested_enlightenments(
static inline void svm_hv_update_vp_id(struct vmcb *vmcb, struct kvm_vcpu *vcpu)
{
+#ifdef CONFIG_KVM_HYPERV
struct hv_vmcb_enlightenments *hve = &vmcb->control.hv_enlightenments;
u32 vp_index = kvm_hv_get_vpindex(vcpu);
@@ -86,6 +87,7 @@ static inline void svm_hv_update_vp_id(struct vmcb *vmcb, struct kvm_vcpu *vcpu)
hve->hv_vp_id = vp_index;
vmcb_mark_dirty(vmcb, HV_VMCB_NESTED_ENLIGHTENMENTS);
}
+#endif
}
#else
diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
index d4ed99008518..933ef6cad5e6 100644
--- a/arch/x86/kvm/vmx/hyperv.h
+++ b/arch/x86/kvm/vmx/hyperv.h
@@ -20,6 +20,7 @@ enum nested_evmptrld_status {
EVMPTRLD_ERROR,
};
+#ifdef CONFIG_KVM_HYPERV
u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
@@ -28,5 +29,12 @@ void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *
int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
+#else
+static inline u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { return EVMPTR_INVALID; }
+static inline void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) {}
+static inline bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
+static inline int nested_evmcs_check_controls(struct vmcs12 *vmcs12) { return 0; }
+#endif
+
#endif /* __KVM_X86_VMX_HYPERV_H */
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index c5ec0ef51ff7..ca7e06759aa3 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -226,6 +226,7 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx)
static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
{
+#ifdef CONFIG_KVM_HYPERV
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -241,6 +242,7 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
hv_vcpu->nested.vm_id = 0;
hv_vcpu->nested.vp_id = 0;
}
+#endif
}
static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx,
@@ -1139,6 +1141,7 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+#ifdef CONFIG_KVM_HYPERV
/*
* KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
* L2's VP_ID upon request from the guest. Make sure we check for
@@ -1147,6 +1150,7 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
*/
if (to_hv_vcpu(vcpu) && enable_ept)
kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
+#endif
/*
* If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
@@ -1576,6 +1580,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
vmcs_load(vmx->loaded_vmcs->vmcs);
}
+#ifdef CONFIG_KVM_HYPERV
static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
{
struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
@@ -2083,6 +2088,10 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
return EVMPTRLD_SUCCEEDED;
}
+#else /* CONFIG_KVM_HYPERV */
+static inline void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields) {}
+static inline void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx) {}
+#endif /* CONFIG_KVM_HYPERV */
void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
{
@@ -3161,6 +3170,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
return 0;
}
+#ifdef CONFIG_KVM_HYPERV
static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -3188,6 +3198,9 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
return true;
}
+#else
+static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu) { return true; }
+#endif
static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
{
@@ -3558,11 +3571,13 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
if (!nested_vmx_check_permission(vcpu))
return 1;
+#ifdef CONFIG_KVM_HYPERV
evmptrld_status = nested_vmx_handle_enlightened_vmptrld(vcpu, launch);
if (evmptrld_status == EVMPTRLD_ERROR) {
kvm_queue_exception(vcpu, UD_VECTOR);
return 1;
}
+#endif
kvm_pmu_trigger_event(vcpu, PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
@@ -7096,7 +7111,9 @@ struct kvm_x86_nested_ops vmx_nested_ops = {
.set_state = vmx_set_nested_state,
.get_nested_state_pages = vmx_get_nested_state_pages,
.write_log_dirty = nested_vmx_write_pml_buffer,
+#ifdef CONFIG_KVM_HYPERV
.enable_evmcs = nested_enable_evmcs,
.get_evmcs_version = nested_get_evmcs_version,
.hv_inject_synthetic_vmexit_post_tlb_flush = vmx_hv_inject_synthetic_vmexit_post_tlb_flush,
+#endif
};
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e273ce8e0b3f..78e18d28bc61 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1504,6 +1504,8 @@ static unsigned num_msrs_to_save;
static const u32 emulated_msrs_all[] = {
MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
+
+#ifdef CONFIG_KVM_HYPERV
HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC,
HV_X64_MSR_TSC_FREQUENCY, HV_X64_MSR_APIC_FREQUENCY,
@@ -1521,6 +1523,7 @@ static const u32 emulated_msrs_all[] = {
HV_X64_MSR_SYNDBG_CONTROL, HV_X64_MSR_SYNDBG_STATUS,
HV_X64_MSR_SYNDBG_SEND_BUFFER, HV_X64_MSR_SYNDBG_RECV_BUFFER,
HV_X64_MSR_SYNDBG_PENDING_BUFFER,
+#endif
MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
MSR_KVM_PV_EOI_EN, MSR_KVM_ASYNC_PF_INT, MSR_KVM_ASYNC_PF_ACK,
@@ -3914,6 +3917,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
* the need to ignore the workaround.
*/
break;
+#ifdef CONFIG_KVM_HYPERV
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
case HV_X64_MSR_SYNDBG_OPTIONS:
@@ -3926,6 +3930,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case HV_X64_MSR_TSC_INVARIANT_CONTROL:
return kvm_hv_set_msr_common(vcpu, msr, data,
msr_info->host_initiated);
+#endif
case MSR_IA32_BBL_CR_CTL3:
/* Drop writes to this legacy MSR -- see rdmsr
* counterpart for further detail.
@@ -4270,6 +4275,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
*/
msr_info->data = 0x20000000;
break;
+#ifdef CONFIG_KVM_HYPERV
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
case HV_X64_MSR_SYNDBG_OPTIONS:
@@ -4283,6 +4289,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return kvm_hv_get_msr_common(vcpu,
msr_info->index, &msr_info->data,
msr_info->host_initiated);
+#endif
case MSR_IA32_BBL_CR_CTL3:
/* This legacy MSR exists but isn't fully documented in current
* silicon. It is however accessed by winxp in very narrow
@@ -4420,6 +4427,7 @@ static inline bool kvm_can_mwait_in_guest(void)
boot_cpu_has(X86_FEATURE_ARAT);
}
+#ifdef CONFIG_KVM_HYPERV
static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
struct kvm_cpuid2 __user *cpuid_arg)
{
@@ -4440,6 +4448,7 @@ static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
return 0;
}
+#endif
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
{
@@ -4764,9 +4773,11 @@ long kvm_arch_dev_ioctl(struct file *filp,
case KVM_GET_MSRS:
r = msr_io(NULL, argp, do_get_msr_feature, 1);
break;
+#ifdef CONFIG_KVM_HYPERV
case KVM_GET_SUPPORTED_HV_CPUID:
r = kvm_ioctl_get_supported_hv_cpuid(NULL, argp);
break;
+#endif
case KVM_GET_DEVICE_ATTR: {
struct kvm_device_attr attr;
r = -EFAULT;
@@ -5580,14 +5591,11 @@ static int kvm_vcpu_ioctl_device_attr(struct kvm_vcpu *vcpu,
static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
struct kvm_enable_cap *cap)
{
- int r;
- uint16_t vmcs_version;
- void __user *user_ptr;
-
if (cap->flags)
return -EINVAL;
switch (cap->cap) {
+#ifdef CONFIG_KVM_HYPERV
case KVM_CAP_HYPERV_SYNIC2:
if (cap->args[0])
return -EINVAL;
@@ -5599,16 +5607,22 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
return kvm_hv_activate_synic(vcpu, cap->cap ==
KVM_CAP_HYPERV_SYNIC2);
case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
- if (!kvm_x86_ops.nested_ops->enable_evmcs)
- return -ENOTTY;
- r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
- if (!r) {
- user_ptr = (void __user *)(uintptr_t)cap->args[0];
- if (copy_to_user(user_ptr, &vmcs_version,
- sizeof(vmcs_version)))
- r = -EFAULT;
+ {
+ int r;
+ uint16_t vmcs_version;
+ void __user *user_ptr;
+
+ if (!kvm_x86_ops.nested_ops->enable_evmcs)
+ return -ENOTTY;
+ r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
+ if (!r) {
+ user_ptr = (void __user *)(uintptr_t)cap->args[0];
+ if (copy_to_user(user_ptr, &vmcs_version,
+ sizeof(vmcs_version)))
+ r = -EFAULT;
+ }
+ return r;
}
- return r;
case KVM_CAP_HYPERV_DIRECT_TLBFLUSH:
if (!kvm_x86_ops.enable_l2_tlb_flush)
return -ENOTTY;
@@ -5617,6 +5631,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
case KVM_CAP_HYPERV_ENFORCE_CPUID:
return kvm_hv_set_enforce_cpuid(vcpu, cap->args[0]);
+#endif
case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
vcpu->arch.pv_cpuid.enforce = cap->args[0];
@@ -6009,9 +6024,11 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
srcu_read_unlock(&vcpu->kvm->srcu, idx);
break;
}
+#ifdef CONFIG_KVM_HYPERV
case KVM_GET_SUPPORTED_HV_CPUID:
r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp);
break;
+#endif
#ifdef CONFIG_KVM_XEN
case KVM_XEN_VCPU_GET_ATTR: {
struct kvm_xen_vcpu_attr xva;
@@ -7066,6 +7083,7 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
r = static_call(kvm_x86_mem_enc_unregister_region)(kvm, ®ion);
break;
}
+#ifdef CONFIG_KVM_HYPERV
case KVM_HYPERV_EVENTFD: {
struct kvm_hyperv_eventfd hvevfd;
@@ -7075,6 +7093,7 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd);
break;
}
+#endif
case KVM_SET_PMU_EVENT_FILTER:
r = kvm_vm_ioctl_set_pmu_event_filter(kvm, argp);
break;
@@ -10445,19 +10464,20 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
{
- u64 eoi_exit_bitmap[4];
-
if (!kvm_apic_hw_enabled(vcpu->arch.apic))
return;
+#ifdef CONFIG_KVM_HYPERV
if (to_hv_vcpu(vcpu)) {
+ u64 eoi_exit_bitmap[4];
+
bitmap_or((ulong *)eoi_exit_bitmap,
vcpu->arch.ioapic_handled_vectors,
to_hv_synic(vcpu)->vec_bitmap, 256);
static_call_cond(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap);
return;
}
-
+#endif
static_call_cond(kvm_x86_load_eoi_exitmap)(
vcpu, (u64 *)vcpu->arch.ioapic_handled_vectors);
}
@@ -10548,9 +10568,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
* the flushes are considered "remote" and not "local" because
* the requests can be initiated from other vCPUs.
*/
+#ifdef CONFIG_KVM_HYPERV
if (kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu) &&
kvm_hv_vcpu_flush_tlb(vcpu))
kvm_vcpu_flush_tlb_guest(vcpu);
+#endif
if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
@@ -10603,6 +10625,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
vcpu_load_eoi_exitmap(vcpu);
if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
kvm_vcpu_reload_apic_access_page(vcpu);
+#ifdef CONFIG_KVM_HYPERV
if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH;
@@ -10633,6 +10656,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
*/
if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
kvm_hv_process_stimers(vcpu);
+#endif
if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
kvm_vcpu_update_apicv(vcpu);
if (kvm_check_request(KVM_REQ_APF_READY, vcpu))
--
2.41.0
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> Saving a few bytes of memory per KVM VM is certainly great but what's more
> important is the ability to see where the code accesses Xen emulation
> context while CONFIG_KVM_XEN is not enabled. Currently, kvm_cpu_get_extint()
> is the only such place and it is harmless: kvm_xen_has_interrupt() always
> returns '0' when !CONFIG_KVM_XEN.
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/include/asm/kvm_host.h | 5 +++++
> arch/x86/kvm/irq.c | 2 ++
> 2 files changed, 7 insertions(+)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 17715cb8731d..e5d4b8a44630 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1126,6 +1126,7 @@ struct msr_bitmap_range {
> unsigned long *bitmap;
> };
>
> +#ifdef CONFIG_KVM_XEN
> /* Xen emulation context */
> struct kvm_xen {
> struct mutex xen_lock;
> @@ -1137,6 +1138,7 @@ struct kvm_xen {
> struct idr evtchn_ports;
> unsigned long poll_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
> };
> +#endif
>
> enum kvm_irqchip_mode {
> KVM_IRQCHIP_NONE,
> @@ -1338,7 +1340,10 @@ struct kvm_arch {
> struct hlist_head mask_notifier_list;
>
> struct kvm_hv hyperv;
> +
> +#ifdef CONFIG_KVM_XEN
> struct kvm_xen xen;
> +#endif
>
> bool backwards_tsc_observed;
> bool boot_vcpu_runs_old_kvmclock;
> diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
> index b2c397dd2bc6..ad9ca8a60144 100644
> --- a/arch/x86/kvm/irq.c
> +++ b/arch/x86/kvm/irq.c
> @@ -118,8 +118,10 @@ static int kvm_cpu_get_extint(struct kvm_vcpu *v)
> if (!lapic_in_kernel(v))
> return v->arch.interrupt.nr;
>
> +#ifdef CONFIG_KVM_XEN
> if (kvm_xen_has_interrupt(v))
> return v->kvm->arch.xen.upcall_vector;
> +#endif
>
> if (irqchip_split(v->kvm)) {
> int vector = v->arch.pending_external_vector;
Reviewed-by: Maxim Levitsky <[email protected]>
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> Hyper-V partition assist page is used when KVM runs on top of Hyper-V and
> is not used for Windows/Hyper-V guests on KVM, this means that 'hv_pa_pg'
> placement in 'struct kvm_hv' is unfortunate. As a preparation to making
> Hyper-V emulation optional, move 'hv_pa_pg' to 'struct kvm_arch' and put it
> under CONFIG_HYPERV.
It took me a while to realize that this parition assist page is indeed something that L0,
running above KVM consumes.
(what a confusing name Microsoft picked...)
As far as I know currently the partition assist page has only
one shared memory variable which allows L1 to be notified of direct TLB flushes that L0 does for L2,
but since KVM doesn't need it, it
never touches this variable/page,
but specs still demand that L1 does allocate that page.
If you agree, it would be great to add a large comment to the code,
explaining the above, and fact that the partition assist page
is something L1 exposes to L0.
I don't know though where to put the comment
because hv_enable_l2_tlb_flush is duplicated between SVM and VMX.
It might be a good idea to have a helper function to allocate the partition assist page,
which will both reduce the code duplication slightly and allow us to put this comment there.
Best regards,
Maxim Levitsky
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/include/asm/kvm_host.h | 2 +-
> arch/x86/kvm/svm/svm_onhyperv.c | 2 +-
> arch/x86/kvm/vmx/vmx.c | 2 +-
> arch/x86/kvm/x86.c | 4 +++-
> 4 files changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index e5d4b8a44630..711dc880a9f0 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1115,7 +1115,6 @@ struct kvm_hv {
> */
> unsigned int synic_auto_eoi_used;
>
> - struct hv_partition_assist_pg *hv_pa_pg;
> struct kvm_hv_syndbg hv_syndbg;
> };
>
> @@ -1436,6 +1435,7 @@ struct kvm_arch {
> #if IS_ENABLED(CONFIG_HYPERV)
> hpa_t hv_root_tdp;
> spinlock_t hv_root_tdp_lock;
> + struct hv_partition_assist_pg *hv_pa_pg;
> #endif
> /*
> * VM-scope maximum vCPU ID. Used to determine the size of structures
> diff --git a/arch/x86/kvm/svm/svm_onhyperv.c b/arch/x86/kvm/svm/svm_onhyperv.c
> index 7af8422d3382..d19666f9b9ac 100644
> --- a/arch/x86/kvm/svm/svm_onhyperv.c
> +++ b/arch/x86/kvm/svm/svm_onhyperv.c
> @@ -19,7 +19,7 @@ int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu)
> {
> struct hv_vmcb_enlightenments *hve;
> struct hv_partition_assist_pg **p_hv_pa_pg =
> - &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
> + &vcpu->kvm->arch.hv_pa_pg;
>
> if (!*p_hv_pa_pg)
> *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL);
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 72e3943f3693..b7dc7acf14be 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -524,7 +524,7 @@ static int hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu)
> {
> struct hv_enlightened_vmcs *evmcs;
> struct hv_partition_assist_pg **p_hv_pa_pg =
> - &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
> + &vcpu->kvm->arch.hv_pa_pg;
> /*
> * Synthetic VM-Exit is not enabled in current code and so All
> * evmcs in singe VM shares same assist page.
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 9f18b06bbda6..e273ce8e0b3f 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -12291,7 +12291,9 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
>
> void kvm_arch_free_vm(struct kvm *kvm)
> {
> - kfree(to_kvm_hv(kvm)->hv_pa_pg);
> +#if IS_ENABLED(CONFIG_HYPERV)
> + kfree(kvm->arch.hv_pa_pg);
> +#endif
> __kvm_arch_free_vm(kvm);
> }
>
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> As a preparation to making Hyper-V emulation optional, create a dedicated
> kvm_hv_synic_auto_eoi_set() helper to avoid extra ifdefs in lapic.c
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/kvm/hyperv.h | 5 +++++
> arch/x86/kvm/lapic.c | 2 +-
> 2 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
> index f83b8db72b11..1897a219981d 100644
> --- a/arch/x86/kvm/hyperv.h
> +++ b/arch/x86/kvm/hyperv.h
> @@ -105,6 +105,11 @@ int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
> void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
> int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages);
>
> +static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector)
> +{
> + return to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap);
> +}
> +
> void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
>
> bool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu);
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index dcd60b39e794..0e80c1fdf899 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -2899,7 +2899,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
> */
>
> apic_clear_irr(vector, apic);
> - if (to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap)) {
> + if (kvm_hv_synic_auto_eoi_set(vcpu, vector)) {
> /*
> * For auto-EOI interrupts, there might be another pending
> * interrupt above PPR, so check whether to raise another
Reviewed-by: Maxim Levitsky <[email protected]>
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> hyperv.{ch} is currently a mix of stuff which is needed by both Hyper-V on
> KVM and KVM on Hyper-V. As a preparation to making Hyper-V emulation
> optional, put KVM-on-Hyper-V specific code into dedicated files.
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/kvm/Makefile | 4 +
> arch/x86/kvm/vmx/hyperv.c | 139 --------------------
> arch/x86/kvm/vmx/hyperv.h | 217 ++++++++++++++++----------------
> arch/x86/kvm/vmx/vmx.c | 1 +
> arch/x86/kvm/vmx/vmx_onhyperv.c | 36 ++++++
> arch/x86/kvm/vmx/vmx_onhyperv.h | 124 ++++++++++++++++++
> arch/x86/kvm/vmx/vmx_ops.h | 2 +-
> 7 files changed, 271 insertions(+), 252 deletions(-)
> create mode 100644 arch/x86/kvm/vmx/vmx_onhyperv.c
> create mode 100644 arch/x86/kvm/vmx/vmx_onhyperv.h
>
> diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
> index 80e3fe184d17..a99ffc3f3a3f 100644
> --- a/arch/x86/kvm/Makefile
> +++ b/arch/x86/kvm/Makefile
> @@ -26,6 +26,10 @@ kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
> vmx/hyperv.o vmx/nested.o vmx/posted_intr.o
> kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
>
> +ifdef CONFIG_HYPERV
> +kvm-intel-y += vmx/vmx_onhyperv.o
> +endif
> +
> kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \
> svm/sev.o svm/hyperv.o
>
> diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c
> index 313b8bb5b8a7..de13dc14fe1d 100644
> --- a/arch/x86/kvm/vmx/hyperv.c
> +++ b/arch/x86/kvm/vmx/hyperv.c
> @@ -13,111 +13,6 @@
>
> #define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK
>
> -/*
> - * Enlightened VMCSv1 doesn't support these:
> - *
> - * POSTED_INTR_NV = 0x00000002,
> - * GUEST_INTR_STATUS = 0x00000810,
> - * APIC_ACCESS_ADDR = 0x00002014,
> - * POSTED_INTR_DESC_ADDR = 0x00002016,
> - * EOI_EXIT_BITMAP0 = 0x0000201c,
> - * EOI_EXIT_BITMAP1 = 0x0000201e,
> - * EOI_EXIT_BITMAP2 = 0x00002020,
> - * EOI_EXIT_BITMAP3 = 0x00002022,
> - * GUEST_PML_INDEX = 0x00000812,
> - * PML_ADDRESS = 0x0000200e,
> - * VM_FUNCTION_CONTROL = 0x00002018,
> - * EPTP_LIST_ADDRESS = 0x00002024,
> - * VMREAD_BITMAP = 0x00002026,
> - * VMWRITE_BITMAP = 0x00002028,
> - *
> - * TSC_MULTIPLIER = 0x00002032,
> - * PLE_GAP = 0x00004020,
> - * PLE_WINDOW = 0x00004022,
> - * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
> - *
> - * Currently unsupported in KVM:
> - * GUEST_IA32_RTIT_CTL = 0x00002814,
> - */
> -#define EVMCS1_SUPPORTED_PINCTRL \
> - (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
> - PIN_BASED_EXT_INTR_MASK | \
> - PIN_BASED_NMI_EXITING | \
> - PIN_BASED_VIRTUAL_NMIS)
> -
> -#define EVMCS1_SUPPORTED_EXEC_CTRL \
> - (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
> - CPU_BASED_HLT_EXITING | \
> - CPU_BASED_CR3_LOAD_EXITING | \
> - CPU_BASED_CR3_STORE_EXITING | \
> - CPU_BASED_UNCOND_IO_EXITING | \
> - CPU_BASED_MOV_DR_EXITING | \
> - CPU_BASED_USE_TSC_OFFSETTING | \
> - CPU_BASED_MWAIT_EXITING | \
> - CPU_BASED_MONITOR_EXITING | \
> - CPU_BASED_INVLPG_EXITING | \
> - CPU_BASED_RDPMC_EXITING | \
> - CPU_BASED_INTR_WINDOW_EXITING | \
> - CPU_BASED_CR8_LOAD_EXITING | \
> - CPU_BASED_CR8_STORE_EXITING | \
> - CPU_BASED_RDTSC_EXITING | \
> - CPU_BASED_TPR_SHADOW | \
> - CPU_BASED_USE_IO_BITMAPS | \
> - CPU_BASED_MONITOR_TRAP_FLAG | \
> - CPU_BASED_USE_MSR_BITMAPS | \
> - CPU_BASED_NMI_WINDOW_EXITING | \
> - CPU_BASED_PAUSE_EXITING | \
> - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
> -
> -#define EVMCS1_SUPPORTED_2NDEXEC \
> - (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
> - SECONDARY_EXEC_WBINVD_EXITING | \
> - SECONDARY_EXEC_ENABLE_VPID | \
> - SECONDARY_EXEC_ENABLE_EPT | \
> - SECONDARY_EXEC_UNRESTRICTED_GUEST | \
> - SECONDARY_EXEC_DESC | \
> - SECONDARY_EXEC_ENABLE_RDTSCP | \
> - SECONDARY_EXEC_ENABLE_INVPCID | \
> - SECONDARY_EXEC_ENABLE_XSAVES | \
> - SECONDARY_EXEC_RDSEED_EXITING | \
> - SECONDARY_EXEC_RDRAND_EXITING | \
> - SECONDARY_EXEC_TSC_SCALING | \
> - SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
> - SECONDARY_EXEC_PT_USE_GPA | \
> - SECONDARY_EXEC_PT_CONCEAL_VMX | \
> - SECONDARY_EXEC_BUS_LOCK_DETECTION | \
> - SECONDARY_EXEC_NOTIFY_VM_EXITING | \
> - SECONDARY_EXEC_ENCLS_EXITING)
> -
> -#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
> -
> -#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
> - (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
> - VM_EXIT_SAVE_DEBUG_CONTROLS | \
> - VM_EXIT_ACK_INTR_ON_EXIT | \
> - VM_EXIT_HOST_ADDR_SPACE_SIZE | \
> - VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
> - VM_EXIT_SAVE_IA32_PAT | \
> - VM_EXIT_LOAD_IA32_PAT | \
> - VM_EXIT_SAVE_IA32_EFER | \
> - VM_EXIT_LOAD_IA32_EFER | \
> - VM_EXIT_CLEAR_BNDCFGS | \
> - VM_EXIT_PT_CONCEAL_PIP | \
> - VM_EXIT_CLEAR_IA32_RTIT_CTL)
> -
> -#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
> - (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
> - VM_ENTRY_LOAD_DEBUG_CONTROLS | \
> - VM_ENTRY_IA32E_MODE | \
> - VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
> - VM_ENTRY_LOAD_IA32_PAT | \
> - VM_ENTRY_LOAD_IA32_EFER | \
> - VM_ENTRY_LOAD_BNDCFGS | \
> - VM_ENTRY_PT_CONCEAL_PIP | \
> - VM_ENTRY_LOAD_IA32_RTIT_CTL)
> -
> -#define EVMCS1_SUPPORTED_VMFUNC (0)
> -
> #define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
> #define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
> {EVMCS1_OFFSET(name), clean_field}
> @@ -608,40 +503,6 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
> return 0;
> }
>
> -#if IS_ENABLED(CONFIG_HYPERV)
> -DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
> -
> -/*
> - * 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)
> -
> -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)
> {
> diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
> index 9623fe1651c4..9401dbfaea7c 100644
> --- a/arch/x86/kvm/vmx/hyperv.h
> +++ b/arch/x86/kvm/vmx/hyperv.h
> @@ -14,12 +14,113 @@
> #include "vmcs.h"
> #include "vmcs12.h"
>
> -struct vmcs_config;
> -
> -#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
> -
> #define KVM_EVMCS_VERSION 1
>
> +/*
> + * Enlightened VMCSv1 doesn't support these:
> + *
> + * POSTED_INTR_NV = 0x00000002,
> + * GUEST_INTR_STATUS = 0x00000810,
> + * APIC_ACCESS_ADDR = 0x00002014,
> + * POSTED_INTR_DESC_ADDR = 0x00002016,
> + * EOI_EXIT_BITMAP0 = 0x0000201c,
> + * EOI_EXIT_BITMAP1 = 0x0000201e,
> + * EOI_EXIT_BITMAP2 = 0x00002020,
> + * EOI_EXIT_BITMAP3 = 0x00002022,
> + * GUEST_PML_INDEX = 0x00000812,
> + * PML_ADDRESS = 0x0000200e,
> + * VM_FUNCTION_CONTROL = 0x00002018,
> + * EPTP_LIST_ADDRESS = 0x00002024,
> + * VMREAD_BITMAP = 0x00002026,
> + * VMWRITE_BITMAP = 0x00002028,
> + *
> + * TSC_MULTIPLIER = 0x00002032,
> + * PLE_GAP = 0x00004020,
> + * PLE_WINDOW = 0x00004022,
> + * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
> + *
> + * Currently unsupported in KVM:
> + * GUEST_IA32_RTIT_CTL = 0x00002814,
> + */
> +#define EVMCS1_SUPPORTED_PINCTRL \
> + (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
> + PIN_BASED_EXT_INTR_MASK | \
> + PIN_BASED_NMI_EXITING | \
> + PIN_BASED_VIRTUAL_NMIS)
> +
> +#define EVMCS1_SUPPORTED_EXEC_CTRL \
> + (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
> + CPU_BASED_HLT_EXITING | \
> + CPU_BASED_CR3_LOAD_EXITING | \
> + CPU_BASED_CR3_STORE_EXITING | \
> + CPU_BASED_UNCOND_IO_EXITING | \
> + CPU_BASED_MOV_DR_EXITING | \
> + CPU_BASED_USE_TSC_OFFSETTING | \
> + CPU_BASED_MWAIT_EXITING | \
> + CPU_BASED_MONITOR_EXITING | \
> + CPU_BASED_INVLPG_EXITING | \
> + CPU_BASED_RDPMC_EXITING | \
> + CPU_BASED_INTR_WINDOW_EXITING | \
> + CPU_BASED_CR8_LOAD_EXITING | \
> + CPU_BASED_CR8_STORE_EXITING | \
> + CPU_BASED_RDTSC_EXITING | \
> + CPU_BASED_TPR_SHADOW | \
> + CPU_BASED_USE_IO_BITMAPS | \
> + CPU_BASED_MONITOR_TRAP_FLAG | \
> + CPU_BASED_USE_MSR_BITMAPS | \
> + CPU_BASED_NMI_WINDOW_EXITING | \
> + CPU_BASED_PAUSE_EXITING | \
> + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
> +
> +#define EVMCS1_SUPPORTED_2NDEXEC \
> + (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
> + SECONDARY_EXEC_WBINVD_EXITING | \
> + SECONDARY_EXEC_ENABLE_VPID | \
> + SECONDARY_EXEC_ENABLE_EPT | \
> + SECONDARY_EXEC_UNRESTRICTED_GUEST | \
> + SECONDARY_EXEC_DESC | \
> + SECONDARY_EXEC_ENABLE_RDTSCP | \
> + SECONDARY_EXEC_ENABLE_INVPCID | \
> + SECONDARY_EXEC_ENABLE_XSAVES | \
> + SECONDARY_EXEC_RDSEED_EXITING | \
> + SECONDARY_EXEC_RDRAND_EXITING | \
> + SECONDARY_EXEC_TSC_SCALING | \
> + SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
> + SECONDARY_EXEC_PT_USE_GPA | \
> + SECONDARY_EXEC_PT_CONCEAL_VMX | \
> + SECONDARY_EXEC_BUS_LOCK_DETECTION | \
> + SECONDARY_EXEC_NOTIFY_VM_EXITING | \
> + SECONDARY_EXEC_ENCLS_EXITING)
> +
> +#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
> +
> +#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
> + (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
> + VM_EXIT_SAVE_DEBUG_CONTROLS | \
> + VM_EXIT_ACK_INTR_ON_EXIT | \
> + VM_EXIT_HOST_ADDR_SPACE_SIZE | \
> + VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
> + VM_EXIT_SAVE_IA32_PAT | \
> + VM_EXIT_LOAD_IA32_PAT | \
> + VM_EXIT_SAVE_IA32_EFER | \
> + VM_EXIT_LOAD_IA32_EFER | \
> + VM_EXIT_CLEAR_BNDCFGS | \
> + VM_EXIT_PT_CONCEAL_PIP | \
> + VM_EXIT_CLEAR_IA32_RTIT_CTL)
> +
> +#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
> + (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
> + VM_ENTRY_LOAD_DEBUG_CONTROLS | \
> + VM_ENTRY_IA32E_MODE | \
> + VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
> + VM_ENTRY_LOAD_IA32_PAT | \
> + VM_ENTRY_LOAD_IA32_EFER | \
> + VM_ENTRY_LOAD_BNDCFGS | \
> + VM_ENTRY_PT_CONCEAL_PIP | \
> + VM_ENTRY_LOAD_IA32_RTIT_CTL)
> +
> +#define EVMCS1_SUPPORTED_VMFUNC (0)
> +
> struct evmcs_field {
> u16 offset;
> u16 clean_field;
> @@ -65,114 +166,6 @@ static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
> return vmcs12_read_any((void *)evmcs, field, offset);
> }
>
> -#if IS_ENABLED(CONFIG_HYPERV)
> -
> -DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
> -
> -static __always_inline bool kvm_is_using_evmcs(void)
> -{
> - return static_branch_unlikely(&__kvm_is_using_evmcs);
> -}
> -
> -static __always_inline int get_evmcs_offset(unsigned long field,
> - u16 *clean_field)
> -{
> - int offset = evmcs_field_offset(field, clean_field);
> -
> - WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field);
> - return offset;
> -}
> -
> -static __always_inline void evmcs_write64(unsigned long field, u64 value)
> -{
> - u16 clean_field;
> - int offset = get_evmcs_offset(field, &clean_field);
> -
> - if (offset < 0)
> - return;
> -
> - *(u64 *)((char *)current_evmcs + offset) = value;
> -
> - current_evmcs->hv_clean_fields &= ~clean_field;
> -}
> -
> -static __always_inline void evmcs_write32(unsigned long field, u32 value)
> -{
> - u16 clean_field;
> - int offset = get_evmcs_offset(field, &clean_field);
> -
> - if (offset < 0)
> - return;
> -
> - *(u32 *)((char *)current_evmcs + offset) = value;
> - current_evmcs->hv_clean_fields &= ~clean_field;
> -}
> -
> -static __always_inline void evmcs_write16(unsigned long field, u16 value)
> -{
> - u16 clean_field;
> - int offset = get_evmcs_offset(field, &clean_field);
> -
> - if (offset < 0)
> - return;
> -
> - *(u16 *)((char *)current_evmcs + offset) = value;
> - current_evmcs->hv_clean_fields &= ~clean_field;
> -}
> -
> -static __always_inline u64 evmcs_read64(unsigned long field)
> -{
> - int offset = get_evmcs_offset(field, NULL);
> -
> - if (offset < 0)
> - return 0;
> -
> - return *(u64 *)((char *)current_evmcs + offset);
> -}
> -
> -static __always_inline u32 evmcs_read32(unsigned long field)
> -{
> - int offset = get_evmcs_offset(field, NULL);
> -
> - if (offset < 0)
> - return 0;
> -
> - return *(u32 *)((char *)current_evmcs + offset);
> -}
> -
> -static __always_inline u16 evmcs_read16(unsigned long field)
> -{
> - int offset = get_evmcs_offset(field, NULL);
> -
> - if (offset < 0)
> - return 0;
> -
> - return *(u16 *)((char *)current_evmcs + offset);
> -}
> -
> -static inline void evmcs_load(u64 phys_addr)
> -{
> - struct hv_vp_assist_page *vp_ap =
> - hv_get_vp_assist_page(smp_processor_id());
> -
> - if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall)
> - vp_ap->nested_control.features.directhypercall = 1;
> - vp_ap->current_nested_vmcs = phys_addr;
> - vp_ap->enlighten_vmentry = 1;
> -}
> -
> -void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
> -#else /* !IS_ENABLED(CONFIG_HYPERV) */
> -static __always_inline bool kvm_is_using_evmcs(void) { return false; }
> -static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
> -static __always_inline void evmcs_write32(unsigned long field, u32 value) {}
> -static __always_inline void evmcs_write16(unsigned long field, u16 value) {}
> -static __always_inline u64 evmcs_read64(unsigned long field) { return 0; }
> -static __always_inline u32 evmcs_read32(unsigned long field) { return 0; }
> -static __always_inline u16 evmcs_read16(unsigned long field) { return 0; }
> -static inline void evmcs_load(u64 phys_addr) {}
> -#endif /* IS_ENABLED(CONFIG_HYPERV) */
> -
> #define EVMPTR_INVALID (-1ULL)
> #define EVMPTR_MAP_PENDING (-2ULL)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index b7dc7acf14be..04eb5d4d28bc 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -66,6 +66,7 @@
> #include "vmx.h"
> #include "x86.h"
> #include "smm.h"
> +#include "vmx_onhyperv.h"
>
> MODULE_AUTHOR("Qumranet");
> MODULE_LICENSE("GPL");
> diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.c b/arch/x86/kvm/vmx/vmx_onhyperv.c
> new file mode 100644
> index 000000000000..b9a8b91166d0
> --- /dev/null
> +++ b/arch/x86/kvm/vmx/vmx_onhyperv.c
> @@ -0,0 +1,36 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include "capabilities.h"
> +#include "vmx_onhyperv.h"
> +
> +DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
> +
> +/*
> + * 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)
> +
> +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);
> +}
> diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h
> new file mode 100644
> index 000000000000..11541d272dbd
> --- /dev/null
> +++ b/arch/x86/kvm/vmx/vmx_onhyperv.h
> @@ -0,0 +1,124 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef __ARCH_X86_KVM_VMX_ONHYPERV_H__
> +#define __ARCH_X86_KVM_VMX_ONHYPERV_H__
> +
> +#include <asm/hyperv-tlfs.h>
> +
> +#include <linux/jump_label.h>
> +
> +#include "capabilities.h"
> +#include "hyperv.h"
> +#include "vmcs12.h"
> +
> +#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
> +
> +#if IS_ENABLED(CONFIG_HYPERV)
> +
> +DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
> +
> +static __always_inline bool kvm_is_using_evmcs(void)
> +{
> + return static_branch_unlikely(&__kvm_is_using_evmcs);
> +}
> +
> +static __always_inline int get_evmcs_offset(unsigned long field,
> + u16 *clean_field)
> +{
> + int offset = evmcs_field_offset(field, clean_field);
> +
> + WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field);
> + return offset;
> +}
> +
> +static __always_inline void evmcs_write64(unsigned long field, u64 value)
> +{
> + u16 clean_field;
> + int offset = get_evmcs_offset(field, &clean_field);
> +
> + if (offset < 0)
> + return;
> +
> + *(u64 *)((char *)current_evmcs + offset) = value;
> +
> + current_evmcs->hv_clean_fields &= ~clean_field;
> +}
> +
> +static __always_inline void evmcs_write32(unsigned long field, u32 value)
> +{
> + u16 clean_field;
> + int offset = get_evmcs_offset(field, &clean_field);
> +
> + if (offset < 0)
> + return;
> +
> + *(u32 *)((char *)current_evmcs + offset) = value;
> + current_evmcs->hv_clean_fields &= ~clean_field;
> +}
> +
> +static __always_inline void evmcs_write16(unsigned long field, u16 value)
> +{
> + u16 clean_field;
> + int offset = get_evmcs_offset(field, &clean_field);
> +
> + if (offset < 0)
> + return;
> +
> + *(u16 *)((char *)current_evmcs + offset) = value;
> + current_evmcs->hv_clean_fields &= ~clean_field;
> +}
> +
> +static __always_inline u64 evmcs_read64(unsigned long field)
> +{
> + int offset = get_evmcs_offset(field, NULL);
> +
> + if (offset < 0)
> + return 0;
> +
> + return *(u64 *)((char *)current_evmcs + offset);
> +}
> +
> +static __always_inline u32 evmcs_read32(unsigned long field)
> +{
> + int offset = get_evmcs_offset(field, NULL);
> +
> + if (offset < 0)
> + return 0;
> +
> + return *(u32 *)((char *)current_evmcs + offset);
> +}
> +
> +static __always_inline u16 evmcs_read16(unsigned long field)
> +{
> + int offset = get_evmcs_offset(field, NULL);
> +
> + if (offset < 0)
> + return 0;
> +
> + return *(u16 *)((char *)current_evmcs + offset);
> +}
> +
> +static inline void evmcs_load(u64 phys_addr)
> +{
> + struct hv_vp_assist_page *vp_ap =
> + hv_get_vp_assist_page(smp_processor_id());
> +
> + if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall)
> + vp_ap->nested_control.features.directhypercall = 1;
> + vp_ap->current_nested_vmcs = phys_addr;
> + vp_ap->enlighten_vmentry = 1;
> +}
> +
> +void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
> +#else /* !IS_ENABLED(CONFIG_HYPERV) */
> +static __always_inline bool kvm_is_using_evmcs(void) { return false; }
> +static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
> +static __always_inline void evmcs_write32(unsigned long field, u32 value) {}
> +static __always_inline void evmcs_write16(unsigned long field, u16 value) {}
> +static __always_inline u64 evmcs_read64(unsigned long field) { return 0; }
> +static __always_inline u32 evmcs_read32(unsigned long field) { return 0; }
> +static __always_inline u16 evmcs_read16(unsigned long field) { return 0; }
> +static inline void evmcs_load(u64 phys_addr) {}
> +#endif /* IS_ENABLED(CONFIG_HYPERV) */
> +
> +#endif /* __ARCH_X86_KVM_VMX_ONHYPERV_H__ */
> diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h
> index 33af7b4c6eb4..f41ce3c24123 100644
> --- a/arch/x86/kvm/vmx/vmx_ops.h
> +++ b/arch/x86/kvm/vmx/vmx_ops.h
> @@ -6,7 +6,7 @@
>
> #include <asm/vmx.h>
>
> -#include "hyperv.h"
> +#include "vmx_onhyperv.h"
> #include "vmcs.h"
> #include "../x86.h"
>
I did an overall sanity check, including 'diff'ing the moved code,
and it looks good, but I might have missed something.
Reviewed-by: Maxim Levitsky <[email protected]>
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> As a preparation to making Hyper-V emulation optional, create a dedicated
> kvm_hv_synic_has_vector() helper to avoid extra ifdefs in lapic.c.
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/kvm/hyperv.h | 5 +++++
> arch/x86/kvm/lapic.c | 3 +--
> 2 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
> index 1897a219981d..ddb1d0b019e6 100644
> --- a/arch/x86/kvm/hyperv.h
> +++ b/arch/x86/kvm/hyperv.h
> @@ -105,6 +105,11 @@ int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
> void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
> int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages);
>
> +static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector)
> +{
> + return to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->vec_bitmap);
> +}
> +
> static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector)
> {
> return to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap);
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index 0e80c1fdf899..37904c5d421b 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -1475,8 +1475,7 @@ static int apic_set_eoi(struct kvm_lapic *apic)
> apic_clear_isr(vector, apic);
> apic_update_ppr(apic);
>
> - if (to_hv_vcpu(apic->vcpu) &&
> - test_bit(vector, to_hv_synic(apic->vcpu)->vec_bitmap))
> + if (kvm_hv_synic_has_vector(apic->vcpu, vector))
> kvm_hv_synic_send_eoi(apic->vcpu, vector);
>
> kvm_ioapic_send_eoi(apic, vector);
Reviewed-by: Maxim Levitsky <[email protected]
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> Some Enlightened VMCS related code is needed both by Hyper-V on KVM and
> KVM on Hyper-V. As a preparation to making Hyper-V emulation optional,
> create dedicated 'hyperv_evmcs.{ch}' files which are used by both.
>
I think it might be a good idea, to put this comment at the start of the
hyperv_evmcs.h and/or hyperv_evmcs.c, explaining the fact that this file
has code that is common for kvm on hyperv and for hyperv on kvm.
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/kvm/Makefile | 2 +-
> arch/x86/kvm/vmx/hyperv.c | 308 -------------------------------
> arch/x86/kvm/vmx/hyperv.h | 163 +----------------
> arch/x86/kvm/vmx/hyperv_evmcs.c | 311 ++++++++++++++++++++++++++++++++
> arch/x86/kvm/vmx/hyperv_evmcs.h | 162 +++++++++++++++++
> arch/x86/kvm/vmx/vmx_onhyperv.h | 3 +-
> 6 files changed, 477 insertions(+), 472 deletions(-)
> create mode 100644 arch/x86/kvm/vmx/hyperv_evmcs.c
> create mode 100644 arch/x86/kvm/vmx/hyperv_evmcs.h
>
> diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
> index a99ffc3f3a3f..8ea872401cd6 100644
> --- a/arch/x86/kvm/Makefile
> +++ b/arch/x86/kvm/Makefile
> @@ -23,7 +23,7 @@ kvm-$(CONFIG_KVM_XEN) += xen.o
> kvm-$(CONFIG_KVM_SMM) += smm.o
>
> kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
> - vmx/hyperv.o vmx/nested.o vmx/posted_intr.o
> + vmx/hyperv.o vmx/hyperv_evmcs.o vmx/nested.o vmx/posted_intr.o
> kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
>
> ifdef CONFIG_HYPERV
> diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c
> index de13dc14fe1d..fab6a1ad98dc 100644
> --- a/arch/x86/kvm/vmx/hyperv.c
> +++ b/arch/x86/kvm/vmx/hyperv.c
> @@ -13,314 +13,6 @@
>
> #define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK
>
> -#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
> -#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
> - {EVMCS1_OFFSET(name), clean_field}
> -
> -const struct evmcs_field vmcs_field_to_evmcs_1[] = {
> - /* 64 bit rw */
> - EVMCS1_FIELD(GUEST_RIP, guest_rip,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(GUEST_RSP, guest_rsp,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
> - EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
> - EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_CR0, host_cr0,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_CR3, host_cr3,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_CR4, host_cr4,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_RIP, host_rip,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
> - EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
> - EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
> - EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> - EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> - EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> - EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> - EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> - EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> - EVMCS1_FIELD(GUEST_CR0, guest_cr0,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> - EVMCS1_FIELD(GUEST_CR3, guest_cr3,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> - EVMCS1_FIELD(GUEST_CR4, guest_cr4,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> - EVMCS1_FIELD(GUEST_DR7, guest_dr7,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> - EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> - EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> - EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> - EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> - EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> - EVMCS1_FIELD(HOST_RSP, host_rsp,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> - EVMCS1_FIELD(EPT_POINTER, ept_pointer,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
> - EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> - EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> - EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> - /*
> - * Not used by KVM:
> - *
> - * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - * EVMCS1_FIELD(0x0000682A, guest_ssp,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
> - * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - * EVMCS1_FIELD(0x00006C1A, host_ssp,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - */
> -
> - /* 64 bit read only */
> - EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - /*
> - * Not defined in KVM:
> - *
> - * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
> - * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
> - * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
> - * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
> - */
> - EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> -
> - /*
> - * No mask defined in the spec as Hyper-V doesn't currently support
> - * these. Future proof by resetting the whole clean field mask on
> - * access.
> - */
> - EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> - EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> - EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> -
> - /* 32 bit rw */
> - EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
> - EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
> - EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
> - EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
> - EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
> - EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
> - vm_entry_exception_error_code,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
> - EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
> - EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
> - EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
> - EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
> - EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> - EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> -
> - /* 32 bit read only */
> - EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> - EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> -
> - /* No mask defined in the spec (not used) */
> - EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> - EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> - EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> - EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> - EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> - EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> -
> - /* 16 bit rw */
> - EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> - EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> - EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
> -};
> -const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
> -
> u64 nested_get_evmptr(struct kvm_vcpu *vcpu)
> {
> struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
> diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
> index 9401dbfaea7c..d4ed99008518 100644
> --- a/arch/x86/kvm/vmx/hyperv.h
> +++ b/arch/x86/kvm/vmx/hyperv.h
> @@ -2,170 +2,9 @@
> #ifndef __KVM_X86_VMX_HYPERV_H
> #define __KVM_X86_VMX_HYPERV_H
>
> -#include <linux/jump_label.h>
> -
> -#include <asm/hyperv-tlfs.h>
> -#include <asm/mshyperv.h>
> -#include <asm/vmx.h>
> -
> -#include "../hyperv.h"
> -
> -#include "capabilities.h"
> -#include "vmcs.h"
> +#include <linux/kvm_host.h>
> #include "vmcs12.h"
>
> -#define KVM_EVMCS_VERSION 1
> -
> -/*
> - * Enlightened VMCSv1 doesn't support these:
> - *
> - * POSTED_INTR_NV = 0x00000002,
> - * GUEST_INTR_STATUS = 0x00000810,
> - * APIC_ACCESS_ADDR = 0x00002014,
> - * POSTED_INTR_DESC_ADDR = 0x00002016,
> - * EOI_EXIT_BITMAP0 = 0x0000201c,
> - * EOI_EXIT_BITMAP1 = 0x0000201e,
> - * EOI_EXIT_BITMAP2 = 0x00002020,
> - * EOI_EXIT_BITMAP3 = 0x00002022,
> - * GUEST_PML_INDEX = 0x00000812,
> - * PML_ADDRESS = 0x0000200e,
> - * VM_FUNCTION_CONTROL = 0x00002018,
> - * EPTP_LIST_ADDRESS = 0x00002024,
> - * VMREAD_BITMAP = 0x00002026,
> - * VMWRITE_BITMAP = 0x00002028,
> - *
> - * TSC_MULTIPLIER = 0x00002032,
> - * PLE_GAP = 0x00004020,
> - * PLE_WINDOW = 0x00004022,
> - * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
> - *
> - * Currently unsupported in KVM:
> - * GUEST_IA32_RTIT_CTL = 0x00002814,
> - */
> -#define EVMCS1_SUPPORTED_PINCTRL \
> - (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
> - PIN_BASED_EXT_INTR_MASK | \
> - PIN_BASED_NMI_EXITING | \
> - PIN_BASED_VIRTUAL_NMIS)
> -
> -#define EVMCS1_SUPPORTED_EXEC_CTRL \
> - (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
> - CPU_BASED_HLT_EXITING | \
> - CPU_BASED_CR3_LOAD_EXITING | \
> - CPU_BASED_CR3_STORE_EXITING | \
> - CPU_BASED_UNCOND_IO_EXITING | \
> - CPU_BASED_MOV_DR_EXITING | \
> - CPU_BASED_USE_TSC_OFFSETTING | \
> - CPU_BASED_MWAIT_EXITING | \
> - CPU_BASED_MONITOR_EXITING | \
> - CPU_BASED_INVLPG_EXITING | \
> - CPU_BASED_RDPMC_EXITING | \
> - CPU_BASED_INTR_WINDOW_EXITING | \
> - CPU_BASED_CR8_LOAD_EXITING | \
> - CPU_BASED_CR8_STORE_EXITING | \
> - CPU_BASED_RDTSC_EXITING | \
> - CPU_BASED_TPR_SHADOW | \
> - CPU_BASED_USE_IO_BITMAPS | \
> - CPU_BASED_MONITOR_TRAP_FLAG | \
> - CPU_BASED_USE_MSR_BITMAPS | \
> - CPU_BASED_NMI_WINDOW_EXITING | \
> - CPU_BASED_PAUSE_EXITING | \
> - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
> -
> -#define EVMCS1_SUPPORTED_2NDEXEC \
> - (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
> - SECONDARY_EXEC_WBINVD_EXITING | \
> - SECONDARY_EXEC_ENABLE_VPID | \
> - SECONDARY_EXEC_ENABLE_EPT | \
> - SECONDARY_EXEC_UNRESTRICTED_GUEST | \
> - SECONDARY_EXEC_DESC | \
> - SECONDARY_EXEC_ENABLE_RDTSCP | \
> - SECONDARY_EXEC_ENABLE_INVPCID | \
> - SECONDARY_EXEC_ENABLE_XSAVES | \
> - SECONDARY_EXEC_RDSEED_EXITING | \
> - SECONDARY_EXEC_RDRAND_EXITING | \
> - SECONDARY_EXEC_TSC_SCALING | \
> - SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
> - SECONDARY_EXEC_PT_USE_GPA | \
> - SECONDARY_EXEC_PT_CONCEAL_VMX | \
> - SECONDARY_EXEC_BUS_LOCK_DETECTION | \
> - SECONDARY_EXEC_NOTIFY_VM_EXITING | \
> - SECONDARY_EXEC_ENCLS_EXITING)
> -
> -#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
> -
> -#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
> - (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
> - VM_EXIT_SAVE_DEBUG_CONTROLS | \
> - VM_EXIT_ACK_INTR_ON_EXIT | \
> - VM_EXIT_HOST_ADDR_SPACE_SIZE | \
> - VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
> - VM_EXIT_SAVE_IA32_PAT | \
> - VM_EXIT_LOAD_IA32_PAT | \
> - VM_EXIT_SAVE_IA32_EFER | \
> - VM_EXIT_LOAD_IA32_EFER | \
> - VM_EXIT_CLEAR_BNDCFGS | \
> - VM_EXIT_PT_CONCEAL_PIP | \
> - VM_EXIT_CLEAR_IA32_RTIT_CTL)
> -
> -#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
> - (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
> - VM_ENTRY_LOAD_DEBUG_CONTROLS | \
> - VM_ENTRY_IA32E_MODE | \
> - VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
> - VM_ENTRY_LOAD_IA32_PAT | \
> - VM_ENTRY_LOAD_IA32_EFER | \
> - VM_ENTRY_LOAD_BNDCFGS | \
> - VM_ENTRY_PT_CONCEAL_PIP | \
> - VM_ENTRY_LOAD_IA32_RTIT_CTL)
> -
> -#define EVMCS1_SUPPORTED_VMFUNC (0)
> -
> -struct evmcs_field {
> - u16 offset;
> - u16 clean_field;
> -};
> -
> -extern const struct evmcs_field vmcs_field_to_evmcs_1[];
> -extern const unsigned int nr_evmcs_1_fields;
> -
> -static __always_inline int evmcs_field_offset(unsigned long field,
> - u16 *clean_field)
> -{
> - unsigned int index = ROL16(field, 6);
> - const struct evmcs_field *evmcs_field;
> -
> - if (unlikely(index >= nr_evmcs_1_fields))
> - return -ENOENT;
> -
> - evmcs_field = &vmcs_field_to_evmcs_1[index];
> -
> - /*
> - * Use offset=0 to detect holes in eVMCS. This offset belongs to
> - * 'revision_id' but this field has no encoding and is supposed to
> - * be accessed directly.
> - */
> - if (unlikely(!evmcs_field->offset))
> - return -ENOENT;
> -
> - if (clean_field)
> - *clean_field = evmcs_field->clean_field;
> -
> - return evmcs_field->offset;
> -}
> -
> -static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
> - unsigned long field, u16 offset)
> -{
> - /*
> - * vmcs12_read_any() doesn't care whether the supplied structure
> - * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
> - * the exact offset of the required field, use it for convenience
> - * here.
> - */
> - return vmcs12_read_any((void *)evmcs, field, offset);
> -}
> -
> #define EVMPTR_INVALID (-1ULL)
> #define EVMPTR_MAP_PENDING (-2ULL)
>
> diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.c b/arch/x86/kvm/vmx/hyperv_evmcs.c
> new file mode 100644
> index 000000000000..57a2e0470ac8
> --- /dev/null
> +++ b/arch/x86/kvm/vmx/hyperv_evmcs.c
> @@ -0,0 +1,311 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include "hyperv_evmcs.h"
> +
> +#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
> +#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
> + {EVMCS1_OFFSET(name), clean_field}
> +
> +const struct evmcs_field vmcs_field_to_evmcs_1[] = {
> + /* 64 bit rw */
> + EVMCS1_FIELD(GUEST_RIP, guest_rip,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(GUEST_RSP, guest_rsp,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
> + EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
> + EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_CR0, host_cr0,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_CR3, host_cr3,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_CR4, host_cr4,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_RIP, host_rip,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
> + EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
> + EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
> + EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> + EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> + EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> + EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> + EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> + EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> + EVMCS1_FIELD(GUEST_CR0, guest_cr0,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> + EVMCS1_FIELD(GUEST_CR3, guest_cr3,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> + EVMCS1_FIELD(GUEST_CR4, guest_cr4,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> + EVMCS1_FIELD(GUEST_DR7, guest_dr7,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
> + EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> + EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> + EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> + EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> + EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> + EVMCS1_FIELD(HOST_RSP, host_rsp,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
> + EVMCS1_FIELD(EPT_POINTER, ept_pointer,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
> + EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> + EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> + EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
> + /*
> + * Not used by KVM:
> + *
> + * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + * EVMCS1_FIELD(0x0000682A, guest_ssp,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
> + * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + * EVMCS1_FIELD(0x00006C1A, host_ssp,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + */
> +
> + /* 64 bit read only */
> + EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + /*
> + * Not defined in KVM:
> + *
> + * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
> + * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
> + * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
> + * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
> + */
> + EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> +
> + /*
> + * No mask defined in the spec as Hyper-V doesn't currently support
> + * these. Future proof by resetting the whole clean field mask on
> + * access.
> + */
> + EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> + EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> + EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> +
> + /* 32 bit rw */
> + EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
> + EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
> + EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
> + EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
> + EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
> + EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
> + vm_entry_exception_error_code,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
> + EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
> + EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
> + EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
> + EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
> + EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> + EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
> +
> + /* 32 bit read only */
> + EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> + EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
> +
> + /* No mask defined in the spec (not used) */
> + EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> + EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> + EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> + EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> + EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> + EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
> +
> + /* 16 bit rw */
> + EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
> + EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
> + EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
> +};
> +const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
> diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.h b/arch/x86/kvm/vmx/hyperv_evmcs.h
> new file mode 100644
> index 000000000000..11d96975e7cc
> --- /dev/null
> +++ b/arch/x86/kvm/vmx/hyperv_evmcs.h
> @@ -0,0 +1,162 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __KVM_X86_VMX_HYPERV_EVMCS_H
> +#define __KVM_X86_VMX_HYPERV_EVMCS_H
> +
> +#include <asm/hyperv-tlfs.h>
> +
> +#include "capabilities.h"
> +#include "vmcs12.h"
> +
> +#define KVM_EVMCS_VERSION 1
> +
> +/*
> + * Enlightened VMCSv1 doesn't support these:
> + *
> + * POSTED_INTR_NV = 0x00000002,
> + * GUEST_INTR_STATUS = 0x00000810,
> + * APIC_ACCESS_ADDR = 0x00002014,
> + * POSTED_INTR_DESC_ADDR = 0x00002016,
> + * EOI_EXIT_BITMAP0 = 0x0000201c,
> + * EOI_EXIT_BITMAP1 = 0x0000201e,
> + * EOI_EXIT_BITMAP2 = 0x00002020,
> + * EOI_EXIT_BITMAP3 = 0x00002022,
> + * GUEST_PML_INDEX = 0x00000812,
> + * PML_ADDRESS = 0x0000200e,
> + * VM_FUNCTION_CONTROL = 0x00002018,
> + * EPTP_LIST_ADDRESS = 0x00002024,
> + * VMREAD_BITMAP = 0x00002026,
> + * VMWRITE_BITMAP = 0x00002028,
> + *
> + * TSC_MULTIPLIER = 0x00002032,
> + * PLE_GAP = 0x00004020,
> + * PLE_WINDOW = 0x00004022,
> + * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
> + *
> + * Currently unsupported in KVM:
> + * GUEST_IA32_RTIT_CTL = 0x00002814,
> + */
> +#define EVMCS1_SUPPORTED_PINCTRL \
> + (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
> + PIN_BASED_EXT_INTR_MASK | \
> + PIN_BASED_NMI_EXITING | \
> + PIN_BASED_VIRTUAL_NMIS)
> +
> +#define EVMCS1_SUPPORTED_EXEC_CTRL \
> + (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
> + CPU_BASED_HLT_EXITING | \
> + CPU_BASED_CR3_LOAD_EXITING | \
> + CPU_BASED_CR3_STORE_EXITING | \
> + CPU_BASED_UNCOND_IO_EXITING | \
> + CPU_BASED_MOV_DR_EXITING | \
> + CPU_BASED_USE_TSC_OFFSETTING | \
> + CPU_BASED_MWAIT_EXITING | \
> + CPU_BASED_MONITOR_EXITING | \
> + CPU_BASED_INVLPG_EXITING | \
> + CPU_BASED_RDPMC_EXITING | \
> + CPU_BASED_INTR_WINDOW_EXITING | \
> + CPU_BASED_CR8_LOAD_EXITING | \
> + CPU_BASED_CR8_STORE_EXITING | \
> + CPU_BASED_RDTSC_EXITING | \
> + CPU_BASED_TPR_SHADOW | \
> + CPU_BASED_USE_IO_BITMAPS | \
> + CPU_BASED_MONITOR_TRAP_FLAG | \
> + CPU_BASED_USE_MSR_BITMAPS | \
> + CPU_BASED_NMI_WINDOW_EXITING | \
> + CPU_BASED_PAUSE_EXITING | \
> + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
> +
> +#define EVMCS1_SUPPORTED_2NDEXEC \
> + (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
> + SECONDARY_EXEC_WBINVD_EXITING | \
> + SECONDARY_EXEC_ENABLE_VPID | \
> + SECONDARY_EXEC_ENABLE_EPT | \
> + SECONDARY_EXEC_UNRESTRICTED_GUEST | \
> + SECONDARY_EXEC_DESC | \
> + SECONDARY_EXEC_ENABLE_RDTSCP | \
> + SECONDARY_EXEC_ENABLE_INVPCID | \
> + SECONDARY_EXEC_ENABLE_XSAVES | \
> + SECONDARY_EXEC_RDSEED_EXITING | \
> + SECONDARY_EXEC_RDRAND_EXITING | \
> + SECONDARY_EXEC_TSC_SCALING | \
> + SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
> + SECONDARY_EXEC_PT_USE_GPA | \
> + SECONDARY_EXEC_PT_CONCEAL_VMX | \
> + SECONDARY_EXEC_BUS_LOCK_DETECTION | \
> + SECONDARY_EXEC_NOTIFY_VM_EXITING | \
> + SECONDARY_EXEC_ENCLS_EXITING)
> +
> +#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
> +
> +#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
> + (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
> + VM_EXIT_SAVE_DEBUG_CONTROLS | \
> + VM_EXIT_ACK_INTR_ON_EXIT | \
> + VM_EXIT_HOST_ADDR_SPACE_SIZE | \
> + VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
> + VM_EXIT_SAVE_IA32_PAT | \
> + VM_EXIT_LOAD_IA32_PAT | \
> + VM_EXIT_SAVE_IA32_EFER | \
> + VM_EXIT_LOAD_IA32_EFER | \
> + VM_EXIT_CLEAR_BNDCFGS | \
> + VM_EXIT_PT_CONCEAL_PIP | \
> + VM_EXIT_CLEAR_IA32_RTIT_CTL)
> +
> +#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
> + (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
> + VM_ENTRY_LOAD_DEBUG_CONTROLS | \
> + VM_ENTRY_IA32E_MODE | \
> + VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
> + VM_ENTRY_LOAD_IA32_PAT | \
> + VM_ENTRY_LOAD_IA32_EFER | \
> + VM_ENTRY_LOAD_BNDCFGS | \
> + VM_ENTRY_PT_CONCEAL_PIP | \
> + VM_ENTRY_LOAD_IA32_RTIT_CTL)
> +
> +#define EVMCS1_SUPPORTED_VMFUNC (0)
> +
> +struct evmcs_field {
> + u16 offset;
> + u16 clean_field;
> +};
> +
> +extern const struct evmcs_field vmcs_field_to_evmcs_1[];
> +extern const unsigned int nr_evmcs_1_fields;
> +
> +static __always_inline int evmcs_field_offset(unsigned long field,
> + u16 *clean_field)
> +{
> + unsigned int index = ROL16(field, 6);
> + const struct evmcs_field *evmcs_field;
> +
> + if (unlikely(index >= nr_evmcs_1_fields))
> + return -ENOENT;
> +
> + evmcs_field = &vmcs_field_to_evmcs_1[index];
> +
> + /*
> + * Use offset=0 to detect holes in eVMCS. This offset belongs to
> + * 'revision_id' but this field has no encoding and is supposed to
> + * be accessed directly.
> + */
> + if (unlikely(!evmcs_field->offset))
> + return -ENOENT;
> +
> + if (clean_field)
> + *clean_field = evmcs_field->clean_field;
> +
> + return evmcs_field->offset;
> +}
> +
> +static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
> + unsigned long field, u16 offset)
> +{
> + /*
> + * vmcs12_read_any() doesn't care whether the supplied structure
> + * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
> + * the exact offset of the required field, use it for convenience
> + * here.
> + */
> + return vmcs12_read_any((void *)evmcs, field, offset);
> +}
> +
> +#endif /* __KVM_X86_VMX_HYPERV_H */
> diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h
> index 11541d272dbd..eb48153bfd73 100644
> --- a/arch/x86/kvm/vmx/vmx_onhyperv.h
> +++ b/arch/x86/kvm/vmx/vmx_onhyperv.h
> @@ -4,11 +4,12 @@
> #define __ARCH_X86_KVM_VMX_ONHYPERV_H__
>
> #include <asm/hyperv-tlfs.h>
> +#include <asm/mshyperv.h>
>
> #include <linux/jump_label.h>
>
> #include "capabilities.h"
> -#include "hyperv.h"
> +#include "hyperv_evmcs.h"
> #include "vmcs12.h"
>
> #define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
This patch fails the build because of vmx_has_valid_vmcs12() in nested.h which uses EVMPTR_INVALID.
vmx/nested.h includes vmx/vmx.h which includes vmx_ops.h, it includes vmx_onhyperv.h which used to include hyperv.h but not anymore.
We can either add hyperv.h to vmx/nested.h, or we can move the code in vmx_has_valid_vmcs12 to hyperv_evmcs.h.
Besides the build error,
Reviewed-by: Maxim Levitsky <[email protected]>
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> 'vmx->nested.hv_evmcs_vmptr' accesses are all over the place so hiding
> 'hv_evmcs_vmptr' under 'ifdef CONFIG_KVM_HYPERV' would take a lot of
> ifdefs. Introduce 'nested_vmx_evmptr()' accessor instead.
It might also make sense to have 'nested_evmptr_valid(vmx)'
so that we could use it instead of 'evmptr_is_valid(nested_vmx_evmptr(vmx))'?
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/kvm/vmx/hyperv.h | 5 +++++
> arch/x86/kvm/vmx/nested.c | 44 +++++++++++++++++++--------------------
> arch/x86/kvm/vmx/nested.h | 3 ++-
> 3 files changed, 29 insertions(+), 23 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
> index 933ef6cad5e6..6ca5c8c5be9c 100644
> --- a/arch/x86/kvm/vmx/hyperv.h
> +++ b/arch/x86/kvm/vmx/hyperv.h
> @@ -4,6 +4,7 @@
>
> #include <linux/kvm_host.h>
> #include "vmcs12.h"
> +#include "vmx.h"
>
> #define EVMPTR_INVALID (-1ULL)
> #define EVMPTR_MAP_PENDING (-2ULL)
> @@ -20,7 +21,10 @@ enum nested_evmptrld_status {
> EVMPTRLD_ERROR,
> };
>
> +struct vcpu_vmx;
> +
> #ifdef CONFIG_KVM_HYPERV
> +static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return vmx->nested.hv_evmcs_vmptr; }
> u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
> uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
> int nested_enable_evmcs(struct kvm_vcpu *vcpu,
> @@ -30,6 +34,7 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
> bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
> void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
> #else
> +static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return EVMPTR_INVALID; };
> static inline u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { return EVMPTR_INVALID; }
> static inline void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) {}
> static inline bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index ca7e06759aa3..e6476f8e2ccd 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -179,7 +179,7 @@ static int nested_vmx_failValid(struct kvm_vcpu *vcpu,
> * VM_INSTRUCTION_ERROR is not shadowed. Enlightened VMCS 'shadows' all
> * fields and thus must be synced.
> */
> - if (to_vmx(vcpu)->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
> + if (nested_vmx_evmptr(to_vmx(vcpu)) != EVMPTR_INVALID)
> to_vmx(vcpu)->nested.need_vmcs12_to_shadow_sync = true;
>
> return kvm_skip_emulated_instruction(vcpu);
> @@ -194,7 +194,7 @@ static int nested_vmx_fail(struct kvm_vcpu *vcpu, u32 vm_instruction_error)
> * can't be done if there isn't a current VMCS.
> */
> if (vmx->nested.current_vmptr == INVALID_GPA &&
> - !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
> + !evmptr_is_valid(nested_vmx_evmptr(vmx)))
> return nested_vmx_failInvalid(vcpu);
>
> return nested_vmx_failValid(vcpu, vm_instruction_error);
> @@ -230,7 +230,7 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
> struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
> struct vcpu_vmx *vmx = to_vmx(vcpu);
>
> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
> + if (evmptr_is_valid(nested_vmx_evmptr(vmx))) {
> kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
> vmx->nested.hv_evmcs = NULL;
> }
> @@ -2019,7 +2019,7 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
> return EVMPTRLD_DISABLED;
> }
>
> - if (unlikely(evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
> + if (unlikely(evmcs_gpa != nested_vmx_evmptr(vmx))) {
> vmx->nested.current_vmptr = INVALID_GPA;
>
> nested_release_evmcs(vcpu);
> @@ -2097,7 +2097,7 @@ void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
> {
> struct vcpu_vmx *vmx = to_vmx(vcpu);
>
> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
> copy_vmcs12_to_enlightened(vmx);
> else
> copy_vmcs12_to_shadow(vmx);
> @@ -2251,7 +2251,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
> u32 exec_control;
> u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12);
>
> - if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
> + if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(nested_vmx_evmptr(vmx)))
> prepare_vmcs02_early_rare(vmx, vmcs12);
There are some similarities between evmcs and shadow vmcs. I used to know this, but it will probably
take me time to recall all of the gory details.
It might make sense to unify some of the logic, which can make it easier to #ifdef the hyperv support
in less places.
>
> /*
> @@ -2546,11 +2546,11 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
> struct vcpu_vmx *vmx = to_vmx(vcpu);
> bool load_guest_pdptrs_vmcs12 = false;
>
> - if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
> + if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(nested_vmx_evmptr(vmx))) {
> prepare_vmcs02_rare(vmx, vmcs12);
> vmx->nested.dirty_vmcs12 = false;
>
> - load_guest_pdptrs_vmcs12 = !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) ||
> + load_guest_pdptrs_vmcs12 = !evmptr_is_valid(nested_vmx_evmptr(vmx)) ||
> !(vmx->nested.hv_evmcs->hv_clean_fields &
> HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
> }
> @@ -2673,7 +2673,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
> * bits when it changes a field in eVMCS. Mark all fields as clean
> * here.
> */
> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
> vmx->nested.hv_evmcs->hv_clean_fields |=
> HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
>
> @@ -3181,7 +3181,7 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
> * properly reflected.
> */
> if (guest_cpuid_has_evmcs(vcpu) &&
> - vmx->nested.hv_evmcs_vmptr == EVMPTR_MAP_PENDING) {
> + nested_vmx_evmptr(vmx) == EVMPTR_MAP_PENDING) {
> enum nested_evmptrld_status evmptrld_status =
> nested_vmx_handle_enlightened_vmptrld(vcpu, false);
>
> @@ -3551,7 +3551,7 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
>
> load_vmcs12_host_state(vcpu, vmcs12);
> vmcs12->vm_exit_reason = exit_reason.full;
> - if (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
> + if (enable_shadow_vmcs || evmptr_is_valid(nested_vmx_evmptr(vmx)))
> vmx->nested.need_vmcs12_to_shadow_sync = true;
> return NVMX_VMENTRY_VMEXIT;
> }
> @@ -3584,7 +3584,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
> if (CC(evmptrld_status == EVMPTRLD_VMFAIL))
> return nested_vmx_failInvalid(vcpu);
>
> - if (CC(!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) &&
> + if (CC(!evmptr_is_valid(nested_vmx_evmptr(vmx)) &&
> vmx->nested.current_vmptr == INVALID_GPA))
> return nested_vmx_failInvalid(vcpu);
>
> @@ -3599,7 +3599,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
> if (CC(vmcs12->hdr.shadow_vmcs))
> return nested_vmx_failInvalid(vcpu);
>
> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
> + if (evmptr_is_valid(nested_vmx_evmptr(vmx))) {
> copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields);
> /* Enlightened VMCS doesn't have launch state */
> vmcs12->launch_state = !launch;
> @@ -4344,11 +4344,11 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
> {
> struct vcpu_vmx *vmx = to_vmx(vcpu);
>
> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
> sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
>
> vmx->nested.need_sync_vmcs02_to_vmcs12_rare =
> - !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
> + !evmptr_is_valid(nested_vmx_evmptr(vmx));
>
> vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
> vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
> @@ -4869,7 +4869,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
> }
>
> if ((vm_exit_reason != -1) &&
> - (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)))
> + (enable_shadow_vmcs || evmptr_is_valid(nested_vmx_evmptr(vmx))))
> vmx->nested.need_vmcs12_to_shadow_sync = true;
>
> /* in case we halted in L2 */
> @@ -5335,7 +5335,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
> vmptr + offsetof(struct vmcs12,
> launch_state),
> &zero, sizeof(zero));
> - } else if (vmx->nested.hv_evmcs && vmptr == vmx->nested.hv_evmcs_vmptr) {
> + } else if (vmx->nested.hv_evmcs && vmptr == nested_vmx_evmptr(vmx)) {
> nested_release_evmcs(vcpu);
> }
>
> @@ -5375,7 +5375,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
> /* Decode instruction info and find the field to read */
> field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
>
> - if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
> + if (!evmptr_is_valid(nested_vmx_evmptr(vmx))) {
> /*
> * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
> * any VMREAD sets the ALU flags for VMfailInvalid.
> @@ -5601,7 +5601,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
> return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER);
>
> /* Forbid normal VMPTRLD if Enlightened version was used */
> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
> return 1;
>
> if (vmx->nested.current_vmptr != vmptr) {
> @@ -5664,7 +5664,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
> if (!nested_vmx_check_permission(vcpu))
> return 1;
>
> - if (unlikely(evmptr_is_valid(to_vmx(vcpu)->nested.hv_evmcs_vmptr)))
> + if (unlikely(evmptr_is_valid(nested_vmx_evmptr(to_vmx(vcpu)))))
> return 1;
>
> if (get_vmx_mem_address(vcpu, exit_qual, instr_info,
> @@ -6450,7 +6450,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
> kvm_state.size += sizeof(user_vmx_nested_state->vmcs12);
>
> /* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
> - if (vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
> + if (nested_vmx_evmptr(vmx) != EVMPTR_INVALID)
> kvm_state.flags |= KVM_STATE_NESTED_EVMCS;
>
> if (is_guest_mode(vcpu) &&
> @@ -6506,7 +6506,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
> } else {
> copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu));
> if (!vmx->nested.need_vmcs12_to_shadow_sync) {
> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
> /*
> * L1 hypervisor is not obliged to keep eVMCS
> * clean fields data always up-to-date while
> diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h
> index b4b9d51438c6..b389312636e2 100644
> --- a/arch/x86/kvm/vmx/nested.h
> +++ b/arch/x86/kvm/vmx/nested.h
> @@ -3,6 +3,7 @@
> #define __KVM_X86_VMX_NESTED_H
>
> #include "kvm_cache_regs.h"
> +#include "hyperv.h"
^ This fixes the build error introduced by patch 6.
> #include "vmcs12.h"
> #include "vmx.h"
>
> @@ -57,7 +58,7 @@ static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu)
>
> /* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
> return vmx->nested.current_vmptr != -1ull ||
> - vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID;
> + nested_vmx_evmptr(vmx) != EVMPTR_INVALID;
However with my suggestion of nested_evmptr_valid(vmx) we
can hide that check and avoid the include as well.
> }
>
> static inline u16 nested_get_vpid02(struct kvm_vcpu *vcpu)
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> Hyper-V emulation in KVM is a fairly big chunk and in some cases it may be
> desirable to not compile it in to reduce module sizes as well as attack
> surface. Introduce CONFIG_KVM_HYPERV option to make it possible.
>
> Note, there's room for further nVMX/nSVM code optimizations when
> !CONFIG_KVM_HYPERV, this will be done in follow-up patches.
Maybe CONFIG_KVM_HYPERV_GUEST_SUPPORT or CONFIG_HYPERV_ON_KVM instead?
IMHO CONFIG_KVM_HYPERV_GUEST_SUPPORT sounds good.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/include/asm/kvm_host.h | 4 +++
> arch/x86/kvm/Kconfig | 9 ++++++
> arch/x86/kvm/Makefile | 17 +++++++---
> arch/x86/kvm/cpuid.c | 6 ++++
> arch/x86/kvm/hyperv.h | 29 +++++++++++++++--
> arch/x86/kvm/irq_comm.c | 9 +++++-
> arch/x86/kvm/svm/hyperv.h | 7 +++++
> arch/x86/kvm/svm/nested.c | 2 ++
> arch/x86/kvm/svm/svm_onhyperv.h | 2 ++
> arch/x86/kvm/vmx/hyperv.h | 8 +++++
> arch/x86/kvm/vmx/nested.c | 17 ++++++++++
> arch/x86/kvm/x86.c | 56 +++++++++++++++++++++++----------
> 12 files changed, 143 insertions(+), 23 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 711dc880a9f0..b0a55b736b47 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1085,6 +1085,7 @@ enum hv_tsc_page_status {
> HV_TSC_PAGE_BROKEN,
> };
>
> +#ifdef CONFIG_KVM_HYPERV
> /* Hyper-V emulation context */
> struct kvm_hv {
> struct mutex hv_lock;
> @@ -1117,6 +1118,7 @@ struct kvm_hv {
>
> struct kvm_hv_syndbg hv_syndbg;
> };
> +#endif
>
> struct msr_bitmap_range {
> u32 flags;
> @@ -1338,7 +1340,9 @@ struct kvm_arch {
> /* reads protected by irq_srcu, writes by irq_lock */
> struct hlist_head mask_notifier_list;
>
> +#ifdef CONFIG_KVM_HYPERV
> struct kvm_hv hyperv;
> +#endif
>
> #ifdef CONFIG_KVM_XEN
> struct kvm_xen xen;
> diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
> index ed90f148140d..a06e19a8a8f6 100644
> --- a/arch/x86/kvm/Kconfig
> +++ b/arch/x86/kvm/Kconfig
> @@ -129,6 +129,15 @@ config KVM_SMM
>
> If unsure, say Y.
>
> +config KVM_HYPERV
> + bool "Support for Microsoft Hyper-V emulation"
> + depends on KVM
> + default y
> + help
> + Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
It feels to me that the KConfig option can have a longer description.
What do you think about something like that:
"Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
This makes KVM expose a set of paravirtualized interfaces,
documented in the HyperV TLFS,
https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs,
which consists of a subset of paravirtualized interfaces that HyperV exposes
to its guests.
This improves performance of modern Windows guests.
Say Y, unless you are sure that this kernel will not be used to run Windows guests."
> +
> + If unsure, say "Y".
> +
> config KVM_XEN
> bool "Support for Xen hypercall interface"
> depends on KVM
> diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
> index 8ea872401cd6..ccd477178f07 100644
> --- a/arch/x86/kvm/Makefile
> +++ b/arch/x86/kvm/Makefile
> @@ -11,7 +11,7 @@ include $(srctree)/virt/kvm/Makefile.kvm
>
> kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \
> i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
> - hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \
> + debugfs.o mmu/mmu.o mmu/page_track.o \
> mmu/spte.o
>
> ifdef CONFIG_HYPERV
> @@ -19,19 +19,28 @@ kvm-y += kvm_onhyperv.o
> endif
>
> kvm-$(CONFIG_X86_64) += mmu/tdp_iter.o mmu/tdp_mmu.o
> +kvm-$(CONFIG_KVM_HYPERV) += hyperv.o
> kvm-$(CONFIG_KVM_XEN) += xen.o
> kvm-$(CONFIG_KVM_SMM) += smm.o
>
> kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
> - vmx/hyperv.o vmx/hyperv_evmcs.o vmx/nested.o vmx/posted_intr.o
> + vmx/nested.o vmx/posted_intr.o
> +ifdef CONFIG_KVM_HYPERV
> +kvm-intel-y += vmx/hyperv.o vmx/hyperv_evmcs.o
> +endif
> +
> kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
>
> ifdef CONFIG_HYPERV
> -kvm-intel-y += vmx/vmx_onhyperv.o
> +kvm-intel-y += vmx/vmx_onhyperv.o vmx/hyperv_evmcs.o
> endif
>
> kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \
> - svm/sev.o svm/hyperv.o
> + svm/sev.o
> +
> +ifdef CONFIG_KVM_HYPERV
> +kvm-amd-y += svm/hyperv.o
> +endif
I think that we can group all the files under one
'ifdef CONFIG_KVM_HYPERV'.
>
> ifdef CONFIG_HYPERV
> kvm-amd-y += svm/svm_onhyperv.o
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 0544e30b4946..7a3533573f94 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -314,11 +314,15 @@ EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime);
>
> static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent)
> {
> +#ifdef CONFIG_KVM_HYPERV
> struct kvm_cpuid_entry2 *entry;
>
> entry = cpuid_entry2_find(entries, nent, HYPERV_CPUID_INTERFACE,
> KVM_CPUID_INDEX_NOT_SIGNIFICANT);
> return entry && entry->eax == HYPERV_CPUID_SIGNATURE_EAX;
> +#else
> + return false;
> +#endif
Do you think that it might make sense to still complain loudly if the userspace
still tries to enable hyperv cpuid?
> }
>
> static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
> @@ -441,11 +445,13 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
> return 0;
> }
>
> +#ifdef CONFIG_KVM_HYPERV
> if (kvm_cpuid_has_hyperv(e2, nent)) {
> r = kvm_hv_vcpu_init(vcpu);
> if (r)
> return r;
> }
> +#endif
>
> r = kvm_check_cpuid(vcpu, e2, nent);
> if (r)
> diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
> index ddb1d0b019e6..3a6acd8a9fa8 100644
> --- a/arch/x86/kvm/hyperv.h
> +++ b/arch/x86/kvm/hyperv.h
> @@ -24,6 +24,8 @@
> #include <linux/kvm_host.h>
> #include "x86.h"
>
> +#ifdef CONFIG_KVM_HYPERV
> +
> /* "Hv#1" signature */
> #define HYPERV_CPUID_SIGNATURE_EAX 0x31237648
>
> @@ -247,5 +249,28 @@ static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu)
> }
>
> int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu);
> -
> -#endif
> +#else /* CONFIG_KVM_HYPERV */
> +static inline void kvm_hv_setup_tsc_page(struct kvm *kvm,
> + struct pvclock_vcpu_time_info *hv_clock) {}
> +static inline void kvm_hv_request_tsc_page_update(struct kvm *kvm) {}
> +static inline void kvm_hv_init_vm(struct kvm *kvm) {}
> +static inline void kvm_hv_destroy_vm(struct kvm *kvm) {}
> +static inline int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu) { return 0; }
> +static inline void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu) {}
> +static inline bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu) { return false; }
> +static inline int kvm_hv_hypercall(struct kvm_vcpu *vcpu) { return HV_STATUS_ACCESS_DENIED; }
> +static inline void kvm_hv_vcpu_purge_flush_tlb(struct kvm_vcpu *vcpu) {}
> +static inline void kvm_hv_free_pa_page(struct kvm *kvm) {}
> +static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector) { return false; }
> +static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector) { return false; }
> +static inline void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector) {}
> +static inline bool kvm_hv_invtsc_suppressed(struct kvm_vcpu *vcpu) { return false; }
> +static inline void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu, bool hyperv_enabled) {}
> +static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu) { return false; }
> +static inline bool kvm_hv_is_tlb_flush_hcall(struct kvm_vcpu *vcpu) { return false; }
> +static inline bool guest_hv_cpuid_has_l2_tlb_flush(struct kvm_vcpu *vcpu) { return false; }
> +static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu) { return 0; }
> +static inline u32 kvm_hv_get_vpindex(struct kvm_vcpu *vcpu) { return vcpu->vcpu_idx; }
> +#endif /* CONFIG_KVM_HYPERV */
> +
> +#endif /* __ARCH_X86_KVM_HYPERV_H__ */
> diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
> index 16d076a1b91a..68f3f6c26046 100644
> --- a/arch/x86/kvm/irq_comm.c
> +++ b/arch/x86/kvm/irq_comm.c
> @@ -144,7 +144,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
> return kvm_irq_delivery_to_apic(kvm, NULL, &irq, NULL);
> }
>
> -
> +#ifdef CONFIG_KVM_HYPERV
> static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
> struct kvm *kvm, int irq_source_id, int level,
> bool line_status)
> @@ -154,6 +154,7 @@ static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
>
> return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
> }
> +#endif
>
> int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
> struct kvm *kvm, int irq_source_id, int level,
> @@ -163,9 +164,11 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
> int r;
>
> switch (e->type) {
> +#ifdef CONFIG_KVM_HYPERV
> case KVM_IRQ_ROUTING_HV_SINT:
> return kvm_hv_set_sint(e, kvm, irq_source_id, level,
> line_status);
> +#endif
>
> case KVM_IRQ_ROUTING_MSI:
> if (kvm_msi_route_invalid(kvm, e))
> @@ -314,11 +317,13 @@ int kvm_set_routing_entry(struct kvm *kvm,
> if (kvm_msi_route_invalid(kvm, e))
> return -EINVAL;
> break;
> +#ifdef CONFIG_KVM_HYPERV
> case KVM_IRQ_ROUTING_HV_SINT:
> e->set = kvm_hv_set_sint;
> e->hv_sint.vcpu = ue->u.hv_sint.vcpu;
> e->hv_sint.sint = ue->u.hv_sint.sint;
> break;
> +#endif
> #ifdef CONFIG_KVM_XEN
> case KVM_IRQ_ROUTING_XEN_EVTCHN:
> return kvm_xen_setup_evtchn(kvm, e, ue);
> @@ -438,5 +443,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
>
> void kvm_arch_irq_routing_update(struct kvm *kvm)
> {
> +#ifdef CONFIG_KVM_HYPERV
> kvm_hv_irq_routing_update(kvm);
> +#endif
> }
> diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h
> index 02f4784b5d44..14eec2d9b6be 100644
> --- a/arch/x86/kvm/svm/hyperv.h
> +++ b/arch/x86/kvm/svm/hyperv.h
> @@ -11,6 +11,7 @@
> #include "../hyperv.h"
> #include "svm.h"
>
> +#ifdef CONFIG_KVM_HYPERV
> static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu)
> {
> struct vcpu_svm *svm = to_svm(vcpu);
> @@ -41,5 +42,11 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
> }
>
> void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
> +#else /* CONFIG_KVM_HYPERV */
> +static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {}
> +static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
> +static inline void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu) {}
> +#endif /* CONFIG_KVM_HYPERV */
> +
>
> #endif /* __ARCH_X86_KVM_SVM_HYPERV_H__ */
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index dd496c9e5f91..4d8cd378a30b 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -487,6 +487,7 @@ static void nested_save_pending_event_to_vmcb12(struct vcpu_svm *svm,
>
> static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
> {
> +#ifdef CONFIG_KVM_HYPERV
> /*
> * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
> * L2's VP_ID upon request from the guest. Make sure we check for
> @@ -495,6 +496,7 @@ static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
> */
> if (to_hv_vcpu(vcpu) && npt_enabled)
> kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
> +#endif
>
> /*
> * TODO: optimize unconditional TLB flush/MMU sync. A partial list of
> diff --git a/arch/x86/kvm/svm/svm_onhyperv.h b/arch/x86/kvm/svm/svm_onhyperv.h
> index f85bc617ffe4..c25cf56e6adb 100644
> --- a/arch/x86/kvm/svm/svm_onhyperv.h
> +++ b/arch/x86/kvm/svm/svm_onhyperv.h
> @@ -79,6 +79,7 @@ static inline void svm_hv_vmcb_dirty_nested_enlightenments(
>
> static inline void svm_hv_update_vp_id(struct vmcb *vmcb, struct kvm_vcpu *vcpu)
> {
> +#ifdef CONFIG_KVM_HYPERV
> struct hv_vmcb_enlightenments *hve = &vmcb->control.hv_enlightenments;
> u32 vp_index = kvm_hv_get_vpindex(vcpu);
>
> @@ -86,6 +87,7 @@ static inline void svm_hv_update_vp_id(struct vmcb *vmcb, struct kvm_vcpu *vcpu)
> hve->hv_vp_id = vp_index;
> vmcb_mark_dirty(vmcb, HV_VMCB_NESTED_ENLIGHTENMENTS);
> }
> +#endif
> }
> #else
>
> diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
> index d4ed99008518..933ef6cad5e6 100644
> --- a/arch/x86/kvm/vmx/hyperv.h
> +++ b/arch/x86/kvm/vmx/hyperv.h
> @@ -20,6 +20,7 @@ enum nested_evmptrld_status {
> EVMPTRLD_ERROR,
> };
>
> +#ifdef CONFIG_KVM_HYPERV
> u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
> uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
> int nested_enable_evmcs(struct kvm_vcpu *vcpu,
> @@ -28,5 +29,12 @@ void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *
> int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
> bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
> void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
> +#else
> +static inline u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { return EVMPTR_INVALID; }
> +static inline void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) {}
> +static inline bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
> +static inline int nested_evmcs_check_controls(struct vmcs12 *vmcs12) { return 0; }
> +#endif
> +
>
> #endif /* __KVM_X86_VMX_HYPERV_H */
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index c5ec0ef51ff7..ca7e06759aa3 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -226,6 +226,7 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx)
>
> static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
> {
> +#ifdef CONFIG_KVM_HYPERV
> struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
> struct vcpu_vmx *vmx = to_vmx(vcpu);
>
> @@ -241,6 +242,7 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
> hv_vcpu->nested.vm_id = 0;
> hv_vcpu->nested.vp_id = 0;
> }
> +#endif
> }
>
> static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx,
> @@ -1139,6 +1141,7 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
> {
> struct vcpu_vmx *vmx = to_vmx(vcpu);
>
> +#ifdef CONFIG_KVM_HYPERV
> /*
> * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
> * L2's VP_ID upon request from the guest. Make sure we check for
> @@ -1147,6 +1150,7 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
> */
> if (to_hv_vcpu(vcpu) && enable_ept)
> kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
> +#endif
>
> /*
> * If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
> @@ -1576,6 +1580,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
> vmcs_load(vmx->loaded_vmcs->vmcs);
> }
>
> +#ifdef CONFIG_KVM_HYPERV
> static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
> {
> struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
> @@ -2083,6 +2088,10 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
>
> return EVMPTRLD_SUCCEEDED;
> }
> +#else /* CONFIG_KVM_HYPERV */
> +static inline void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields) {}
> +static inline void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx) {}
> +#endif /* CONFIG_KVM_HYPERV */
>
> void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
> {
> @@ -3161,6 +3170,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
> return 0;
> }
>
> +#ifdef CONFIG_KVM_HYPERV
> static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
> {
> struct vcpu_vmx *vmx = to_vmx(vcpu);
> @@ -3188,6 +3198,9 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
>
> return true;
> }
> +#else
> +static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu) { return true; }
> +#endif
>
> static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
> {
> @@ -3558,11 +3571,13 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
> if (!nested_vmx_check_permission(vcpu))
> return 1;
>
> +#ifdef CONFIG_KVM_HYPERV
> evmptrld_status = nested_vmx_handle_enlightened_vmptrld(vcpu, launch);
> if (evmptrld_status == EVMPTRLD_ERROR) {
> kvm_queue_exception(vcpu, UD_VECTOR);
> return 1;
> }
> +#endif
>
> kvm_pmu_trigger_event(vcpu, PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
>
> @@ -7096,7 +7111,9 @@ struct kvm_x86_nested_ops vmx_nested_ops = {
> .set_state = vmx_set_nested_state,
> .get_nested_state_pages = vmx_get_nested_state_pages,
> .write_log_dirty = nested_vmx_write_pml_buffer,
> +#ifdef CONFIG_KVM_HYPERV
> .enable_evmcs = nested_enable_evmcs,
> .get_evmcs_version = nested_get_evmcs_version,
> .hv_inject_synthetic_vmexit_post_tlb_flush = vmx_hv_inject_synthetic_vmexit_post_tlb_flush,
> +#endif
> };
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index e273ce8e0b3f..78e18d28bc61 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -1504,6 +1504,8 @@ static unsigned num_msrs_to_save;
> static const u32 emulated_msrs_all[] = {
> MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
> MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
> +
> +#ifdef CONFIG_KVM_HYPERV
> HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
> HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC,
> HV_X64_MSR_TSC_FREQUENCY, HV_X64_MSR_APIC_FREQUENCY,
> @@ -1521,6 +1523,7 @@ static const u32 emulated_msrs_all[] = {
> HV_X64_MSR_SYNDBG_CONTROL, HV_X64_MSR_SYNDBG_STATUS,
> HV_X64_MSR_SYNDBG_SEND_BUFFER, HV_X64_MSR_SYNDBG_RECV_BUFFER,
> HV_X64_MSR_SYNDBG_PENDING_BUFFER,
> +#endif
>
> MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
> MSR_KVM_PV_EOI_EN, MSR_KVM_ASYNC_PF_INT, MSR_KVM_ASYNC_PF_ACK,
> @@ -3914,6 +3917,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> * the need to ignore the workaround.
> */
> break;
> +#ifdef CONFIG_KVM_HYPERV
> case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
> case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
> case HV_X64_MSR_SYNDBG_OPTIONS:
> @@ -3926,6 +3930,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> case HV_X64_MSR_TSC_INVARIANT_CONTROL:
> return kvm_hv_set_msr_common(vcpu, msr, data,
> msr_info->host_initiated);
> +#endif
> case MSR_IA32_BBL_CR_CTL3:
> /* Drop writes to this legacy MSR -- see rdmsr
> * counterpart for further detail.
> @@ -4270,6 +4275,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> */
> msr_info->data = 0x20000000;
> break;
> +#ifdef CONFIG_KVM_HYPERV
> case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
> case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
> case HV_X64_MSR_SYNDBG_OPTIONS:
> @@ -4283,6 +4289,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> return kvm_hv_get_msr_common(vcpu,
> msr_info->index, &msr_info->data,
> msr_info->host_initiated);
> +#endif
> case MSR_IA32_BBL_CR_CTL3:
> /* This legacy MSR exists but isn't fully documented in current
> * silicon. It is however accessed by winxp in very narrow
> @@ -4420,6 +4427,7 @@ static inline bool kvm_can_mwait_in_guest(void)
> boot_cpu_has(X86_FEATURE_ARAT);
> }
>
> +#ifdef CONFIG_KVM_HYPERV
> static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
> struct kvm_cpuid2 __user *cpuid_arg)
> {
> @@ -4440,6 +4448,7 @@ static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
>
> return 0;
> }
> +#endif
>
> int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
> {
> @@ -4764,9 +4773,11 @@ long kvm_arch_dev_ioctl(struct file *filp,
> case KVM_GET_MSRS:
> r = msr_io(NULL, argp, do_get_msr_feature, 1);
> break;
> +#ifdef CONFIG_KVM_HYPERV
> case KVM_GET_SUPPORTED_HV_CPUID:
> r = kvm_ioctl_get_supported_hv_cpuid(NULL, argp);
> break;
> +#endif
> case KVM_GET_DEVICE_ATTR: {
> struct kvm_device_attr attr;
> r = -EFAULT;
> @@ -5580,14 +5591,11 @@ static int kvm_vcpu_ioctl_device_attr(struct kvm_vcpu *vcpu,
> static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
> struct kvm_enable_cap *cap)
> {
> - int r;
> - uint16_t vmcs_version;
> - void __user *user_ptr;
> -
> if (cap->flags)
> return -EINVAL;
>
> switch (cap->cap) {
> +#ifdef CONFIG_KVM_HYPERV
> case KVM_CAP_HYPERV_SYNIC2:
> if (cap->args[0])
> return -EINVAL;
> @@ -5599,16 +5607,22 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
> return kvm_hv_activate_synic(vcpu, cap->cap ==
> KVM_CAP_HYPERV_SYNIC2);
> case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
> - if (!kvm_x86_ops.nested_ops->enable_evmcs)
> - return -ENOTTY;
> - r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
> - if (!r) {
> - user_ptr = (void __user *)(uintptr_t)cap->args[0];
> - if (copy_to_user(user_ptr, &vmcs_version,
> - sizeof(vmcs_version)))
> - r = -EFAULT;
> + {
> + int r;
> + uint16_t vmcs_version;
> + void __user *user_ptr;CONFIG_KVM_HYPERV_GUEST_SUPPORT
> +
> + if (!kvm_x86_ops.nested_ops->enable_evmcs)
> + return -ENOTTY;
> + r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
> + if (!r) {
> + user_ptr = (void __user *)(uintptr_t)cap->args[0];
> + if (copy_to_user(user_ptr, &vmcs_version,
> + sizeof(vmcs_version)))
> + r = -EFAULT;
> + }
> + return r;
> }
> - return r;
> case KVM_CAP_HYPERV_DIRECT_TLBFLUSH:
> if (!kvm_x86_ops.enable_l2_tlb_flush)
> return -ENOTTY;
> @@ -5617,6 +5631,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
>
> case KVM_CAP_HYPERV_ENFORCE_CPUID:
> return kvm_hv_set_enforce_cpuid(vcpu, cap->args[0]);
> +#endif
>
> case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
> vcpu->arch.pv_cpuid.enforce = cap->args[0];
> @@ -6009,9 +6024,11 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> srcu_read_unlock(&vcpu->kvm->srcu, idx);
> break;
> }
> +#ifdef CONFIG_KVM_HYPERV
> case KVM_GET_SUPPORTED_HV_CPUID:
> r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp);
> break;
> +#endif
> #ifdef CONFIG_KVM_XEN
> case KVM_XEN_VCPU_GET_ATTR: {
> struct kvm_xen_vcpu_attr xva;
> @@ -7066,6 +7083,7 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
> r = static_call(kvm_x86_mem_enc_unregister_region)(kvm, ®ion);
> break;
> }
> +#ifdef CONFIG_KVM_HYPERV
> case KVM_HYPERV_EVENTFD: {
> struct kvm_hyperv_eventfd hvevfd;
>
> @@ -7075,6 +7093,7 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
> r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd);
> break;
> }
> +#endif
> case KVM_SET_PMU_EVENT_FILTER:
> r = kvm_vm_ioctl_set_pmu_event_filter(kvm, argp);
> break;
> @@ -10445,19 +10464,20 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
>
> static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
> {
> - u64 eoi_exit_bitmap[4];
> -
> if (!kvm_apic_hw_enabled(vcpu->arch.apic))
> return;
>
> +#ifdef CONFIG_KVM_HYPERV
> if (to_hv_vcpu(vcpu)) {
> + u64 eoi_exit_bitmap[4];
> +
> bitmap_or((ulong *)eoi_exit_bitmap,
> vcpu->arch.ioapic_handled_vectors,
> to_hv_synic(vcpu)->vec_bitmap, 256);
> static_call_cond(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap);
> return;
> }
> -
> +#endif
> static_call_cond(kvm_x86_load_eoi_exitmap)(
> vcpu, (u64 *)vcpu->arch.ioapic_handled_vectors);
> }
> @@ -10548,9 +10568,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
> * the flushes are considered "remote" and not "local" because
> * the requests can be initiated from other vCPUs.
> */
> +#ifdef CONFIG_KVM_HYPERV
> if (kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu) &&
> kvm_hv_vcpu_flush_tlb(vcpu))
> kvm_vcpu_flush_tlb_guest(vcpu);
> +#endif
>
> if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
> vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
> @@ -10603,6 +10625,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
> vcpu_load_eoi_exitmap(vcpu);
> if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
> kvm_vcpu_reload_apic_access_page(vcpu);
> +#ifdef CONFIG_KVM_HYPERV
> if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) {
> vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
> vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH;
> @@ -10633,6 +10656,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
> */
> if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
> kvm_hv_process_stimers(vcpu);
> +#endif
> if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
> kvm_vcpu_update_apicv(vcpu);
> if (kvm_check_request(KVM_REQ_APF_READY, vcpu))
Looks reasonable, I didn't check everything though, I might have missed something.
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> There's a number of 'vmx->nested.hv_evmcs' accesses in nested.c, introduce
> 'nested_vmx_evmcs()' accessor to hide them all in !CONFIG_KVM_HYPERV case.
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/kvm/vmx/hyperv.h | 8 ++++++++
> arch/x86/kvm/vmx/nested.c | 33 ++++++++++++++++++---------------
> 2 files changed, 26 insertions(+), 15 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
> index 6ca5c8c5be9c..b07131a23250 100644
> --- a/arch/x86/kvm/vmx/hyperv.h
> +++ b/arch/x86/kvm/vmx/hyperv.h
> @@ -25,6 +25,10 @@ struct vcpu_vmx;
>
> #ifdef CONFIG_KVM_HYPERV
> static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return vmx->nested.hv_evmcs_vmptr; }
> +static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
> +{
> + return vmx->nested.hv_evmcs;
> +}
> u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
> uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
> int nested_enable_evmcs(struct kvm_vcpu *vcpu,
> @@ -35,6 +39,10 @@ bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
> void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
> #else
> static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return EVMPTR_INVALID; };
> +static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
> +{
> + return NULL;
> +}
> static inline u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { return EVMPTR_INVALID; }
> static inline void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) {}
> static inline bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index e6476f8e2ccd..d539904d8f1e 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -574,7 +574,6 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
> int msr;
> unsigned long *msr_bitmap_l1;
> unsigned long *msr_bitmap_l0 = vmx->nested.vmcs02.msr_bitmap;
> - struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
> struct kvm_host_map *map = &vmx->nested.msr_bitmap_map;
>
> /* Nothing to do if the MSR bitmap is not in use. */
> @@ -590,10 +589,13 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
> * - Nested hypervisor (L1) has enabled 'Enlightened MSR Bitmap' feature
> * and tells KVM (L0) there were no changes in MSR bitmap for L2.
> */
> - if (!vmx->nested.force_msr_bitmap_recalc && evmcs &&
> - evmcs->hv_enlightenments_control.msr_bitmap &&
> - evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP)
> - return true;
> + if (!vmx->nested.force_msr_bitmap_recalc) {
> + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
> +
> + if (evmcs && evmcs->hv_enlightenments_control.msr_bitmap &&
> + evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP)
> + return true;
> + }
>
> if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->msr_bitmap), map))
> return false;
> @@ -1584,7 +1586,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
> static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
> {
> struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
> - struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
> + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
> struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(&vmx->vcpu);
>
> /* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE */
> @@ -1828,7 +1830,7 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields
> static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
> {
> struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
> - struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
> + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
>
> /*
> * Should not be changed by KVM:
> @@ -2412,7 +2414,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
>
> static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
> {
> - struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs;
> + struct hv_enlightened_vmcs *hv_evmcs = nested_vmx_evmcs(vmx);
>
> if (!hv_evmcs || !(hv_evmcs->hv_clean_fields &
> HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2)) {
> @@ -2544,6 +2546,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
> enum vm_entry_failure_code *entry_failure_code)
> {
> struct vcpu_vmx *vmx = to_vmx(vcpu);
> + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
> bool load_guest_pdptrs_vmcs12 = false;
>
> if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(nested_vmx_evmptr(vmx))) {
> @@ -2551,8 +2554,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
> vmx->nested.dirty_vmcs12 = false;
>
> load_guest_pdptrs_vmcs12 = !evmptr_is_valid(nested_vmx_evmptr(vmx)) ||
> - !(vmx->nested.hv_evmcs->hv_clean_fields &
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
> + !(evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
> }
>
> if (vmx->nested.nested_run_pending &&
> @@ -2674,8 +2676,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
> * here.
> */
> if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
> - vmx->nested.hv_evmcs->hv_clean_fields |=
> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
> + evmcs->hv_clean_fields |= HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
>
> return 0;
> }
> @@ -3600,7 +3601,9 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
> return nested_vmx_failInvalid(vcpu);
>
> if (evmptr_is_valid(nested_vmx_evmptr(vmx))) {
> - copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields);
> + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
> +
> + copy_enlightened_to_vmcs12(vmx, evmcs->hv_clean_fields);
> /* Enlightened VMCS doesn't have launch state */
> vmcs12->launch_state = !launch;
> } else if (enable_shadow_vmcs) {
> @@ -5335,7 +5338,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
> vmptr + offsetof(struct vmcs12,
> launch_state),
> &zero, sizeof(zero));
> - } else if (vmx->nested.hv_evmcs && vmptr == nested_vmx_evmptr(vmx)) {
> + } else if (nested_vmx_evmcs(vmx) && vmptr == nested_vmx_evmptr(vmx)) {
> nested_release_evmcs(vcpu);
> }
>
> @@ -5413,7 +5416,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
> return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
>
> /* Read the field, zero-extended to a u64 value */
> - value = evmcs_read_any(vmx->nested.hv_evmcs, field, offset);
> + value = evmcs_read_any(nested_vmx_evmcs(vmx), field, offset);
> }
>
> /*
Reviewed-by: Maxim Levitsky <[email protected]>
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:03 +0200, Vitaly Kuznetsov пише:
> 'struct hv_vmcb_enlightenments' in VMCB only make sense when either
> CONFIG_KVM_HYPERV or CONFIG_HYPERV is enabled.
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/kvm/svm/nested.c | 20 ++++++++++++++------
> arch/x86/kvm/svm/svm.h | 2 ++
> 2 files changed, 16 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index 4d8cd378a30b..5ae41a708005 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -187,7 +187,6 @@ void recalc_intercepts(struct vcpu_svm *svm)
> */
> static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
> {
> - struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments;
> int i;
>
> /*
> @@ -198,11 +197,16 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
> * - Nested hypervisor (L1) is using Hyper-V emulation interface and
> * tells KVM (L0) there were no changes in MSR bitmap for L2.
> */
> - if (!svm->nested.force_msr_bitmap_recalc &&
> - kvm_hv_hypercall_enabled(&svm->vcpu) &&
> - hve->hv_enlightenments_control.msr_bitmap &&
> - (svm->nested.ctl.clean & BIT(HV_VMCB_NESTED_ENLIGHTENMENTS)))
> - goto set_msrpm_base_pa;
> +#ifdef CONFIG_KVM_HYPERV
> + if (!svm->nested.force_msr_bitmap_recalc) {
> + struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments;
> +
> + if (kvm_hv_hypercall_enabled(&svm->vcpu) &&
> + hve->hv_enlightenments_control.msr_bitmap &&
> + (svm->nested.ctl.clean & BIT(HV_VMCB_NESTED_ENLIGHTENMENTS)))
> + goto set_msrpm_base_pa;
> + }
> +#endif
>
> if (!(vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT)))
> return true;
> @@ -230,7 +234,9 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
>
> svm->nested.force_msr_bitmap_recalc = false;
>
> +#ifdef CONFIG_KVM_HYPERV
> set_msrpm_base_pa:
> +#endif
> svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm));
>
> return true;
> @@ -378,12 +384,14 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
> to->msrpm_base_pa &= ~0x0fffULL;
> to->iopm_base_pa &= ~0x0fffULL;
>
> +#ifdef CONFIG_KVM_HYPERV
> /* Hyper-V extensions (Enlightened VMCB) */
> if (kvm_hv_hypercall_enabled(vcpu)) {
> to->clean = from->clean;
> memcpy(&to->hv_enlightenments, &from->hv_enlightenments,
> sizeof(to->hv_enlightenments));
> }
> +#endif
> }
>
> void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm,
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index be67ab7fdd10..59adff7bbf55 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -148,7 +148,9 @@ struct vmcb_ctrl_area_cached {
> u64 virt_ext;
> u32 clean;
> union {
> +#if IS_ENABLED(CONFIG_HYPERV) || IS_ENABLED(CONFIG_KVM_HYPERV)
> struct hv_vmcb_enlightenments hv_enlightenments;
> +#endif
> u8 reserved_sw[32];
> };
> };
Reviewed-by: Maxim Levitsky <[email protected]>
Best regards,
Maxim Levitsky
У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> 'hv_evmcs_vmptr'/'hv_evmcs_map'/'hv_evmcs' fields in 'struct nested_vmx'
> should not be used when !CONFIG_KVM_HYPERV, hide them when
> !CONFIG_KVM_HYPERV.
>
> No functional change intended.
>
> Signed-off-by: Vitaly Kuznetsov <[email protected]>
> ---
> arch/x86/kvm/vmx/nested.c | 2 ++
> arch/x86/kvm/vmx/vmx.c | 3 +++
> arch/x86/kvm/vmx/vmx.h | 2 ++
> 3 files changed, 7 insertions(+)
>
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index d539904d8f1e..10cb35cd7a19 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -6650,6 +6650,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
> return -EINVAL;
>
> set_current_vmptr(vmx, kvm_state->hdr.vmx.vmcs12_pa);
> +#ifdef CONFIG_KVM_HYPERV
> } else if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) {
> /*
> * nested_vmx_handle_enlightened_vmptrld() cannot be called
> @@ -6659,6 +6660,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
> */
> vmx->nested.hv_evmcs_vmptr = EVMPTR_MAP_PENDING;
> kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
> +#endif
> } else {
> return -EINVAL;
> }
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 04eb5d4d28bc..3b1bd3d97150 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -4834,7 +4834,10 @@ static void __vmx_vcpu_reset(struct kvm_vcpu *vcpu)
> vmx->nested.posted_intr_nv = -1;
> vmx->nested.vmxon_ptr = INVALID_GPA;
> vmx->nested.current_vmptr = INVALID_GPA;
> +
> +#ifdef CONFIG_KVM_HYPERV
> vmx->nested.hv_evmcs_vmptr = EVMPTR_INVALID;
> +#endif
>
> vcpu->arch.microcode_version = 0x100000000ULL;
> vmx->msr_ia32_feature_control_valid_bits = FEAT_CTL_LOCKED;
> diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
> index c2130d2c8e24..55addb8eef01 100644
> --- a/arch/x86/kvm/vmx/vmx.h
> +++ b/arch/x86/kvm/vmx/vmx.h
> @@ -241,9 +241,11 @@ struct nested_vmx {
> bool guest_mode;
> } smm;
>
> +#ifdef CONFIG_KVM_HYPERV
> gpa_t hv_evmcs_vmptr;
> struct kvm_host_map hv_evmcs_map;
> struct hv_enlightened_vmcs *hv_evmcs;
> +#endif
> };
>
> struct vcpu_vmx {
Reviewed-by: Maxim Levitsky <[email protected]>
Best regards,
Maxim Levitsky
Maxim Levitsky <[email protected]> writes:
> У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
>> Hyper-V partition assist page is used when KVM runs on top of Hyper-V and
>> is not used for Windows/Hyper-V guests on KVM, this means that 'hv_pa_pg'
>> placement in 'struct kvm_hv' is unfortunate. As a preparation to making
>> Hyper-V emulation optional, move 'hv_pa_pg' to 'struct kvm_arch' and put it
>> under CONFIG_HYPERV.
>
> It took me a while to realize that this parition assist page is indeed something that L0,
> running above KVM consumes.
> (what a confusing name Microsoft picked...)
>
> As far as I know currently the partition assist page has only
> one shared memory variable which allows L1 to be notified of direct TLB flushes that L0 does for L2,
> but since KVM doesn't need it, it
> never touches this variable/page,
> but specs still demand that L1 does allocate that page.
>
Yes,
KVM doesn't ask L0 (Hyper-V) to deliver synthetic vmexits but the page
needs to be allocated. I'm not sure whether this is done to follow the
spec ("The partition assist page is a page-size aligned page-size region
of memory that the L1 hypervisor must allocate and zero before direct
flush hypercalls can be used.") or if anyone has ever tried writing '0'
to the corresponding field to see what happens with various Hyper-V
versions but even if it happens to work today, there's no guarantee for
the future.
>
> If you agree, it would be great to add a large comment to the code,
> explaining the above,
There' this in vmx.c:
/*
* Synthetic VM-Exit is not enabled in current code and so All
* evmcs in singe VM shares same assist page.
*/
but this can certainly get extended. Moreover, it seems that
hv_enable_l2_tlb_flush() should go vmx_onhyperv.c to make that fact that
it's for KVM-on-Hyper-V 'more obvious'.
> and fact that the partition assist page
> is something L1 exposes to L0.
>
> I don't know though where to put the comment
> because hv_enable_l2_tlb_flush is duplicated between SVM and VMX.
>
> It might be a good idea to have a helper function to allocate the partition assist page,
> which will both reduce the code duplication slightly and allow us to
> put this comment there.
OK.
>
>
> Best regards,
> Maxim Levitsky
>
>>
>> No functional change intended.
>>
>> Signed-off-by: Vitaly Kuznetsov <[email protected]>
>> ---
>> arch/x86/include/asm/kvm_host.h | 2 +-
>> arch/x86/kvm/svm/svm_onhyperv.c | 2 +-
>> arch/x86/kvm/vmx/vmx.c | 2 +-
>> arch/x86/kvm/x86.c | 4 +++-
>> 4 files changed, 6 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index e5d4b8a44630..711dc880a9f0 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -1115,7 +1115,6 @@ struct kvm_hv {
>> */
>> unsigned int synic_auto_eoi_used;
>>
>> - struct hv_partition_assist_pg *hv_pa_pg;
>> struct kvm_hv_syndbg hv_syndbg;
>> };
>>
>> @@ -1436,6 +1435,7 @@ struct kvm_arch {
>> #if IS_ENABLED(CONFIG_HYPERV)
>> hpa_t hv_root_tdp;
>> spinlock_t hv_root_tdp_lock;
>> + struct hv_partition_assist_pg *hv_pa_pg;
>> #endif
>> /*
>> * VM-scope maximum vCPU ID. Used to determine the size of structures
>> diff --git a/arch/x86/kvm/svm/svm_onhyperv.c b/arch/x86/kvm/svm/svm_onhyperv.c
>> index 7af8422d3382..d19666f9b9ac 100644
>> --- a/arch/x86/kvm/svm/svm_onhyperv.c
>> +++ b/arch/x86/kvm/svm/svm_onhyperv.c
>> @@ -19,7 +19,7 @@ int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu)
>> {
>> struct hv_vmcb_enlightenments *hve;
>> struct hv_partition_assist_pg **p_hv_pa_pg =
>> - &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
>> + &vcpu->kvm->arch.hv_pa_pg;
>>
>> if (!*p_hv_pa_pg)
>> *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL);
>> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
>> index 72e3943f3693..b7dc7acf14be 100644
>> --- a/arch/x86/kvm/vmx/vmx.c
>> +++ b/arch/x86/kvm/vmx/vmx.c
>> @@ -524,7 +524,7 @@ static int hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu)
>> {
>> struct hv_enlightened_vmcs *evmcs;
>> struct hv_partition_assist_pg **p_hv_pa_pg =
>> - &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
>> + &vcpu->kvm->arch.hv_pa_pg;
>> /*
>> * Synthetic VM-Exit is not enabled in current code and so All
>> * evmcs in singe VM shares same assist page.
>> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
>> index 9f18b06bbda6..e273ce8e0b3f 100644
>> --- a/arch/x86/kvm/x86.c
>> +++ b/arch/x86/kvm/x86.c
>> @@ -12291,7 +12291,9 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
>>
>> void kvm_arch_free_vm(struct kvm *kvm)
>> {
>> - kfree(to_kvm_hv(kvm)->hv_pa_pg);
>> +#if IS_ENABLED(CONFIG_HYPERV)
>> + kfree(kvm->arch.hv_pa_pg);
>> +#endif
>> __kvm_arch_free_vm(kvm);
>> }
>>
>
>
>
>
--
Vitaly
Maxim Levitsky <[email protected]> writes:
> У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
>> Some Enlightened VMCS related code is needed both by Hyper-V on KVM and
>> KVM on Hyper-V. As a preparation to making Hyper-V emulation optional,
>> create dedicated 'hyperv_evmcs.{ch}' files which are used by both.
>>
>
> I think it might be a good idea, to put this comment at the start of the
> hyperv_evmcs.h and/or hyperv_evmcs.c, explaining the fact that this file
> has code that is common for kvm on hyperv and for hyperv on kvm.
>
>
>> No functional change intended.
>>
>> Signed-off-by: Vitaly Kuznetsov <[email protected]>
>> ---
>> arch/x86/kvm/Makefile | 2 +-
>> arch/x86/kvm/vmx/hyperv.c | 308 -------------------------------
>> arch/x86/kvm/vmx/hyperv.h | 163 +----------------
>> arch/x86/kvm/vmx/hyperv_evmcs.c | 311 ++++++++++++++++++++++++++++++++
>> arch/x86/kvm/vmx/hyperv_evmcs.h | 162 +++++++++++++++++
>> arch/x86/kvm/vmx/vmx_onhyperv.h | 3 +-
>> 6 files changed, 477 insertions(+), 472 deletions(-)
>> create mode 100644 arch/x86/kvm/vmx/hyperv_evmcs.c
>> create mode 100644 arch/x86/kvm/vmx/hyperv_evmcs.h
>>
>> diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
>> index a99ffc3f3a3f..8ea872401cd6 100644
>> --- a/arch/x86/kvm/Makefile
>> +++ b/arch/x86/kvm/Makefile
>> @@ -23,7 +23,7 @@ kvm-$(CONFIG_KVM_XEN) += xen.o
>> kvm-$(CONFIG_KVM_SMM) += smm.o
>>
>> kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
>> - vmx/hyperv.o vmx/nested.o vmx/posted_intr.o
>> + vmx/hyperv.o vmx/hyperv_evmcs.o vmx/nested.o vmx/posted_intr.o
>> kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
>>
>> ifdef CONFIG_HYPERV
>> diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c
>> index de13dc14fe1d..fab6a1ad98dc 100644
>> --- a/arch/x86/kvm/vmx/hyperv.c
>> +++ b/arch/x86/kvm/vmx/hyperv.c
>> @@ -13,314 +13,6 @@
>>
>> #define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK
>>
>> -#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
>> -#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
>> - {EVMCS1_OFFSET(name), clean_field}
>> -
>> -const struct evmcs_field vmcs_field_to_evmcs_1[] = {
>> - /* 64 bit rw */
>> - EVMCS1_FIELD(GUEST_RIP, guest_rip,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(GUEST_RSP, guest_rsp,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
>> - EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
>> - EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_CR0, host_cr0,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_CR3, host_cr3,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_CR4, host_cr4,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_RIP, host_rip,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
>> - EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
>> - EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
>> - EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> - EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> - EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> - EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> - EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> - EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> - EVMCS1_FIELD(GUEST_CR0, guest_cr0,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> - EVMCS1_FIELD(GUEST_CR3, guest_cr3,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> - EVMCS1_FIELD(GUEST_CR4, guest_cr4,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> - EVMCS1_FIELD(GUEST_DR7, guest_dr7,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> - EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> - EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> - EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> - EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> - EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> - EVMCS1_FIELD(HOST_RSP, host_rsp,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> - EVMCS1_FIELD(EPT_POINTER, ept_pointer,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
>> - EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> - EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> - EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> - /*
>> - * Not used by KVM:
>> - *
>> - * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - * EVMCS1_FIELD(0x0000682A, guest_ssp,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
>> - * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - * EVMCS1_FIELD(0x00006C1A, host_ssp,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - */
>> -
>> - /* 64 bit read only */
>> - EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - /*
>> - * Not defined in KVM:
>> - *
>> - * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
>> - * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
>> - * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
>> - * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
>> - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
>> - */
>> - EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> -
>> - /*
>> - * No mask defined in the spec as Hyper-V doesn't currently support
>> - * these. Future proof by resetting the whole clean field mask on
>> - * access.
>> - */
>> - EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> - EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> - EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> -
>> - /* 32 bit rw */
>> - EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
>> - EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
>> - EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
>> - EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
>> - EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
>> - EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
>> - vm_entry_exception_error_code,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
>> - EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
>> - EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
>> - EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
>> - EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
>> - EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> - EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> -
>> - /* 32 bit read only */
>> - EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> - EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> -
>> - /* No mask defined in the spec (not used) */
>> - EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> - EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> - EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> - EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> - EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> - EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> -
>> - /* 16 bit rw */
>> - EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> - EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> - EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
>> - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
>> -};
>> -const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
>> -
>> u64 nested_get_evmptr(struct kvm_vcpu *vcpu)
>> {
>> struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
>> diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
>> index 9401dbfaea7c..d4ed99008518 100644
>> --- a/arch/x86/kvm/vmx/hyperv.h
>> +++ b/arch/x86/kvm/vmx/hyperv.h
>> @@ -2,170 +2,9 @@
>> #ifndef __KVM_X86_VMX_HYPERV_H
>> #define __KVM_X86_VMX_HYPERV_H
>>
>> -#include <linux/jump_label.h>
>> -
>> -#include <asm/hyperv-tlfs.h>
>> -#include <asm/mshyperv.h>
>> -#include <asm/vmx.h>
>> -
>> -#include "../hyperv.h"
>> -
>> -#include "capabilities.h"
>> -#include "vmcs.h"
>> +#include <linux/kvm_host.h>
>> #include "vmcs12.h"
>>
>> -#define KVM_EVMCS_VERSION 1
>> -
>> -/*
>> - * Enlightened VMCSv1 doesn't support these:
>> - *
>> - * POSTED_INTR_NV = 0x00000002,
>> - * GUEST_INTR_STATUS = 0x00000810,
>> - * APIC_ACCESS_ADDR = 0x00002014,
>> - * POSTED_INTR_DESC_ADDR = 0x00002016,
>> - * EOI_EXIT_BITMAP0 = 0x0000201c,
>> - * EOI_EXIT_BITMAP1 = 0x0000201e,
>> - * EOI_EXIT_BITMAP2 = 0x00002020,
>> - * EOI_EXIT_BITMAP3 = 0x00002022,
>> - * GUEST_PML_INDEX = 0x00000812,
>> - * PML_ADDRESS = 0x0000200e,
>> - * VM_FUNCTION_CONTROL = 0x00002018,
>> - * EPTP_LIST_ADDRESS = 0x00002024,
>> - * VMREAD_BITMAP = 0x00002026,
>> - * VMWRITE_BITMAP = 0x00002028,
>> - *
>> - * TSC_MULTIPLIER = 0x00002032,
>> - * PLE_GAP = 0x00004020,
>> - * PLE_WINDOW = 0x00004022,
>> - * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
>> - *
>> - * Currently unsupported in KVM:
>> - * GUEST_IA32_RTIT_CTL = 0x00002814,
>> - */
>> -#define EVMCS1_SUPPORTED_PINCTRL \
>> - (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
>> - PIN_BASED_EXT_INTR_MASK | \
>> - PIN_BASED_NMI_EXITING | \
>> - PIN_BASED_VIRTUAL_NMIS)
>> -
>> -#define EVMCS1_SUPPORTED_EXEC_CTRL \
>> - (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
>> - CPU_BASED_HLT_EXITING | \
>> - CPU_BASED_CR3_LOAD_EXITING | \
>> - CPU_BASED_CR3_STORE_EXITING | \
>> - CPU_BASED_UNCOND_IO_EXITING | \
>> - CPU_BASED_MOV_DR_EXITING | \
>> - CPU_BASED_USE_TSC_OFFSETTING | \
>> - CPU_BASED_MWAIT_EXITING | \
>> - CPU_BASED_MONITOR_EXITING | \
>> - CPU_BASED_INVLPG_EXITING | \
>> - CPU_BASED_RDPMC_EXITING | \
>> - CPU_BASED_INTR_WINDOW_EXITING | \
>> - CPU_BASED_CR8_LOAD_EXITING | \
>> - CPU_BASED_CR8_STORE_EXITING | \
>> - CPU_BASED_RDTSC_EXITING | \
>> - CPU_BASED_TPR_SHADOW | \
>> - CPU_BASED_USE_IO_BITMAPS | \
>> - CPU_BASED_MONITOR_TRAP_FLAG | \
>> - CPU_BASED_USE_MSR_BITMAPS | \
>> - CPU_BASED_NMI_WINDOW_EXITING | \
>> - CPU_BASED_PAUSE_EXITING | \
>> - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
>> -
>> -#define EVMCS1_SUPPORTED_2NDEXEC \
>> - (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
>> - SECONDARY_EXEC_WBINVD_EXITING | \
>> - SECONDARY_EXEC_ENABLE_VPID | \
>> - SECONDARY_EXEC_ENABLE_EPT | \
>> - SECONDARY_EXEC_UNRESTRICTED_GUEST | \
>> - SECONDARY_EXEC_DESC | \
>> - SECONDARY_EXEC_ENABLE_RDTSCP | \
>> - SECONDARY_EXEC_ENABLE_INVPCID | \
>> - SECONDARY_EXEC_ENABLE_XSAVES | \
>> - SECONDARY_EXEC_RDSEED_EXITING | \
>> - SECONDARY_EXEC_RDRAND_EXITING | \
>> - SECONDARY_EXEC_TSC_SCALING | \
>> - SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
>> - SECONDARY_EXEC_PT_USE_GPA | \
>> - SECONDARY_EXEC_PT_CONCEAL_VMX | \
>> - SECONDARY_EXEC_BUS_LOCK_DETECTION | \
>> - SECONDARY_EXEC_NOTIFY_VM_EXITING | \
>> - SECONDARY_EXEC_ENCLS_EXITING)
>> -
>> -#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
>> -
>> -#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
>> - (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
>> - VM_EXIT_SAVE_DEBUG_CONTROLS | \
>> - VM_EXIT_ACK_INTR_ON_EXIT | \
>> - VM_EXIT_HOST_ADDR_SPACE_SIZE | \
>> - VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
>> - VM_EXIT_SAVE_IA32_PAT | \
>> - VM_EXIT_LOAD_IA32_PAT | \
>> - VM_EXIT_SAVE_IA32_EFER | \
>> - VM_EXIT_LOAD_IA32_EFER | \
>> - VM_EXIT_CLEAR_BNDCFGS | \
>> - VM_EXIT_PT_CONCEAL_PIP | \
>> - VM_EXIT_CLEAR_IA32_RTIT_CTL)
>> -
>> -#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
>> - (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
>> - VM_ENTRY_LOAD_DEBUG_CONTROLS | \
>> - VM_ENTRY_IA32E_MODE | \
>> - VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
>> - VM_ENTRY_LOAD_IA32_PAT | \
>> - VM_ENTRY_LOAD_IA32_EFER | \
>> - VM_ENTRY_LOAD_BNDCFGS | \
>> - VM_ENTRY_PT_CONCEAL_PIP | \
>> - VM_ENTRY_LOAD_IA32_RTIT_CTL)
>> -
>> -#define EVMCS1_SUPPORTED_VMFUNC (0)
>> -
>> -struct evmcs_field {
>> - u16 offset;
>> - u16 clean_field;
>> -};
>> -
>> -extern const struct evmcs_field vmcs_field_to_evmcs_1[];
>> -extern const unsigned int nr_evmcs_1_fields;
>> -
>> -static __always_inline int evmcs_field_offset(unsigned long field,
>> - u16 *clean_field)
>> -{
>> - unsigned int index = ROL16(field, 6);
>> - const struct evmcs_field *evmcs_field;
>> -
>> - if (unlikely(index >= nr_evmcs_1_fields))
>> - return -ENOENT;
>> -
>> - evmcs_field = &vmcs_field_to_evmcs_1[index];
>> -
>> - /*
>> - * Use offset=0 to detect holes in eVMCS. This offset belongs to
>> - * 'revision_id' but this field has no encoding and is supposed to
>> - * be accessed directly.
>> - */
>> - if (unlikely(!evmcs_field->offset))
>> - return -ENOENT;
>> -
>> - if (clean_field)
>> - *clean_field = evmcs_field->clean_field;
>> -
>> - return evmcs_field->offset;
>> -}
>> -
>> -static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
>> - unsigned long field, u16 offset)
>> -{
>> - /*
>> - * vmcs12_read_any() doesn't care whether the supplied structure
>> - * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
>> - * the exact offset of the required field, use it for convenience
>> - * here.
>> - */
>> - return vmcs12_read_any((void *)evmcs, field, offset);
>> -}
>> -
>> #define EVMPTR_INVALID (-1ULL)
>> #define EVMPTR_MAP_PENDING (-2ULL)
>>
>> diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.c b/arch/x86/kvm/vmx/hyperv_evmcs.c
>> new file mode 100644
>> index 000000000000..57a2e0470ac8
>> --- /dev/null
>> +++ b/arch/x86/kvm/vmx/hyperv_evmcs.c
>> @@ -0,0 +1,311 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +#include "hyperv_evmcs.h"
>> +
>> +#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
>> +#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
>> + {EVMCS1_OFFSET(name), clean_field}
>> +
>> +const struct evmcs_field vmcs_field_to_evmcs_1[] = {
>> + /* 64 bit rw */
>> + EVMCS1_FIELD(GUEST_RIP, guest_rip,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(GUEST_RSP, guest_rsp,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
>> + EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
>> + EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_CR0, host_cr0,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_CR3, host_cr3,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_CR4, host_cr4,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_RIP, host_rip,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
>> + EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
>> + EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
>> + EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> + EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> + EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> + EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> + EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> + EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> + EVMCS1_FIELD(GUEST_CR0, guest_cr0,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> + EVMCS1_FIELD(GUEST_CR3, guest_cr3,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> + EVMCS1_FIELD(GUEST_CR4, guest_cr4,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> + EVMCS1_FIELD(GUEST_DR7, guest_dr7,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
>> + EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> + EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> + EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> + EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> + EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> + EVMCS1_FIELD(HOST_RSP, host_rsp,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
>> + EVMCS1_FIELD(EPT_POINTER, ept_pointer,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
>> + EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> + EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> + EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
>> + /*
>> + * Not used by KVM:
>> + *
>> + * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + * EVMCS1_FIELD(0x0000682A, guest_ssp,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
>> + * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + * EVMCS1_FIELD(0x00006C1A, host_ssp,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + */
>> +
>> + /* 64 bit read only */
>> + EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + /*
>> + * Not defined in KVM:
>> + *
>> + * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
>> + * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
>> + * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
>> + * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
>> + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
>> + */
>> + EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> +
>> + /*
>> + * No mask defined in the spec as Hyper-V doesn't currently support
>> + * these. Future proof by resetting the whole clean field mask on
>> + * access.
>> + */
>> + EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> + EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> + EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> +
>> + /* 32 bit rw */
>> + EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
>> + EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
>> + EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
>> + EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
>> + EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
>> + EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
>> + vm_entry_exception_error_code,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
>> + EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
>> + EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
>> + EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
>> + EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
>> + EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> + EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
>> +
>> + /* 32 bit read only */
>> + EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> + EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
>> +
>> + /* No mask defined in the spec (not used) */
>> + EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> + EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> + EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> + EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> + EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> + EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
>> +
>> + /* 16 bit rw */
>> + EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
>> + EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
>> + EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
>> + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
>> +};
>> +const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
>> diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.h b/arch/x86/kvm/vmx/hyperv_evmcs.h
>> new file mode 100644
>> index 000000000000..11d96975e7cc
>> --- /dev/null
>> +++ b/arch/x86/kvm/vmx/hyperv_evmcs.h
>> @@ -0,0 +1,162 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +#ifndef __KVM_X86_VMX_HYPERV_EVMCS_H
>> +#define __KVM_X86_VMX_HYPERV_EVMCS_H
>> +
>> +#include <asm/hyperv-tlfs.h>
>> +
>> +#include "capabilities.h"
>> +#include "vmcs12.h"
>> +
>> +#define KVM_EVMCS_VERSION 1
>> +
>> +/*
>> + * Enlightened VMCSv1 doesn't support these:
>> + *
>> + * POSTED_INTR_NV = 0x00000002,
>> + * GUEST_INTR_STATUS = 0x00000810,
>> + * APIC_ACCESS_ADDR = 0x00002014,
>> + * POSTED_INTR_DESC_ADDR = 0x00002016,
>> + * EOI_EXIT_BITMAP0 = 0x0000201c,
>> + * EOI_EXIT_BITMAP1 = 0x0000201e,
>> + * EOI_EXIT_BITMAP2 = 0x00002020,
>> + * EOI_EXIT_BITMAP3 = 0x00002022,
>> + * GUEST_PML_INDEX = 0x00000812,
>> + * PML_ADDRESS = 0x0000200e,
>> + * VM_FUNCTION_CONTROL = 0x00002018,
>> + * EPTP_LIST_ADDRESS = 0x00002024,
>> + * VMREAD_BITMAP = 0x00002026,
>> + * VMWRITE_BITMAP = 0x00002028,
>> + *
>> + * TSC_MULTIPLIER = 0x00002032,
>> + * PLE_GAP = 0x00004020,
>> + * PLE_WINDOW = 0x00004022,
>> + * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
>> + *
>> + * Currently unsupported in KVM:
>> + * GUEST_IA32_RTIT_CTL = 0x00002814,
>> + */
>> +#define EVMCS1_SUPPORTED_PINCTRL \
>> + (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
>> + PIN_BASED_EXT_INTR_MASK | \
>> + PIN_BASED_NMI_EXITING | \
>> + PIN_BASED_VIRTUAL_NMIS)
>> +
>> +#define EVMCS1_SUPPORTED_EXEC_CTRL \
>> + (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
>> + CPU_BASED_HLT_EXITING | \
>> + CPU_BASED_CR3_LOAD_EXITING | \
>> + CPU_BASED_CR3_STORE_EXITING | \
>> + CPU_BASED_UNCOND_IO_EXITING | \
>> + CPU_BASED_MOV_DR_EXITING | \
>> + CPU_BASED_USE_TSC_OFFSETTING | \
>> + CPU_BASED_MWAIT_EXITING | \
>> + CPU_BASED_MONITOR_EXITING | \
>> + CPU_BASED_INVLPG_EXITING | \
>> + CPU_BASED_RDPMC_EXITING | \
>> + CPU_BASED_INTR_WINDOW_EXITING | \
>> + CPU_BASED_CR8_LOAD_EXITING | \
>> + CPU_BASED_CR8_STORE_EXITING | \
>> + CPU_BASED_RDTSC_EXITING | \
>> + CPU_BASED_TPR_SHADOW | \
>> + CPU_BASED_USE_IO_BITMAPS | \
>> + CPU_BASED_MONITOR_TRAP_FLAG | \
>> + CPU_BASED_USE_MSR_BITMAPS | \
>> + CPU_BASED_NMI_WINDOW_EXITING | \
>> + CPU_BASED_PAUSE_EXITING | \
>> + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
>> +
>> +#define EVMCS1_SUPPORTED_2NDEXEC \
>> + (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
>> + SECONDARY_EXEC_WBINVD_EXITING | \
>> + SECONDARY_EXEC_ENABLE_VPID | \
>> + SECONDARY_EXEC_ENABLE_EPT | \
>> + SECONDARY_EXEC_UNRESTRICTED_GUEST | \
>> + SECONDARY_EXEC_DESC | \
>> + SECONDARY_EXEC_ENABLE_RDTSCP | \
>> + SECONDARY_EXEC_ENABLE_INVPCID | \
>> + SECONDARY_EXEC_ENABLE_XSAVES | \
>> + SECONDARY_EXEC_RDSEED_EXITING | \
>> + SECONDARY_EXEC_RDRAND_EXITING | \
>> + SECONDARY_EXEC_TSC_SCALING | \
>> + SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
>> + SECONDARY_EXEC_PT_USE_GPA | \
>> + SECONDARY_EXEC_PT_CONCEAL_VMX | \
>> + SECONDARY_EXEC_BUS_LOCK_DETECTION | \
>> + SECONDARY_EXEC_NOTIFY_VM_EXITING | \
>> + SECONDARY_EXEC_ENCLS_EXITING)
>> +
>> +#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
>> +
>> +#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
>> + (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
>> + VM_EXIT_SAVE_DEBUG_CONTROLS | \
>> + VM_EXIT_ACK_INTR_ON_EXIT | \
>> + VM_EXIT_HOST_ADDR_SPACE_SIZE | \
>> + VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
>> + VM_EXIT_SAVE_IA32_PAT | \
>> + VM_EXIT_LOAD_IA32_PAT | \
>> + VM_EXIT_SAVE_IA32_EFER | \
>> + VM_EXIT_LOAD_IA32_EFER | \
>> + VM_EXIT_CLEAR_BNDCFGS | \
>> + VM_EXIT_PT_CONCEAL_PIP | \
>> + VM_EXIT_CLEAR_IA32_RTIT_CTL)
>> +
>> +#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
>> + (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
>> + VM_ENTRY_LOAD_DEBUG_CONTROLS | \
>> + VM_ENTRY_IA32E_MODE | \
>> + VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
>> + VM_ENTRY_LOAD_IA32_PAT | \
>> + VM_ENTRY_LOAD_IA32_EFER | \
>> + VM_ENTRY_LOAD_BNDCFGS | \
>> + VM_ENTRY_PT_CONCEAL_PIP | \
>> + VM_ENTRY_LOAD_IA32_RTIT_CTL)
>> +
>> +#define EVMCS1_SUPPORTED_VMFUNC (0)
>> +
>> +struct evmcs_field {
>> + u16 offset;
>> + u16 clean_field;
>> +};
>> +
>> +extern const struct evmcs_field vmcs_field_to_evmcs_1[];
>> +extern const unsigned int nr_evmcs_1_fields;
>> +
>> +static __always_inline int evmcs_field_offset(unsigned long field,
>> + u16 *clean_field)
>> +{
>> + unsigned int index = ROL16(field, 6);
>> + const struct evmcs_field *evmcs_field;
>> +
>> + if (unlikely(index >= nr_evmcs_1_fields))
>> + return -ENOENT;
>> +
>> + evmcs_field = &vmcs_field_to_evmcs_1[index];
>> +
>> + /*
>> + * Use offset=0 to detect holes in eVMCS. This offset belongs to
>> + * 'revision_id' but this field has no encoding and is supposed to
>> + * be accessed directly.
>> + */
>> + if (unlikely(!evmcs_field->offset))
>> + return -ENOENT;
>> +
>> + if (clean_field)
>> + *clean_field = evmcs_field->clean_field;
>> +
>> + return evmcs_field->offset;
>> +}
>> +
>> +static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
>> + unsigned long field, u16 offset)
>> +{
>> + /*
>> + * vmcs12_read_any() doesn't care whether the supplied structure
>> + * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
>> + * the exact offset of the required field, use it for convenience
>> + * here.
>> + */
>> + return vmcs12_read_any((void *)evmcs, field, offset);
>> +}
>> +
>> +#endif /* __KVM_X86_VMX_HYPERV_H */
>> diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h
>> index 11541d272dbd..eb48153bfd73 100644
>> --- a/arch/x86/kvm/vmx/vmx_onhyperv.h
>> +++ b/arch/x86/kvm/vmx/vmx_onhyperv.h
>> @@ -4,11 +4,12 @@
>> #define __ARCH_X86_KVM_VMX_ONHYPERV_H__
>>
>> #include <asm/hyperv-tlfs.h>
>> +#include <asm/mshyperv.h>
>>
>> #include <linux/jump_label.h>
>>
>> #include "capabilities.h"
>> -#include "hyperv.h"
>> +#include "hyperv_evmcs.h"
>> #include "vmcs12.h"
>>
>> #define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
>
>
> This patch fails the build because of vmx_has_valid_vmcs12() in nested.h which uses EVMPTR_INVALID.
>
> vmx/nested.h includes vmx/vmx.h which includes vmx_ops.h, it includes vmx_onhyperv.h which used to include hyperv.h but not anymore.
>
> We can either add hyperv.h to vmx/nested.h, or we can move the code in
> vmx_has_valid_vmcs12 to hyperv_evmcs.h.
That's weird as I'm pretty sure I've tested all 4 option states for
CONFIG_KVM_HYPERV/CONFIG_HYPERV before sending this out but I'll retest.
>
>
> Besides the build error,
> Reviewed-by: Maxim Levitsky <[email protected]>
>
> Best regards,
> Maxim Levitsky
>
>
>
--
Vitaly
Maxim Levitsky <[email protected]> writes:
> У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
>> Hyper-V emulation in KVM is a fairly big chunk and in some cases it may be
>> desirable to not compile it in to reduce module sizes as well as attack
>> surface. Introduce CONFIG_KVM_HYPERV option to make it possible.
>>
>> Note, there's room for further nVMX/nSVM code optimizations when
>> !CONFIG_KVM_HYPERV, this will be done in follow-up patches.
>
> Maybe CONFIG_KVM_HYPERV_GUEST_SUPPORT or CONFIG_HYPERV_ON_KVM instead?
>
> IMHO CONFIG_KVM_HYPERV_GUEST_SUPPORT sounds good.
We already have CONFIG_KVM_XEN so I decided to stay concise. I do
understand that 'KVM-on-Hyper-V' and 'Hyper-V-on-KVM' mess which creates
the confusion though.
>
>>
>> Signed-off-by: Vitaly Kuznetsov <[email protected]>
>> ---
>> arch/x86/include/asm/kvm_host.h | 4 +++
>> arch/x86/kvm/Kconfig | 9 ++++++
>> arch/x86/kvm/Makefile | 17 +++++++---
>> arch/x86/kvm/cpuid.c | 6 ++++
>> arch/x86/kvm/hyperv.h | 29 +++++++++++++++--
>> arch/x86/kvm/irq_comm.c | 9 +++++-
>> arch/x86/kvm/svm/hyperv.h | 7 +++++
>> arch/x86/kvm/svm/nested.c | 2 ++
>> arch/x86/kvm/svm/svm_onhyperv.h | 2 ++
>> arch/x86/kvm/vmx/hyperv.h | 8 +++++
>> arch/x86/kvm/vmx/nested.c | 17 ++++++++++
>> arch/x86/kvm/x86.c | 56 +++++++++++++++++++++++----------
>> 12 files changed, 143 insertions(+), 23 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index 711dc880a9f0..b0a55b736b47 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -1085,6 +1085,7 @@ enum hv_tsc_page_status {
>> HV_TSC_PAGE_BROKEN,
>> };
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> /* Hyper-V emulation context */
>> struct kvm_hv {
>> struct mutex hv_lock;
>> @@ -1117,6 +1118,7 @@ struct kvm_hv {
>>
>> struct kvm_hv_syndbg hv_syndbg;
>> };
>> +#endif
>>
>> struct msr_bitmap_range {
>> u32 flags;
>> @@ -1338,7 +1340,9 @@ struct kvm_arch {
>> /* reads protected by irq_srcu, writes by irq_lock */
>> struct hlist_head mask_notifier_list;
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> struct kvm_hv hyperv;
>> +#endif
>>
>> #ifdef CONFIG_KVM_XEN
>> struct kvm_xen xen;
>> diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
>> index ed90f148140d..a06e19a8a8f6 100644
>> --- a/arch/x86/kvm/Kconfig
>> +++ b/arch/x86/kvm/Kconfig
>> @@ -129,6 +129,15 @@ config KVM_SMM
>>
>> If unsure, say Y.
>>
>> +config KVM_HYPERV
>> + bool "Support for Microsoft Hyper-V emulation"
>> + depends on KVM
>> + default y
>> + help
>> + Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
>
>
> It feels to me that the KConfig option can have a longer description.
>
> What do you think about something like that:
>
> "Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
>
> This makes KVM expose a set of paravirtualized interfaces,
> documented in the HyperV TLFS,
> https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs,
> which consists of a subset of paravirtualized interfaces that HyperV exposes
> to its guests.
>
> This improves performance of modern Windows guests.
>
> Say Y, unless you are sure that this kernel will not be used to run Windows guests."
Thanks) This was an RFC so I was too lazy to write such a paragraph :-)
>
>
>> +
>> + If unsure, say "Y".
>> +
>> config KVM_XEN
>> bool "Support for Xen hypercall interface"
>> depends on KVM
>> diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
>> index 8ea872401cd6..ccd477178f07 100644
>> --- a/arch/x86/kvm/Makefile
>> +++ b/arch/x86/kvm/Makefile
>> @@ -11,7 +11,7 @@ include $(srctree)/virt/kvm/Makefile.kvm
>>
>> kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \
>> i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
>> - hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \
>> + debugfs.o mmu/mmu.o mmu/page_track.o \
>> mmu/spte.o
>>
>> ifdef CONFIG_HYPERV
>> @@ -19,19 +19,28 @@ kvm-y += kvm_onhyperv.o
>> endif
>>
>> kvm-$(CONFIG_X86_64) += mmu/tdp_iter.o mmu/tdp_mmu.o
>> +kvm-$(CONFIG_KVM_HYPERV) += hyperv.o
>> kvm-$(CONFIG_KVM_XEN) += xen.o
>> kvm-$(CONFIG_KVM_SMM) += smm.o
>>
>> kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
>> - vmx/hyperv.o vmx/hyperv_evmcs.o vmx/nested.o vmx/posted_intr.o
>> + vmx/nested.o vmx/posted_intr.o
>> +ifdef CONFIG_KVM_HYPERV
>> +kvm-intel-y += vmx/hyperv.o vmx/hyperv_evmcs.o
>> +endif
>> +
>> kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
>>
>> ifdef CONFIG_HYPERV
>> -kvm-intel-y += vmx/vmx_onhyperv.o
>> +kvm-intel-y += vmx/vmx_onhyperv.o vmx/hyperv_evmcs.o
>> endif
>>
>> kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \
>> - svm/sev.o svm/hyperv.o
>> + svm/sev.o
>> +
>> +ifdef CONFIG_KVM_HYPERV
>> +kvm-amd-y += svm/hyperv.o
>> +endif
>
> I think that we can group all the files under one
> 'ifdef CONFIG_KVM_HYPERV'.
We sure can..
>
>>
>> ifdef CONFIG_HYPERV
>> kvm-amd-y += svm/svm_onhyperv.o
>> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
>> index 0544e30b4946..7a3533573f94 100644
>> --- a/arch/x86/kvm/cpuid.c
>> +++ b/arch/x86/kvm/cpuid.c
>> @@ -314,11 +314,15 @@ EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime);
>>
>> static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent)
>> {
>> +#ifdef CONFIG_KVM_HYPERV
>> struct kvm_cpuid_entry2 *entry;
>>
>> entry = cpuid_entry2_find(entries, nent, HYPERV_CPUID_INTERFACE,
>> KVM_CPUID_INDEX_NOT_SIGNIFICANT);
>> return entry && entry->eax == HYPERV_CPUID_SIGNATURE_EAX;
>> +#else
>> + return false;
>> +#endif
>
> Do you think that it might make sense to still complain loudly if the userspace
> still tries to enable hyperv cpuid?
I don't think so. In fact, userspace can now set whatever it wants in
guest visible CPUIDs, e.g. pretend being Vmware/Virtualbox/... and KVM
will just pass it through. Enabling Hyper-V specific KVM capabilities
must fail, of course.
>
>> }
>>
>> static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
>> @@ -441,11 +445,13 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
>> return 0;
>> }
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> if (kvm_cpuid_has_hyperv(e2, nent)) {
>> r = kvm_hv_vcpu_init(vcpu);
>> if (r)
>> return r;
>> }
>> +#endif
>>
>> r = kvm_check_cpuid(vcpu, e2, nent);
>> if (r)
>> diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
>> index ddb1d0b019e6..3a6acd8a9fa8 100644
>> --- a/arch/x86/kvm/hyperv.h
>> +++ b/arch/x86/kvm/hyperv.h
>> @@ -24,6 +24,8 @@
>> #include <linux/kvm_host.h>
>> #include "x86.h"
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> +
>> /* "Hv#1" signature */
>> #define HYPERV_CPUID_SIGNATURE_EAX 0x31237648
>>
>> @@ -247,5 +249,28 @@ static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu)
>> }
>>
>> int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu);
>> -
>> -#endif
>> +#else /* CONFIG_KVM_HYPERV */
>> +static inline void kvm_hv_setup_tsc_page(struct kvm *kvm,
>> + struct pvclock_vcpu_time_info *hv_clock) {}
>> +static inline void kvm_hv_request_tsc_page_update(struct kvm *kvm) {}
>> +static inline void kvm_hv_init_vm(struct kvm *kvm) {}
>> +static inline void kvm_hv_destroy_vm(struct kvm *kvm) {}
>> +static inline int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu) { return 0; }
>> +static inline void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu) {}
>> +static inline bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu) { return false; }
>> +static inline int kvm_hv_hypercall(struct kvm_vcpu *vcpu) { return HV_STATUS_ACCESS_DENIED; }
>> +static inline void kvm_hv_vcpu_purge_flush_tlb(struct kvm_vcpu *vcpu) {}
>> +static inline void kvm_hv_free_pa_page(struct kvm *kvm) {}
>> +static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector) { return false; }
>> +static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector) { return false; }
>> +static inline void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector) {}
>> +static inline bool kvm_hv_invtsc_suppressed(struct kvm_vcpu *vcpu) { return false; }
>> +static inline void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu, bool hyperv_enabled) {}
>> +static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu) { return false; }
>> +static inline bool kvm_hv_is_tlb_flush_hcall(struct kvm_vcpu *vcpu) { return false; }
>> +static inline bool guest_hv_cpuid_has_l2_tlb_flush(struct kvm_vcpu *vcpu) { return false; }
>> +static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu) { return 0; }
>> +static inline u32 kvm_hv_get_vpindex(struct kvm_vcpu *vcpu) { return vcpu->vcpu_idx; }
>> +#endif /* CONFIG_KVM_HYPERV */
>> +
>> +#endif /* __ARCH_X86_KVM_HYPERV_H__ */
>> diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
>> index 16d076a1b91a..68f3f6c26046 100644
>> --- a/arch/x86/kvm/irq_comm.c
>> +++ b/arch/x86/kvm/irq_comm.c
>> @@ -144,7 +144,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
>> return kvm_irq_delivery_to_apic(kvm, NULL, &irq, NULL);
>> }
>>
>> -
>> +#ifdef CONFIG_KVM_HYPERV
>> static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
>> struct kvm *kvm, int irq_source_id, int level,
>> bool line_status)
>> @@ -154,6 +154,7 @@ static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
>>
>> return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
>> }
>> +#endif
>>
>> int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
>> struct kvm *kvm, int irq_source_id, int level,
>> @@ -163,9 +164,11 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
>> int r;
>>
>> switch (e->type) {
>> +#ifdef CONFIG_KVM_HYPERV
>> case KVM_IRQ_ROUTING_HV_SINT:
>> return kvm_hv_set_sint(e, kvm, irq_source_id, level,
>> line_status);
>> +#endif
>>
>> case KVM_IRQ_ROUTING_MSI:
>> if (kvm_msi_route_invalid(kvm, e))
>> @@ -314,11 +317,13 @@ int kvm_set_routing_entry(struct kvm *kvm,
>> if (kvm_msi_route_invalid(kvm, e))
>> return -EINVAL;
>> break;
>> +#ifdef CONFIG_KVM_HYPERV
>> case KVM_IRQ_ROUTING_HV_SINT:
>> e->set = kvm_hv_set_sint;
>> e->hv_sint.vcpu = ue->u.hv_sint.vcpu;
>> e->hv_sint.sint = ue->u.hv_sint.sint;
>> break;
>> +#endif
>> #ifdef CONFIG_KVM_XEN
>> case KVM_IRQ_ROUTING_XEN_EVTCHN:
>> return kvm_xen_setup_evtchn(kvm, e, ue);
>> @@ -438,5 +443,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
>>
>> void kvm_arch_irq_routing_update(struct kvm *kvm)
>> {
>> +#ifdef CONFIG_KVM_HYPERV
>> kvm_hv_irq_routing_update(kvm);
>> +#endif
>> }
>> diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h
>> index 02f4784b5d44..14eec2d9b6be 100644
>> --- a/arch/x86/kvm/svm/hyperv.h
>> +++ b/arch/x86/kvm/svm/hyperv.h
>> @@ -11,6 +11,7 @@
>> #include "../hyperv.h"
>> #include "svm.h"
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu)
>> {
>> struct vcpu_svm *svm = to_svm(vcpu);
>> @@ -41,5 +42,11 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
>> }
>>
>> void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
>> +#else /* CONFIG_KVM_HYPERV */
>> +static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {}
>> +static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
>> +static inline void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu) {}
>> +#endif /* CONFIG_KVM_HYPERV */
>> +
>>
>> #endif /* __ARCH_X86_KVM_SVM_HYPERV_H__ */
>> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
>> index dd496c9e5f91..4d8cd378a30b 100644
>> --- a/arch/x86/kvm/svm/nested.c
>> +++ b/arch/x86/kvm/svm/nested.c
>> @@ -487,6 +487,7 @@ static void nested_save_pending_event_to_vmcb12(struct vcpu_svm *svm,
>>
>> static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
>> {
>> +#ifdef CONFIG_KVM_HYPERV
>> /*
>> * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
>> * L2's VP_ID upon request from the guest. Make sure we check for
>> @@ -495,6 +496,7 @@ static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
>> */
>> if (to_hv_vcpu(vcpu) && npt_enabled)
>> kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
>> +#endif
>>
>> /*
>> * TODO: optimize unconditional TLB flush/MMU sync. A partial list of
>> diff --git a/arch/x86/kvm/svm/svm_onhyperv.h b/arch/x86/kvm/svm/svm_onhyperv.h
>> index f85bc617ffe4..c25cf56e6adb 100644
>> --- a/arch/x86/kvm/svm/svm_onhyperv.h
>> +++ b/arch/x86/kvm/svm/svm_onhyperv.h
>> @@ -79,6 +79,7 @@ static inline void svm_hv_vmcb_dirty_nested_enlightenments(
>>
>> static inline void svm_hv_update_vp_id(struct vmcb *vmcb, struct kvm_vcpu *vcpu)
>> {
>> +#ifdef CONFIG_KVM_HYPERV
>> struct hv_vmcb_enlightenments *hve = &vmcb->control.hv_enlightenments;
>> u32 vp_index = kvm_hv_get_vpindex(vcpu);
>>
>> @@ -86,6 +87,7 @@ static inline void svm_hv_update_vp_id(struct vmcb *vmcb, struct kvm_vcpu *vcpu)
>> hve->hv_vp_id = vp_index;
>> vmcb_mark_dirty(vmcb, HV_VMCB_NESTED_ENLIGHTENMENTS);
>> }
>> +#endif
>> }
>> #else
>>
>> diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
>> index d4ed99008518..933ef6cad5e6 100644
>> --- a/arch/x86/kvm/vmx/hyperv.h
>> +++ b/arch/x86/kvm/vmx/hyperv.h
>> @@ -20,6 +20,7 @@ enum nested_evmptrld_status {
>> EVMPTRLD_ERROR,
>> };
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
>> uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
>> int nested_enable_evmcs(struct kvm_vcpu *vcpu,
>> @@ -28,5 +29,12 @@ void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *
>> int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
>> bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
>> void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
>> +#else
>> +static inline u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { return EVMPTR_INVALID; }
>> +static inline void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) {}
>> +static inline bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
>> +static inline int nested_evmcs_check_controls(struct vmcs12 *vmcs12) { return 0; }
>> +#endif
>> +
>>
>> #endif /* __KVM_X86_VMX_HYPERV_H */
>> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
>> index c5ec0ef51ff7..ca7e06759aa3 100644
>> --- a/arch/x86/kvm/vmx/nested.c
>> +++ b/arch/x86/kvm/vmx/nested.c
>> @@ -226,6 +226,7 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx)
>>
>> static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
>> {
>> +#ifdef CONFIG_KVM_HYPERV
>> struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
>> struct vcpu_vmx *vmx = to_vmx(vcpu);
>>
>> @@ -241,6 +242,7 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
>> hv_vcpu->nested.vm_id = 0;
>> hv_vcpu->nested.vp_id = 0;
>> }
>> +#endif
>> }
>>
>> static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx,
>> @@ -1139,6 +1141,7 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
>> {
>> struct vcpu_vmx *vmx = to_vmx(vcpu);
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> /*
>> * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
>> * L2's VP_ID upon request from the guest. Make sure we check for
>> @@ -1147,6 +1150,7 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
>> */
>> if (to_hv_vcpu(vcpu) && enable_ept)
>> kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
>> +#endif
>>
>> /*
>> * If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
>> @@ -1576,6 +1580,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
>> vmcs_load(vmx->loaded_vmcs->vmcs);
>> }
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
>> {
>> struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
>> @@ -2083,6 +2088,10 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
>>
>> return EVMPTRLD_SUCCEEDED;
>> }
>> +#else /* CONFIG_KVM_HYPERV */
>> +static inline void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields) {}
>> +static inline void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx) {}
>> +#endif /* CONFIG_KVM_HYPERV */
>>
>> void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
>> {
>> @@ -3161,6 +3170,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
>> return 0;
>> }
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
>> {
>> struct vcpu_vmx *vmx = to_vmx(vcpu);
>> @@ -3188,6 +3198,9 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
>>
>> return true;
>> }
>> +#else
>> +static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu) { return true; }
>> +#endif
>>
>> static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
>> {
>> @@ -3558,11 +3571,13 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
>> if (!nested_vmx_check_permission(vcpu))
>> return 1;
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> evmptrld_status = nested_vmx_handle_enlightened_vmptrld(vcpu, launch);
>> if (evmptrld_status == EVMPTRLD_ERROR) {
>> kvm_queue_exception(vcpu, UD_VECTOR);
>> return 1;
>> }
>> +#endif
>>
>> kvm_pmu_trigger_event(vcpu, PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
>>
>> @@ -7096,7 +7111,9 @@ struct kvm_x86_nested_ops vmx_nested_ops = {
>> .set_state = vmx_set_nested_state,
>> .get_nested_state_pages = vmx_get_nested_state_pages,
>> .write_log_dirty = nested_vmx_write_pml_buffer,
>> +#ifdef CONFIG_KVM_HYPERV
>> .enable_evmcs = nested_enable_evmcs,
>> .get_evmcs_version = nested_get_evmcs_version,
>> .hv_inject_synthetic_vmexit_post_tlb_flush = vmx_hv_inject_synthetic_vmexit_post_tlb_flush,
>> +#endif
>> };
>> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
>> index e273ce8e0b3f..78e18d28bc61 100644
>> --- a/arch/x86/kvm/x86.c
>> +++ b/arch/x86/kvm/x86.c
>> @@ -1504,6 +1504,8 @@ static unsigned num_msrs_to_save;
>> static const u32 emulated_msrs_all[] = {
>> MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
>> MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
>> +
>> +#ifdef CONFIG_KVM_HYPERV
>> HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
>> HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC,
>> HV_X64_MSR_TSC_FREQUENCY, HV_X64_MSR_APIC_FREQUENCY,
>> @@ -1521,6 +1523,7 @@ static const u32 emulated_msrs_all[] = {
>> HV_X64_MSR_SYNDBG_CONTROL, HV_X64_MSR_SYNDBG_STATUS,
>> HV_X64_MSR_SYNDBG_SEND_BUFFER, HV_X64_MSR_SYNDBG_RECV_BUFFER,
>> HV_X64_MSR_SYNDBG_PENDING_BUFFER,
>> +#endif
>>
>> MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
>> MSR_KVM_PV_EOI_EN, MSR_KVM_ASYNC_PF_INT, MSR_KVM_ASYNC_PF_ACK,
>> @@ -3914,6 +3917,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>> * the need to ignore the workaround.
>> */
>> break;
>> +#ifdef CONFIG_KVM_HYPERV
>> case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
>> case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
>> case HV_X64_MSR_SYNDBG_OPTIONS:
>> @@ -3926,6 +3930,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>> case HV_X64_MSR_TSC_INVARIANT_CONTROL:
>> return kvm_hv_set_msr_common(vcpu, msr, data,
>> msr_info->host_initiated);
>> +#endif
>> case MSR_IA32_BBL_CR_CTL3:
>> /* Drop writes to this legacy MSR -- see rdmsr
>> * counterpart for further detail.
>> @@ -4270,6 +4275,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>> */
>> msr_info->data = 0x20000000;
>> break;
>> +#ifdef CONFIG_KVM_HYPERV
>> case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
>> case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
>> case HV_X64_MSR_SYNDBG_OPTIONS:
>> @@ -4283,6 +4289,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>> return kvm_hv_get_msr_common(vcpu,
>> msr_info->index, &msr_info->data,
>> msr_info->host_initiated);
>> +#endif
>> case MSR_IA32_BBL_CR_CTL3:
>> /* This legacy MSR exists but isn't fully documented in current
>> * silicon. It is however accessed by winxp in very narrow
>> @@ -4420,6 +4427,7 @@ static inline bool kvm_can_mwait_in_guest(void)
>> boot_cpu_has(X86_FEATURE_ARAT);
>> }
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
>> struct kvm_cpuid2 __user *cpuid_arg)
>> {
>> @@ -4440,6 +4448,7 @@ static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
>>
>> return 0;
>> }
>> +#endif
>>
>> int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>> {
>> @@ -4764,9 +4773,11 @@ long kvm_arch_dev_ioctl(struct file *filp,
>> case KVM_GET_MSRS:
>> r = msr_io(NULL, argp, do_get_msr_feature, 1);
>> break;
>> +#ifdef CONFIG_KVM_HYPERV
>> case KVM_GET_SUPPORTED_HV_CPUID:
>> r = kvm_ioctl_get_supported_hv_cpuid(NULL, argp);
>> break;
>> +#endif
>> case KVM_GET_DEVICE_ATTR: {
>> struct kvm_device_attr attr;
>> r = -EFAULT;
>> @@ -5580,14 +5591,11 @@ static int kvm_vcpu_ioctl_device_attr(struct kvm_vcpu *vcpu,
>> static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
>> struct kvm_enable_cap *cap)
>> {
>> - int r;
>> - uint16_t vmcs_version;
>> - void __user *user_ptr;
>> -
>> if (cap->flags)
>> return -EINVAL;
>>
>> switch (cap->cap) {
>> +#ifdef CONFIG_KVM_HYPERV
>> case KVM_CAP_HYPERV_SYNIC2:
>> if (cap->args[0])
>> return -EINVAL;
>> @@ -5599,16 +5607,22 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
>> return kvm_hv_activate_synic(vcpu, cap->cap ==
>> KVM_CAP_HYPERV_SYNIC2);
>> case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
>> - if (!kvm_x86_ops.nested_ops->enable_evmcs)
>> - return -ENOTTY;
>> - r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
>> - if (!r) {
>> - user_ptr = (void __user *)(uintptr_t)cap->args[0];
>> - if (copy_to_user(user_ptr, &vmcs_version,
>> - sizeof(vmcs_version)))
>> - r = -EFAULT;
>> + {
>> + int r;
>> + uint16_t vmcs_version;
>> + void __user *user_ptr;CONFIG_KVM_HYPERV_GUEST_SUPPORT
>> +
>> + if (!kvm_x86_ops.nested_ops->enable_evmcs)
>> + return -ENOTTY;
>> + r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
>> + if (!r) {
>> + user_ptr = (void __user *)(uintptr_t)cap->args[0];
>> + if (copy_to_user(user_ptr, &vmcs_version,
>> + sizeof(vmcs_version)))
>> + r = -EFAULT;
>> + }
>> + return r;
>> }
>> - return r;
>> case KVM_CAP_HYPERV_DIRECT_TLBFLUSH:
>> if (!kvm_x86_ops.enable_l2_tlb_flush)
>> return -ENOTTY;
>> @@ -5617,6 +5631,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
>>
>> case KVM_CAP_HYPERV_ENFORCE_CPUID:
>> return kvm_hv_set_enforce_cpuid(vcpu, cap->args[0]);
>> +#endif
>>
>> case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
>> vcpu->arch.pv_cpuid.enforce = cap->args[0];
>> @@ -6009,9 +6024,11 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>> srcu_read_unlock(&vcpu->kvm->srcu, idx);
>> break;
>> }
>> +#ifdef CONFIG_KVM_HYPERV
>> case KVM_GET_SUPPORTED_HV_CPUID:
>> r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp);
>> break;
>> +#endif
>> #ifdef CONFIG_KVM_XEN
>> case KVM_XEN_VCPU_GET_ATTR: {
>> struct kvm_xen_vcpu_attr xva;
>> @@ -7066,6 +7083,7 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
>> r = static_call(kvm_x86_mem_enc_unregister_region)(kvm, ®ion);
>> break;
>> }
>> +#ifdef CONFIG_KVM_HYPERV
>> case KVM_HYPERV_EVENTFD: {
>> struct kvm_hyperv_eventfd hvevfd;
>>
>> @@ -7075,6 +7093,7 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
>> r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd);
>> break;
>> }
>> +#endif
>> case KVM_SET_PMU_EVENT_FILTER:
>> r = kvm_vm_ioctl_set_pmu_event_filter(kvm, argp);
>> break;
>> @@ -10445,19 +10464,20 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
>>
>> static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
>> {
>> - u64 eoi_exit_bitmap[4];
>> -
>> if (!kvm_apic_hw_enabled(vcpu->arch.apic))
>> return;
>>
>> +#ifdef CONFIG_KVM_HYPERV
>> if (to_hv_vcpu(vcpu)) {
>> + u64 eoi_exit_bitmap[4];
>> +
>> bitmap_or((ulong *)eoi_exit_bitmap,
>> vcpu->arch.ioapic_handled_vectors,
>> to_hv_synic(vcpu)->vec_bitmap, 256);
>> static_call_cond(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap);
>> return;
>> }
>> -
>> +#endif
>> static_call_cond(kvm_x86_load_eoi_exitmap)(
>> vcpu, (u64 *)vcpu->arch.ioapic_handled_vectors);
>> }
>> @@ -10548,9 +10568,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>> * the flushes are considered "remote" and not "local" because
>> * the requests can be initiated from other vCPUs.
>> */
>> +#ifdef CONFIG_KVM_HYPERV
>> if (kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu) &&
>> kvm_hv_vcpu_flush_tlb(vcpu))
>> kvm_vcpu_flush_tlb_guest(vcpu);
>> +#endif
>>
>> if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
>> vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
>> @@ -10603,6 +10625,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>> vcpu_load_eoi_exitmap(vcpu);
>> if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
>> kvm_vcpu_reload_apic_access_page(vcpu);
>> +#ifdef CONFIG_KVM_HYPERV
>> if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) {
>> vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
>> vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH;
>> @@ -10633,6 +10656,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>> */
>> if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
>> kvm_hv_process_stimers(vcpu);
>> +#endif
>> if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
>> kvm_vcpu_update_apicv(vcpu);
>> if (kvm_check_request(KVM_REQ_APF_READY, vcpu))
>
>
> Looks reasonable, I didn't check everything though, I might have missed something.
>
>
> Best regards,
> Maxim Levitsky
>
--
Vitaly
Maxim Levitsky <[email protected]> writes:
> У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
>> 'vmx->nested.hv_evmcs_vmptr' accesses are all over the place so hiding
>> 'hv_evmcs_vmptr' under 'ifdef CONFIG_KVM_HYPERV' would take a lot of
>> ifdefs. Introduce 'nested_vmx_evmptr()' accessor instead.
>
>
> It might also make sense to have 'nested_evmptr_valid(vmx)'
> so that we could use it instead of 'evmptr_is_valid(nested_vmx_evmptr(vmx))'?
>
Makes sense, thanks!
>
>>
>> No functional change intended.
>>
>> Signed-off-by: Vitaly Kuznetsov <[email protected]>
>> ---
>> arch/x86/kvm/vmx/hyperv.h | 5 +++++
>> arch/x86/kvm/vmx/nested.c | 44 +++++++++++++++++++--------------------
>> arch/x86/kvm/vmx/nested.h | 3 ++-
>> 3 files changed, 29 insertions(+), 23 deletions(-)
>>
>> diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
>> index 933ef6cad5e6..6ca5c8c5be9c 100644
>> --- a/arch/x86/kvm/vmx/hyperv.h
>> +++ b/arch/x86/kvm/vmx/hyperv.h
>> @@ -4,6 +4,7 @@
>>
>> #include <linux/kvm_host.h>
>> #include "vmcs12.h"
>> +#include "vmx.h"
>>
>> #define EVMPTR_INVALID (-1ULL)
>> #define EVMPTR_MAP_PENDING (-2ULL)
>> @@ -20,7 +21,10 @@ enum nested_evmptrld_status {
>> EVMPTRLD_ERROR,
>> };
>>
>> +struct vcpu_vmx;
>> +
>> #ifdef CONFIG_KVM_HYPERV
>> +static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return vmx->nested.hv_evmcs_vmptr; }
>> u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
>> uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
>> int nested_enable_evmcs(struct kvm_vcpu *vcpu,
>> @@ -30,6 +34,7 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
>> bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
>> void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
>> #else
>> +static inline gpa_t nested_vmx_evmptr(struct vcpu_vmx *vmx) { return EVMPTR_INVALID; };
>> static inline u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { return EVMPTR_INVALID; }
>> static inline void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) {}
>> static inline bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) { return false; }
>> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
>> index ca7e06759aa3..e6476f8e2ccd 100644
>> --- a/arch/x86/kvm/vmx/nested.c
>> +++ b/arch/x86/kvm/vmx/nested.c
>> @@ -179,7 +179,7 @@ static int nested_vmx_failValid(struct kvm_vcpu *vcpu,
>> * VM_INSTRUCTION_ERROR is not shadowed. Enlightened VMCS 'shadows' all
>> * fields and thus must be synced.
>> */
>> - if (to_vmx(vcpu)->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
>> + if (nested_vmx_evmptr(to_vmx(vcpu)) != EVMPTR_INVALID)
>> to_vmx(vcpu)->nested.need_vmcs12_to_shadow_sync = true;
>>
>> return kvm_skip_emulated_instruction(vcpu);
>> @@ -194,7 +194,7 @@ static int nested_vmx_fail(struct kvm_vcpu *vcpu, u32 vm_instruction_error)
>> * can't be done if there isn't a current VMCS.
>> */
>> if (vmx->nested.current_vmptr == INVALID_GPA &&
>> - !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
>> + !evmptr_is_valid(nested_vmx_evmptr(vmx)))
>> return nested_vmx_failInvalid(vcpu);
>>
>> return nested_vmx_failValid(vcpu, vm_instruction_error);
>> @@ -230,7 +230,7 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
>> struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
>> struct vcpu_vmx *vmx = to_vmx(vcpu);
>>
>> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
>> + if (evmptr_is_valid(nested_vmx_evmptr(vmx))) {
>> kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
>> vmx->nested.hv_evmcs = NULL;
>> }
>> @@ -2019,7 +2019,7 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
>> return EVMPTRLD_DISABLED;
>> }
>>
>> - if (unlikely(evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
>> + if (unlikely(evmcs_gpa != nested_vmx_evmptr(vmx))) {
>> vmx->nested.current_vmptr = INVALID_GPA;
>>
>> nested_release_evmcs(vcpu);
>> @@ -2097,7 +2097,7 @@ void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
>> {
>> struct vcpu_vmx *vmx = to_vmx(vcpu);
>>
>> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
>> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
>> copy_vmcs12_to_enlightened(vmx);
>> else
>> copy_vmcs12_to_shadow(vmx);
>> @@ -2251,7 +2251,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
>> u32 exec_control;
>> u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12);
>>
>> - if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
>> + if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(nested_vmx_evmptr(vmx)))
>> prepare_vmcs02_early_rare(vmx, vmcs12);
>
> There are some similarities between evmcs and shadow vmcs. I used to know this, but it will probably
> take me time to recall all of the gory details.
>
> It might make sense to unify some of the logic, which can make it easier to #ifdef the hyperv support
> in less places.
>
>
>>
>> /*
>> @@ -2546,11 +2546,11 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
>> struct vcpu_vmx *vmx = to_vmx(vcpu);
>> bool load_guest_pdptrs_vmcs12 = false;
>>
>> - if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
>> + if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(nested_vmx_evmptr(vmx))) {
>> prepare_vmcs02_rare(vmx, vmcs12);
>> vmx->nested.dirty_vmcs12 = false;
>>
>> - load_guest_pdptrs_vmcs12 = !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) ||
>> + load_guest_pdptrs_vmcs12 = !evmptr_is_valid(nested_vmx_evmptr(vmx)) ||
>> !(vmx->nested.hv_evmcs->hv_clean_fields &
>> HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
>> }
>> @@ -2673,7 +2673,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
>> * bits when it changes a field in eVMCS. Mark all fields as clean
>> * here.
>> */
>> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
>> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
>> vmx->nested.hv_evmcs->hv_clean_fields |=
>> HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
>>
>> @@ -3181,7 +3181,7 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
>> * properly reflected.
>> */
>> if (guest_cpuid_has_evmcs(vcpu) &&
>> - vmx->nested.hv_evmcs_vmptr == EVMPTR_MAP_PENDING) {
>> + nested_vmx_evmptr(vmx) == EVMPTR_MAP_PENDING) {
>> enum nested_evmptrld_status evmptrld_status =
>> nested_vmx_handle_enlightened_vmptrld(vcpu, false);
>>
>> @@ -3551,7 +3551,7 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
>>
>> load_vmcs12_host_state(vcpu, vmcs12);
>> vmcs12->vm_exit_reason = exit_reason.full;
>> - if (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
>> + if (enable_shadow_vmcs || evmptr_is_valid(nested_vmx_evmptr(vmx)))
>> vmx->nested.need_vmcs12_to_shadow_sync = true;
>> return NVMX_VMENTRY_VMEXIT;
>> }
>> @@ -3584,7 +3584,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
>> if (CC(evmptrld_status == EVMPTRLD_VMFAIL))
>> return nested_vmx_failInvalid(vcpu);
>>
>> - if (CC(!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) &&
>> + if (CC(!evmptr_is_valid(nested_vmx_evmptr(vmx)) &&
>> vmx->nested.current_vmptr == INVALID_GPA))
>> return nested_vmx_failInvalid(vcpu);
>>
>> @@ -3599,7 +3599,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
>> if (CC(vmcs12->hdr.shadow_vmcs))
>> return nested_vmx_failInvalid(vcpu);
>>
>> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
>> + if (evmptr_is_valid(nested_vmx_evmptr(vmx))) {
>> copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields);
>> /* Enlightened VMCS doesn't have launch state */
>> vmcs12->launch_state = !launch;
>> @@ -4344,11 +4344,11 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
>> {
>> struct vcpu_vmx *vmx = to_vmx(vcpu);
>>
>> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
>> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
>> sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
>>
>> vmx->nested.need_sync_vmcs02_to_vmcs12_rare =
>> - !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
>> + !evmptr_is_valid(nested_vmx_evmptr(vmx));
>>
>> vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
>> vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
>> @@ -4869,7 +4869,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
>> }
>>
>> if ((vm_exit_reason != -1) &&
>> - (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)))
>> + (enable_shadow_vmcs || evmptr_is_valid(nested_vmx_evmptr(vmx))))
>> vmx->nested.need_vmcs12_to_shadow_sync = true;
>>
>> /* in case we halted in L2 */
>> @@ -5335,7 +5335,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
>> vmptr + offsetof(struct vmcs12,
>> launch_state),
>> &zero, sizeof(zero));
>> - } else if (vmx->nested.hv_evmcs && vmptr == vmx->nested.hv_evmcs_vmptr) {
>> + } else if (vmx->nested.hv_evmcs && vmptr == nested_vmx_evmptr(vmx)) {
>> nested_release_evmcs(vcpu);
>> }
>>
>> @@ -5375,7 +5375,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
>> /* Decode instruction info and find the field to read */
>> field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
>>
>> - if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
>> + if (!evmptr_is_valid(nested_vmx_evmptr(vmx))) {
>> /*
>> * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
>> * any VMREAD sets the ALU flags for VMfailInvalid.
>> @@ -5601,7 +5601,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
>> return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER);
>>
>> /* Forbid normal VMPTRLD if Enlightened version was used */
>> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
>> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
>> return 1;
>>
>> if (vmx->nested.current_vmptr != vmptr) {
>> @@ -5664,7 +5664,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
>> if (!nested_vmx_check_permission(vcpu))
>> return 1;
>>
>> - if (unlikely(evmptr_is_valid(to_vmx(vcpu)->nested.hv_evmcs_vmptr)))
>> + if (unlikely(evmptr_is_valid(nested_vmx_evmptr(to_vmx(vcpu)))))
>> return 1;
>>
>> if (get_vmx_mem_address(vcpu, exit_qual, instr_info,
>> @@ -6450,7 +6450,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
>> kvm_state.size += sizeof(user_vmx_nested_state->vmcs12);
>>
>> /* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
>> - if (vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
>> + if (nested_vmx_evmptr(vmx) != EVMPTR_INVALID)
>> kvm_state.flags |= KVM_STATE_NESTED_EVMCS;
>>
>> if (is_guest_mode(vcpu) &&
>> @@ -6506,7 +6506,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
>> } else {
>> copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu));
>> if (!vmx->nested.need_vmcs12_to_shadow_sync) {
>> - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
>> + if (evmptr_is_valid(nested_vmx_evmptr(vmx)))
>> /*
>> * L1 hypervisor is not obliged to keep eVMCS
>> * clean fields data always up-to-date while
>> diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h
>> index b4b9d51438c6..b389312636e2 100644
>> --- a/arch/x86/kvm/vmx/nested.h
>> +++ b/arch/x86/kvm/vmx/nested.h
>> @@ -3,6 +3,7 @@
>> #define __KVM_X86_VMX_NESTED_H
>>
>> #include "kvm_cache_regs.h"
>> +#include "hyperv.h"
>
> ^ This fixes the build error introduced by patch 6.
>
>> #include "vmcs12.h"
>> #include "vmx.h"
>>
>> @@ -57,7 +58,7 @@ static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu)
>>
>> /* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
>> return vmx->nested.current_vmptr != -1ull ||
>> - vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID;
>> + nested_vmx_evmptr(vmx) != EVMPTR_INVALID;
>
> However with my suggestion of nested_evmptr_valid(vmx) we
> can hide that check and avoid the include as well.
>
>> }
>>
>> static inline u16 nested_get_vpid02(struct kvm_vcpu *vcpu)
>
>
> Best regards,
> Maxim Levitsky
>
>
>
>
>
--
Vitaly
On Mon, Oct 16, 2023, Vitaly Kuznetsov wrote:
> Maxim Levitsky <[email protected]> writes:
>
> > У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> >> Hyper-V emulation in KVM is a fairly big chunk and in some cases it may be
> >> desirable to not compile it in to reduce module sizes as well as attack
> >> surface. Introduce CONFIG_KVM_HYPERV option to make it possible.
> >>
> >> Note, there's room for further nVMX/nSVM code optimizations when
> >> !CONFIG_KVM_HYPERV, this will be done in follow-up patches.
> >
> > Maybe CONFIG_KVM_HYPERV_GUEST_SUPPORT or CONFIG_HYPERV_ON_KVM instead?
> >
> > IMHO CONFIG_KVM_HYPERV_GUEST_SUPPORT sounds good.
Adding GUEST_SUPPORT doesn't disambiguate anything though, as there's no clear
indication of whether KVM or Hyper-V is the guest. E.g. the umbrella kconfig for
Linux-as-a-guest is CONFIG_HYPERVISOR_GUEST.
> We already have CONFIG_KVM_XEN so I decided to stay concise. I do
> understand that 'KVM-on-Hyper-V' and 'Hyper-V-on-KVM' mess which creates
> the confusion though.
Yeah, matching Xen is probably the best way to minimize confusion, e.g. the kernel
has CONFIG_HYPERV and CONFIG_XEN to go with KVM's, CONFIG_KVM_HYPERV and CONFIG_KVM_XEN.
> >> diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
> >> index ed90f148140d..a06e19a8a8f6 100644
> >> --- a/arch/x86/kvm/Kconfig
> >> +++ b/arch/x86/kvm/Kconfig
> >> @@ -129,6 +129,15 @@ config KVM_SMM
> >>
> >> If unsure, say Y.
> >>
> >> +config KVM_HYPERV
> >> + bool "Support for Microsoft Hyper-V emulation"
> >> + depends on KVM
> >> + default y
> >> + help
> >> + Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
> >
> >
> > It feels to me that the KConfig option can have a longer description.
> >
> > What do you think about something like that:
> >
> > "Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
I don't think we should put Hyper-V in parentheses, I haven't seen any documentation
that calls it "Microsoft Hypervisor", i.e. Hyper-V is the full and proper name.
> > This makes KVM expose a set of paravirtualized interfaces,
s/makes/allows, since KVM still requires userspace to opt-in to exposing Hyper-V.
> > documented in the HyperV TLFS,
s/TLFS/spec? Readers that aren't already familiar with Hyper-V will have no idea
what TLFS is until they click the link.
> > https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs,
> > which consists of a subset of paravirtualized interfaces that HyperV exposes
We can trim this paragraph by stating that KVM only supports a subset of the
PV interfaces straightaway.
> > to its guests.
E.g.
Provides KVM support for for emulating Microsoft Hyper-V. This allows KVM to
expose a subset of the paravirtualized interfaces defined in Hyper-V's spec:
https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs.
> >
> > This improves performance of modern Windows guests.
Isn't Hyper-V emulation effectively mandatory these days? IIRC, modern versions
of Windows will fail to boot if they detect a hypervisor but the core Hyper-V
interfaces aren't supported.
Sean Christopherson <[email protected]> writes:
> On Mon, Oct 16, 2023, Vitaly Kuznetsov wrote:
>> Maxim Levitsky <[email protected]> writes:
>>
...
>> >
>> > "Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
>
> I don't think we should put Hyper-V in parentheses, I haven't seen any documentation
> that calls it "Microsoft Hypervisor", i.e. Hyper-V is the full and
> proper name.
Ha :-) From
https://lore.kernel.org/linux-hyperv/1696010501-24584-1-git-send-email-nunodasneves@linux.microsoft.com/
"""
This series introduces support for creating and running guest machines
while running on the Microsoft Hypervisor. [0]
...
[0] "Hyper-V" is more well-known, but it really refers to the whole stack
including the hypervisor and other components that run in Windows
kernel and userspace.
"""
I'm fine with keeping the staus quo though :-)
>
>> > This makes KVM expose a set of paravirtualized interfaces,
>
> s/makes/allows, since KVM still requires userspace to opt-in to exposing Hyper-V.
>
>> > documented in the HyperV TLFS,
>
> s/TLFS/spec? Readers that aren't already familiar with Hyper-V will have no idea
> what TLFS is until they click the link.
>
>> > https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs,
>> > which consists of a subset of paravirtualized interfaces that HyperV exposes
>
> We can trim this paragraph by stating that KVM only supports a subset of the
> PV interfaces straightaway.
>
>> > to its guests.
>
> E.g.
>
> Provides KVM support for for emulating Microsoft Hyper-V. This allows KVM to
> expose a subset of the paravirtualized interfaces defined in Hyper-V's spec:
> https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs.
LGTM, thanks!
>
>> >
>> > This improves performance of modern Windows guests.
>
> Isn't Hyper-V emulation effectively mandatory these days? IIRC, modern versions
> of Windows will fail to boot if they detect a hypervisor but the core Hyper-V
> interfaces aren't supported.
>
It's rather a rule of thumb: normally, modern Windows and Hyper-V
versions (Win10/11, WS2019/22) boot and pretend to work but without
Hyper-V enlightenment it's not uncommon to see a blue screen of death
because of a watchdog firing. It's hard to say for sure as things keep
changing under the hood so even different builds can behave differently;
pretending we're a genuine Hyper-V was proven to be the most robust
approach.
--
Vitaly
On Mon, Oct 16, 2023, Vitaly Kuznetsov wrote:
> Maxim Levitsky <[email protected]> writes:
>
> > У вт, 2023-10-10 у 18:02 +0200, Vitaly Kuznetsov пише:
> >> 'vmx->nested.hv_evmcs_vmptr' accesses are all over the place so hiding
> >> 'hv_evmcs_vmptr' under 'ifdef CONFIG_KVM_HYPERV' would take a lot of
> >> ifdefs. Introduce 'nested_vmx_evmptr()' accessor instead.
> >
> >
> > It might also make sense to have 'nested_evmptr_valid(vmx)'
"is_valid" please so that it's clear the helper is a check, not a declaration.
> > so that we could use it instead of 'evmptr_is_valid(nested_vmx_evmptr(vmx))'?
> >
>
> Makes sense, thanks!
Would it be accurate to call it nested_vmx_is_evmptr12_valid()? If so, that has
my vote. It's a bit verbose, but it should be fully self-explanatory for anyone
that's familiar with KVM's vmcs12 and vmcb12 terminology.
On Mon, Oct 16, 2023, Vitaly Kuznetsov wrote:
> Sean Christopherson <[email protected]> writes:
>
> > On Mon, Oct 16, 2023, Vitaly Kuznetsov wrote:
> >> Maxim Levitsky <[email protected]> writes:
> >>
>
> ...
>
> >> >
> >> > "Provides KVM support for emulating Microsoft Hypervisor (Hyper-V).
> >
> > I don't think we should put Hyper-V in parentheses, I haven't seen any documentation
> > that calls it "Microsoft Hypervisor", i.e. Hyper-V is the full and
> > proper name.
>
> Ha :-) From
> https://lore.kernel.org/linux-hyperv/1696010501-24584-1-git-send-email-nunodasneves@linux.microsoft.com/
>
> """
> This series introduces support for creating and running guest machines
> while running on the Microsoft Hypervisor. [0]
> ...
> [0] "Hyper-V" is more well-known, but it really refers to the whole stack
> including the hypervisor and other components that run in Windows
> kernel and userspace.
> """
LOL indeed. :-)
> I'm fine with keeping the staus quo though :-)
>
> >
> >> > This makes KVM expose a set of paravirtualized interfaces,
> >
> > s/makes/allows, since KVM still requires userspace to opt-in to exposing Hyper-V.
> >
> >> > documented in the HyperV TLFS,
> >
> > s/TLFS/spec? Readers that aren't already familiar with Hyper-V will have no idea
> > what TLFS is until they click the link.
> >
> >> > https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs,
> >> > which consists of a subset of paravirtualized interfaces that HyperV exposes
> >
> > We can trim this paragraph by stating that KVM only supports a subset of the
> > PV interfaces straightaway.
> >
> >> > to its guests.
> >
> > E.g.
> >
> > Provides KVM support for for emulating Microsoft Hyper-V. This allows KVM to
> > expose a subset of the paravirtualized interfaces defined in Hyper-V's spec:
> > https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs.
To fold in the whole "Microsoft Hypervisor" thing, what if we take the verbiage
verbatim from the TLFS intro?
Provides KVM support for emulating Microsoft Hyper-V. This allows KVM to
expose a subset of the paravirtualized interfaces defined in the Hyper-V
Hypervisor Top-Level Functional Specification (TLFS):
https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs
> LGTM, thanks!
>
> >
> >> >
> >> > This improves performance of modern Windows guests.
> >
> > Isn't Hyper-V emulation effectively mandatory these days? IIRC, modern versions
> > of Windows will fail to boot if they detect a hypervisor but the core Hyper-V
> > interfaces aren't supported.
> >
>
> It's rather a rule of thumb: normally, modern Windows and Hyper-V
> versions (Win10/11, WS2019/22) boot and pretend to work but without
> Hyper-V enlightenment it's not uncommon to see a blue screen of death
> because of a watchdog firing. It's hard to say for sure as things keep
> changing under the hood so even different builds can behave differently;
> pretending we're a genuine Hyper-V was proven to be the most robust
> approach.
We should capture something to that effect in the help. I want to avoid bug
reports of Windows not working on KVM because someone turned off CONFIG_KVM_HYPERV
because the help implies that it _only_ improves performance.