mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
KVM x86 Hyper-V changes for 6.8:
- Guard KVM-on-HyperV's range-based TLB flush hooks with an #ifdef on CONFIG_HYPERV as a minor optimization, and to self-document the code. - Add CONFIG_KVM_HYPERV to allow disabling KVM support for HyperV "emulation" at build time. -----BEGIN PGP SIGNATURE----- iQJGBAABCgAwFiEEMHr+pfEFOIzK+KY1YJEiAU0MEvkFAmWW8gYSHHNlYW5qY0Bn b29nbGUuY29tAAoJEGCRIgFNDBL5sGUP/iadHMz7Up1X29IDGtq58LRORNVXp2Ln 2dqoj8IKZeSr+mPMw2GvZyuiLqVPMs4Et21WJfCO7HgKd/NPMDORwRndhJYweFRY yk+5NJLvXYuo8UR3b2QYy8XUghEqP+j5eYyon6UdCiPACcBGTpgoj4pU7SLM7l4T EOge42ya5YxD/1oWr5vyifNrOJCPNTBYcC0as5//+RdnmQYqYZ26Z73b0B8Pdct4 XMWwgoKlmLTmei0YntXtGaDGimCvTYP8EPM4tOWgiBSWMhQXWbAh/0biDfd3eZVO Hoe4HvstdjUNbpO3h3Zo78Ob7ehk4kx/6r0nlQnz5JxzGnuDjYCDIVUlYn0mw5Yi nu4ztr8M3VRksDbpmAjSO9XFEKIYxlYQfzZ1UuTy8ehdBYTDl/3lPAbh2ApUYE72 Tt2PXmFGz2j1sjG38Gh94s48Za5OxHoVlfq8iGhU4v7UjuxnMNHfExOWd66SwZgx 5tZkr4rj/pWt21wr7jaVqFGzuftIC5G4ZEBhh7JcW89oamFrykgQUu5z4dhBMO75 G7DAVh9eSH2SKkmJH1ClXriveazTK7fqMx8sZzzRnusMz09qH7SIdjSzmp7H5utw pWBfatft0n0FTI1r+hxGueiJt7dFlrIz0Q4hHyBN4saoVH121bZioc0pq1ob6MIk Y2Ou4xJBt14F =bjfs -----END PGP SIGNATURE----- Merge tag 'kvm-x86-hyperv-6.8' of https://github.com/kvm-x86/linux into HEAD KVM x86 Hyper-V changes for 6.8: - Guard KVM-on-HyperV's range-based TLB flush hooks with an #ifdef on CONFIG_HYPERV as a minor optimization, and to self-document the code. - Add CONFIG_KVM_HYPERV to allow disabling KVM support for HyperV "emulation" at build time.
This commit is contained in:
commit
0afdfd85e3
35 changed files with 1092 additions and 768 deletions
|
@ -55,8 +55,10 @@ KVM_X86_OP(set_rflags)
|
|||
KVM_X86_OP(get_if_flag)
|
||||
KVM_X86_OP(flush_tlb_all)
|
||||
KVM_X86_OP(flush_tlb_current)
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
KVM_X86_OP_OPTIONAL(flush_remote_tlbs)
|
||||
KVM_X86_OP_OPTIONAL(flush_remote_tlbs_range)
|
||||
#endif
|
||||
KVM_X86_OP(flush_tlb_gva)
|
||||
KVM_X86_OP(flush_tlb_guest)
|
||||
KVM_X86_OP(vcpu_pre_run)
|
||||
|
|
|
@ -937,8 +937,10 @@ struct kvm_vcpu_arch {
|
|||
/* used for guest single stepping over the given code position */
|
||||
unsigned long singlestep_rip;
|
||||
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
bool hyperv_enabled;
|
||||
struct kvm_vcpu_hv *hyperv;
|
||||
#endif
|
||||
#ifdef CONFIG_KVM_XEN
|
||||
struct kvm_vcpu_xen xen;
|
||||
#endif
|
||||
|
@ -1095,6 +1097,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;
|
||||
|
@ -1125,9 +1128,9 @@ struct kvm_hv {
|
|||
*/
|
||||
unsigned int synic_auto_eoi_used;
|
||||
|
||||
struct hv_partition_assist_pg *hv_pa_pg;
|
||||
struct kvm_hv_syndbg hv_syndbg;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct msr_bitmap_range {
|
||||
u32 flags;
|
||||
|
@ -1136,6 +1139,7 @@ struct msr_bitmap_range {
|
|||
unsigned long *bitmap;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KVM_XEN
|
||||
/* Xen emulation context */
|
||||
struct kvm_xen {
|
||||
struct mutex xen_lock;
|
||||
|
@ -1147,6 +1151,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,
|
||||
|
@ -1348,8 +1353,13 @@ 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;
|
||||
#endif
|
||||
|
||||
bool backwards_tsc_observed;
|
||||
bool boot_vcpu_runs_old_kvmclock;
|
||||
|
@ -1442,6 +1452,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
|
||||
|
@ -1614,9 +1625,11 @@ struct kvm_x86_ops {
|
|||
|
||||
void (*flush_tlb_all)(struct kvm_vcpu *vcpu);
|
||||
void (*flush_tlb_current)(struct kvm_vcpu *vcpu);
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
int (*flush_remote_tlbs)(struct kvm *kvm);
|
||||
int (*flush_remote_tlbs_range)(struct kvm *kvm, gfn_t gfn,
|
||||
gfn_t nr_pages);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Flush any TLB entries associated with the given GVA.
|
||||
|
@ -1825,6 +1838,7 @@ static inline struct kvm *kvm_arch_alloc_vm(void)
|
|||
#define __KVM_HAVE_ARCH_VM_FREE
|
||||
void kvm_arch_free_vm(struct kvm *kvm);
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
#define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLBS
|
||||
static inline int kvm_arch_flush_remote_tlbs(struct kvm *kvm)
|
||||
{
|
||||
|
@ -1836,6 +1850,15 @@ static inline int kvm_arch_flush_remote_tlbs(struct kvm *kvm)
|
|||
}
|
||||
|
||||
#define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLBS_RANGE
|
||||
static inline int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn,
|
||||
u64 nr_pages)
|
||||
{
|
||||
if (!kvm_x86_ops.flush_remote_tlbs_range)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return static_call(kvm_x86_flush_remote_tlbs_range)(kvm, gfn, nr_pages);
|
||||
}
|
||||
#endif /* CONFIG_HYPERV */
|
||||
|
||||
#define kvm_arch_pmi_in_guest(vcpu) \
|
||||
((vcpu) && (vcpu)->arch.handling_intr_from_guest)
|
||||
|
|
|
@ -138,6 +138,20 @@ 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 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
|
||||
These interfaces are required for the correct and performant functioning
|
||||
of Windows and Hyper-V guests on KVM.
|
||||
|
||||
If unsure, say "Y".
|
||||
|
||||
config KVM_XEN
|
||||
bool "Support for Xen hypercall interface"
|
||||
depends on KVM
|
||||
|
|
|
@ -11,25 +11,27 @@ 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
|
||||
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/nested.o vmx/posted_intr.o
|
||||
vmx/nested.o vmx/posted_intr.o
|
||||
|
||||
kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
|
||||
kvm-intel-$(CONFIG_KVM_HYPERV) += vmx/hyperv.o vmx/hyperv_evmcs.o
|
||||
|
||||
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
|
||||
kvm-amd-$(CONFIG_KVM_HYPERV) += svm/hyperv.o
|
||||
|
||||
ifdef CONFIG_HYPERV
|
||||
kvm-y += kvm_onhyperv.o
|
||||
kvm-intel-y += vmx/vmx_onhyperv.o vmx/hyperv_evmcs.o
|
||||
kvm-amd-y += svm/svm_onhyperv.o
|
||||
endif
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
@ -433,11 +437,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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -105,6 +107,17 @@ 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);
|
||||
}
|
||||
|
||||
void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
|
||||
|
||||
bool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu);
|
||||
|
@ -236,6 +249,76 @@ static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu)
|
|||
return kvm_hv_get_assist_page(vcpu);
|
||||
}
|
||||
|
||||
int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu);
|
||||
static inline void kvm_hv_nested_transtion_tlb_flush(struct kvm_vcpu *vcpu,
|
||||
bool tdp_enabled)
|
||||
{
|
||||
/*
|
||||
* 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
|
||||
* pending entries in the right FIFO upon L1/L2 transition as these
|
||||
* requests are put by other vCPUs asynchronously.
|
||||
*/
|
||||
if (to_hv_vcpu(vcpu) && tdp_enabled)
|
||||
kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
|
||||
}
|
||||
|
||||
#endif
|
||||
int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu);
|
||||
#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;
|
||||
}
|
||||
static inline void kvm_hv_nested_transtion_tlb_flush(struct kvm_vcpu *vcpu, bool tdp_enabled) {}
|
||||
#endif /* CONFIG_KVM_HYPERV */
|
||||
|
||||
#endif /* __ARCH_X86_KVM_HYPERV_H__ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -10,6 +10,26 @@
|
|||
int hv_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, gfn_t nr_pages);
|
||||
int hv_flush_remote_tlbs(struct kvm *kvm);
|
||||
void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp);
|
||||
static inline hpa_t hv_get_partition_assist_page(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* Partition assist page is something which Hyper-V running in L0
|
||||
* requires from KVM running in L1 before direct TLB flush for L2
|
||||
* guests can be enabled. KVM doesn't currently use the page but to
|
||||
* comply with TLFS it still needs to be allocated. For now, this
|
||||
* is a single page shared among all vCPUs.
|
||||
*/
|
||||
struct hv_partition_assist_pg **p_hv_pa_pg =
|
||||
&vcpu->kvm->arch.hv_pa_pg;
|
||||
|
||||
if (!*p_hv_pa_pg)
|
||||
*p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT);
|
||||
|
||||
if (!*p_hv_pa_pg)
|
||||
return INVALID_PAGE;
|
||||
|
||||
return __pa(*p_hv_pa_pg);
|
||||
}
|
||||
#else /* !CONFIG_HYPERV */
|
||||
static inline int hv_flush_remote_tlbs(struct kvm *kvm)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
@ -2905,7 +2904,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
|
||||
|
|
|
@ -271,15 +271,11 @@ static inline unsigned long kvm_mmu_get_guest_pgd(struct kvm_vcpu *vcpu,
|
|||
|
||||
static inline bool kvm_available_flush_remote_tlbs_range(void)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
return kvm_x86_ops.flush_remote_tlbs_range;
|
||||
}
|
||||
|
||||
int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, u64 nr_pages)
|
||||
{
|
||||
if (!kvm_x86_ops.flush_remote_tlbs_range)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return static_call(kvm_x86_flush_remote_tlbs_range)(kvm, gfn, nr_pages);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index);
|
||||
|
|
|
@ -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,13 @@ 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__ */
|
||||
|
|
|
@ -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,
|
||||
|
@ -487,14 +495,8 @@ static void nested_save_pending_event_to_vmcb12(struct vcpu_svm *svm,
|
|||
|
||||
static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* 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
|
||||
* pending entries in the right FIFO upon L1/L2 transition as these
|
||||
* requests are put by other vCPUs asynchronously.
|
||||
*/
|
||||
if (to_hv_vcpu(vcpu) && npt_enabled)
|
||||
kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
|
||||
/* Handle pending Hyper-V TLB flush requests */
|
||||
kvm_hv_nested_transtion_tlb_flush(vcpu, npt_enabled);
|
||||
|
||||
/*
|
||||
* TODO: optimize unconditional TLB flush/MMU sync. A partial list of
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -18,18 +18,14 @@
|
|||
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;
|
||||
hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu);
|
||||
|
||||
if (!*p_hv_pa_pg)
|
||||
*p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
|
||||
if (!*p_hv_pa_pg)
|
||||
if (partition_assist_page == INVALID_PAGE)
|
||||
return -ENOMEM;
|
||||
|
||||
hve = &to_svm(vcpu)->vmcb->control.hv_enlightenments;
|
||||
|
||||
hve->partition_assist_page = __pa(*p_hv_pa_pg);
|
||||
hve->partition_assist_page = partition_assist_page;
|
||||
hve->hv_vm_id = (unsigned long)vcpu->kvm;
|
||||
if (!hve->hv_enlightenments_control.nested_flush_hypercall) {
|
||||
hve->hv_enlightenments_control.nested_flush_hypercall = 1;
|
||||
|
|
|
@ -13,419 +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}
|
||||
|
||||
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);
|
||||
|
@ -608,40 +195,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)
|
||||
{
|
||||
|
|
|
@ -2,185 +2,13 @@
|
|||
#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"
|
||||
|
||||
struct vmcs_config;
|
||||
|
||||
#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
|
||||
|
||||
#define KVM_EVMCS_VERSION 1
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#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) */
|
||||
#include "vmx.h"
|
||||
|
||||
#define EVMPTR_INVALID (-1ULL)
|
||||
#define EVMPTR_MAP_PENDING (-2ULL)
|
||||
|
||||
static inline bool evmptr_is_valid(u64 evmptr)
|
||||
{
|
||||
return evmptr != EVMPTR_INVALID && evmptr != EVMPTR_MAP_PENDING;
|
||||
}
|
||||
|
||||
enum nested_evmptrld_status {
|
||||
EVMPTRLD_DISABLED,
|
||||
EVMPTRLD_SUCCEEDED,
|
||||
|
@ -188,6 +16,42 @@ enum nested_evmptrld_status {
|
|||
EVMPTRLD_ERROR,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
static inline bool evmptr_is_valid(u64 evmptr)
|
||||
{
|
||||
return evmptr != EVMPTR_INVALID && evmptr != EVMPTR_MAP_PENDING;
|
||||
}
|
||||
|
||||
static inline bool nested_vmx_is_evmptr12_valid(struct vcpu_vmx *vmx)
|
||||
{
|
||||
return evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
|
||||
}
|
||||
|
||||
static inline bool evmptr_is_set(u64 evmptr)
|
||||
{
|
||||
return evmptr != EVMPTR_INVALID;
|
||||
}
|
||||
|
||||
static inline bool nested_vmx_is_evmptr12_set(struct vcpu_vmx *vmx)
|
||||
{
|
||||
return evmptr_is_set(vmx->nested.hv_evmcs_vmptr);
|
||||
}
|
||||
|
||||
static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
|
||||
{
|
||||
return vmx->nested.hv_evmcs;
|
||||
}
|
||||
|
||||
static inline bool guest_cpuid_has_evmcs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* eVMCS is exposed to the guest if Hyper-V is enabled in CPUID and
|
||||
* eVMCS has been explicitly enabled by userspace.
|
||||
*/
|
||||
return vcpu->arch.hyperv_enabled &&
|
||||
to_vmx(vcpu)->nested.enlightened_vmcs_enabled;
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -196,5 +60,31 @@ 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 bool evmptr_is_valid(u64 evmptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool nested_vmx_is_evmptr12_valid(struct vcpu_vmx *vmx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool evmptr_is_set(u64 evmptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool nested_vmx_is_evmptr12_set(struct vcpu_vmx *vmx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __KVM_X86_VMX_HYPERV_H */
|
||||
|
|
315
arch/x86/kvm/vmx/hyperv_evmcs.c
Normal file
315
arch/x86/kvm/vmx/hyperv_evmcs.c
Normal file
|
@ -0,0 +1,315 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* This file contains common code for working with Enlightened VMCS which is
|
||||
* used both by Hyper-V on KVM and KVM on Hyper-V.
|
||||
*/
|
||||
|
||||
#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);
|
166
arch/x86/kvm/vmx/hyperv_evmcs.h
Normal file
166
arch/x86/kvm/vmx/hyperv_evmcs.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* This file contains common definitions for working with Enlightened VMCS which
|
||||
* are used both by Hyper-V on KVM and KVM on Hyper-V.
|
||||
*/
|
||||
#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)
|
||||
{
|
||||
const struct evmcs_field *evmcs_field;
|
||||
unsigned int index = ROL16(field, 6);
|
||||
|
||||
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 */
|
|
@ -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_is_evmptr12_set(to_vmx(vcpu)))
|
||||
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))
|
||||
!nested_vmx_is_evmptr12_valid(vmx))
|
||||
return nested_vmx_failInvalid(vcpu);
|
||||
|
||||
return nested_vmx_failValid(vcpu, vm_instruction_error);
|
||||
|
@ -226,10 +226,11 @@ 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);
|
||||
|
||||
if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
|
||||
if (nested_vmx_is_evmptr12_valid(vmx)) {
|
||||
kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
|
||||
vmx->nested.hv_evmcs = NULL;
|
||||
}
|
||||
|
@ -241,6 +242,34 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
|
|||
hv_vcpu->nested.vm_id = 0;
|
||||
hv_vcpu->nested.vp_id = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool nested_evmcs_handle_vmclear(struct kvm_vcpu *vcpu, gpa_t vmptr)
|
||||
{
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
/*
|
||||
* When Enlightened VMEntry is enabled on the calling CPU we treat
|
||||
* memory area pointer by vmptr as Enlightened VMCS (as there's no good
|
||||
* way to distinguish it from VMCS12) and we must not corrupt it by
|
||||
* writing to the non-existent 'launch_state' field. The area doesn't
|
||||
* have to be the currently active EVMCS on the calling CPU and there's
|
||||
* nothing KVM has to do to transition it from 'active' to 'non-active'
|
||||
* state. It is possible that the area will stay mapped as
|
||||
* vmx->nested.hv_evmcs but this shouldn't be a problem.
|
||||
*/
|
||||
if (!guest_cpuid_has_evmcs(vcpu) ||
|
||||
!evmptr_is_valid(nested_get_evmptr(vcpu)))
|
||||
return false;
|
||||
|
||||
if (nested_vmx_evmcs(vmx) && vmptr == vmx->nested.hv_evmcs_vmptr)
|
||||
nested_release_evmcs(vcpu);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx,
|
||||
|
@ -572,7 +601,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. */
|
||||
|
@ -588,10 +616,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;
|
||||
|
@ -1139,14 +1170,8 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* pending entries in the right FIFO upon L1/L2 transition as these
|
||||
* requests are put by other vCPUs asynchronously.
|
||||
*/
|
||||
if (to_hv_vcpu(vcpu) && enable_ept)
|
||||
kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
|
||||
/* Handle pending Hyper-V TLB flush requests */
|
||||
kvm_hv_nested_transtion_tlb_flush(vcpu, enable_ept);
|
||||
|
||||
/*
|
||||
* If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
|
||||
|
@ -1578,8 +1603,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
|
|||
|
||||
static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
|
||||
{
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
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 */
|
||||
|
@ -1818,12 +1844,16 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields
|
|||
*/
|
||||
|
||||
return;
|
||||
#else /* CONFIG_KVM_HYPERV */
|
||||
KVM_BUG_ON(1, vmx->vcpu.kvm);
|
||||
#endif /* CONFIG_KVM_HYPERV */
|
||||
}
|
||||
|
||||
static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
|
||||
{
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
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:
|
||||
|
@ -1992,6 +2022,9 @@ static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
|
|||
evmcs->guest_bndcfgs = vmcs12->guest_bndcfgs;
|
||||
|
||||
return;
|
||||
#else /* CONFIG_KVM_HYPERV */
|
||||
KVM_BUG_ON(1, vmx->vcpu.kvm);
|
||||
#endif /* CONFIG_KVM_HYPERV */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2001,6 +2034,7 @@ static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
|
|||
static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
|
||||
struct kvm_vcpu *vcpu, bool from_launch)
|
||||
{
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
bool evmcs_gpa_changed = false;
|
||||
u64 evmcs_gpa;
|
||||
|
@ -2082,13 +2116,16 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
|
|||
}
|
||||
|
||||
return EVMPTRLD_SUCCEEDED;
|
||||
#else
|
||||
return EVMPTRLD_DISABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
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 (nested_vmx_is_evmptr12_valid(vmx))
|
||||
copy_vmcs12_to_enlightened(vmx);
|
||||
else
|
||||
copy_vmcs12_to_shadow(vmx);
|
||||
|
@ -2242,7 +2279,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 || nested_vmx_is_evmptr12_valid(vmx))
|
||||
prepare_vmcs02_early_rare(vmx, vmcs12);
|
||||
|
||||
/*
|
||||
|
@ -2403,7 +2440,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)) {
|
||||
|
@ -2535,15 +2572,15 @@ 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(vmx->nested.hv_evmcs_vmptr)) {
|
||||
if (vmx->nested.dirty_vmcs12 || nested_vmx_is_evmptr12_valid(vmx)) {
|
||||
prepare_vmcs02_rare(vmx, vmcs12);
|
||||
vmx->nested.dirty_vmcs12 = false;
|
||||
|
||||
load_guest_pdptrs_vmcs12 = !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) ||
|
||||
!(vmx->nested.hv_evmcs->hv_clean_fields &
|
||||
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
|
||||
load_guest_pdptrs_vmcs12 = !nested_vmx_is_evmptr12_valid(vmx) ||
|
||||
!(evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
|
||||
}
|
||||
|
||||
if (vmx->nested.nested_run_pending &&
|
||||
|
@ -2664,9 +2701,8 @@ 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))
|
||||
vmx->nested.hv_evmcs->hv_clean_fields |=
|
||||
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
|
||||
if (nested_vmx_is_evmptr12_valid(vmx))
|
||||
evmcs->hv_clean_fields |= HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2888,8 +2924,10 @@ static int nested_vmx_check_controls(struct kvm_vcpu *vcpu,
|
|||
nested_check_vm_entry_controls(vcpu, vmcs12))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
if (guest_cpuid_has_evmcs(vcpu))
|
||||
return nested_evmcs_check_controls(vmcs12);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3161,6 +3199,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 +3227,7 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
|
@ -3279,6 +3319,7 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
|
|||
|
||||
static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
/*
|
||||
* Note: nested_get_evmcs_page() also updates 'vp_assist_page' copy
|
||||
* in 'struct kvm_vcpu_hv' in case eVMCS is in use, this is mandatory
|
||||
|
@ -3295,6 +3336,7 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
|
|||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_guest_mode(vcpu) && !nested_get_vmcs12_pages(vcpu))
|
||||
return false;
|
||||
|
@ -3538,7 +3580,7 @@ vmentry_fail_vmexit:
|
|||
|
||||
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 || nested_vmx_is_evmptr12_valid(vmx))
|
||||
vmx->nested.need_vmcs12_to_shadow_sync = true;
|
||||
return NVMX_VMENTRY_VMEXIT;
|
||||
}
|
||||
|
@ -3569,7 +3611,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(!nested_vmx_is_evmptr12_valid(vmx) &&
|
||||
vmx->nested.current_vmptr == INVALID_GPA))
|
||||
return nested_vmx_failInvalid(vcpu);
|
||||
|
||||
|
@ -3584,8 +3626,10 @@ 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)) {
|
||||
copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields);
|
||||
if (nested_vmx_is_evmptr12_valid(vmx)) {
|
||||
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) {
|
||||
|
@ -4329,11 +4373,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 (nested_vmx_is_evmptr12_valid(vmx))
|
||||
sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
|
||||
|
||||
vmx->nested.need_sync_vmcs02_to_vmcs12_rare =
|
||||
!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
|
||||
!nested_vmx_is_evmptr12_valid(vmx);
|
||||
|
||||
vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
|
||||
vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
|
||||
|
@ -4732,6 +4776,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
|
|||
/* trying to cancel vmlaunch/vmresume is a bug */
|
||||
WARN_ON_ONCE(vmx->nested.nested_run_pending);
|
||||
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
|
||||
/*
|
||||
* KVM_REQ_GET_NESTED_STATE_PAGES is also used to map
|
||||
|
@ -4741,6 +4786,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
|
|||
*/
|
||||
(void)nested_get_evmcs_page(vcpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Service pending TLB flush requests for L2 before switching to L1. */
|
||||
kvm_service_local_tlb_flush_requests(vcpu);
|
||||
|
@ -4854,7 +4900,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 || nested_vmx_is_evmptr12_valid(vmx)))
|
||||
vmx->nested.need_vmcs12_to_shadow_sync = true;
|
||||
|
||||
/* in case we halted in L2 */
|
||||
|
@ -5292,18 +5338,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
|
|||
if (vmptr == vmx->nested.vmxon_ptr)
|
||||
return nested_vmx_fail(vcpu, VMXERR_VMCLEAR_VMXON_POINTER);
|
||||
|
||||
/*
|
||||
* When Enlightened VMEntry is enabled on the calling CPU we treat
|
||||
* memory area pointer by vmptr as Enlightened VMCS (as there's no good
|
||||
* way to distinguish it from VMCS12) and we must not corrupt it by
|
||||
* writing to the non-existent 'launch_state' field. The area doesn't
|
||||
* have to be the currently active EVMCS on the calling CPU and there's
|
||||
* nothing KVM has to do to transition it from 'active' to 'non-active'
|
||||
* state. It is possible that the area will stay mapped as
|
||||
* vmx->nested.hv_evmcs but this shouldn't be a problem.
|
||||
*/
|
||||
if (likely(!guest_cpuid_has_evmcs(vcpu) ||
|
||||
!evmptr_is_valid(nested_get_evmptr(vcpu)))) {
|
||||
if (likely(!nested_evmcs_handle_vmclear(vcpu, vmptr))) {
|
||||
if (vmptr == vmx->nested.current_vmptr)
|
||||
nested_release_vmcs12(vcpu);
|
||||
|
||||
|
@ -5320,8 +5355,6 @@ 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) {
|
||||
nested_release_evmcs(vcpu);
|
||||
}
|
||||
|
||||
return nested_vmx_succeed(vcpu);
|
||||
|
@ -5360,7 +5393,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 (!nested_vmx_is_evmptr12_valid(vmx)) {
|
||||
/*
|
||||
* In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
|
||||
* any VMREAD sets the ALU flags for VMfailInvalid.
|
||||
|
@ -5398,7 +5431,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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -5586,7 +5619,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 (nested_vmx_is_evmptr12_valid(vmx))
|
||||
return 1;
|
||||
|
||||
if (vmx->nested.current_vmptr != vmptr) {
|
||||
|
@ -5649,7 +5682,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(nested_vmx_is_evmptr12_valid(to_vmx(vcpu))))
|
||||
return 1;
|
||||
|
||||
if (get_vmx_mem_address(vcpu, exit_qual, instr_info,
|
||||
|
@ -6208,11 +6241,13 @@ static bool nested_vmx_l0_wants_exit(struct kvm_vcpu *vcpu,
|
|||
* Handle L2's bus locks in L0 directly.
|
||||
*/
|
||||
return true;
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
case EXIT_REASON_VMCALL:
|
||||
/* Hyper-V L2 TLB flush hypercall is handled by L0 */
|
||||
return guest_hv_cpuid_has_l2_tlb_flush(vcpu) &&
|
||||
nested_evmcs_l2_tlb_flush_enabled(vcpu) &&
|
||||
kvm_hv_is_tlb_flush_hcall(vcpu);
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -6435,7 +6470,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_is_evmptr12_set(vmx))
|
||||
kvm_state.flags |= KVM_STATE_NESTED_EVMCS;
|
||||
|
||||
if (is_guest_mode(vcpu) &&
|
||||
|
@ -6491,7 +6526,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 (nested_vmx_is_evmptr12_valid(vmx))
|
||||
/*
|
||||
* L1 hypervisor is not obliged to keep eVMCS
|
||||
* clean fields data always up-to-date while
|
||||
|
@ -6632,6 +6667,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
|
||||
|
@ -6641,6 +6677,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;
|
||||
}
|
||||
|
@ -7096,7 +7133,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
|
||||
};
|
||||
|
|
|
@ -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_is_evmptr12_set(vmx);
|
||||
}
|
||||
|
||||
static inline u16 nested_get_vpid02(struct kvm_vcpu *vcpu)
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#include "vmx.h"
|
||||
#include "x86.h"
|
||||
#include "smm.h"
|
||||
#include "vmx_onhyperv.h"
|
||||
|
||||
MODULE_AUTHOR("Qumranet");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -523,22 +524,14 @@ module_param(enlightened_vmcs, bool, 0444);
|
|||
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;
|
||||
/*
|
||||
* Synthetic VM-Exit is not enabled in current code and so All
|
||||
* evmcs in singe VM shares same assist page.
|
||||
*/
|
||||
if (!*p_hv_pa_pg)
|
||||
*p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT);
|
||||
hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu);
|
||||
|
||||
if (!*p_hv_pa_pg)
|
||||
if (partition_assist_page == INVALID_PAGE)
|
||||
return -ENOMEM;
|
||||
|
||||
evmcs = (struct hv_enlightened_vmcs *)to_vmx(vcpu)->loaded_vmcs->vmcs;
|
||||
|
||||
evmcs->partition_assist_page =
|
||||
__pa(*p_hv_pa_pg);
|
||||
evmcs->partition_assist_page = partition_assist_page;
|
||||
evmcs->hv_vm_id = (unsigned long)vcpu->kvm;
|
||||
evmcs->hv_enlightenments_control.nested_flush_hypercall = 1;
|
||||
|
||||
|
@ -2055,6 +2048,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index,
|
||||
&msr_info->data))
|
||||
return 1;
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
/*
|
||||
* Enlightened VMCS v1 doesn't have certain VMCS fields but
|
||||
* instead of just ignoring the features, different Hyper-V
|
||||
|
@ -2065,6 +2059,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
if (!msr_info->host_initiated && guest_cpuid_has_evmcs(vcpu))
|
||||
nested_evmcs_filter_control_msr(vcpu, msr_info->index,
|
||||
&msr_info->data);
|
||||
#endif
|
||||
break;
|
||||
case MSR_IA32_RTIT_CTL:
|
||||
if (!vmx_pt_mode_is_host_guest())
|
||||
|
@ -4833,7 +4828,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;
|
||||
|
|
|
@ -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 {
|
||||
|
@ -745,14 +747,4 @@ static inline bool vmx_can_use_ipiv(struct kvm_vcpu *vcpu)
|
|||
return lapic_in_kernel(vcpu) && enable_ipiv;
|
||||
}
|
||||
|
||||
static inline bool guest_cpuid_has_evmcs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* eVMCS is exposed to the guest if Hyper-V is enabled in CPUID and
|
||||
* eVMCS has been explicitly enabled by userspace.
|
||||
*/
|
||||
return vcpu->arch.hyperv_enabled &&
|
||||
to_vmx(vcpu)->nested.enlightened_vmcs_enabled;
|
||||
}
|
||||
|
||||
#endif /* __KVM_X86_VMX_H */
|
||||
|
|
36
arch/x86/kvm/vmx/vmx_onhyperv.c
Normal file
36
arch/x86/kvm/vmx/vmx_onhyperv.c
Normal file
|
@ -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);
|
||||
}
|
125
arch/x86/kvm/vmx/vmx_onhyperv.h
Normal file
125
arch/x86/kvm/vmx/vmx_onhyperv.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
/* 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 <asm/mshyperv.h>
|
||||
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
#include "capabilities.h"
|
||||
#include "hyperv_evmcs.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__ */
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include <asm/vmx.h>
|
||||
|
||||
#include "hyperv.h"
|
||||
#include "vmx_onhyperv.h"
|
||||
#include "vmcs.h"
|
||||
#include "../x86.h"
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -4020,6 +4023,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:
|
||||
|
@ -4032,6 +4036,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.
|
||||
|
@ -4377,6 +4382,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:
|
||||
|
@ -4390,6 +4396,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
|
||||
|
@ -4527,6 +4534,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)
|
||||
{
|
||||
|
@ -4547,6 +4555,7 @@ static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool kvm_is_vm_type_supported(unsigned long type)
|
||||
{
|
||||
|
@ -4580,9 +4589,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
case KVM_CAP_PIT_STATE2:
|
||||
case KVM_CAP_SET_IDENTITY_MAP_ADDR:
|
||||
case KVM_CAP_VCPU_EVENTS:
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
case KVM_CAP_HYPERV:
|
||||
case KVM_CAP_HYPERV_VAPIC:
|
||||
case KVM_CAP_HYPERV_SPIN:
|
||||
case KVM_CAP_HYPERV_TIME:
|
||||
case KVM_CAP_HYPERV_SYNIC:
|
||||
case KVM_CAP_HYPERV_SYNIC2:
|
||||
case KVM_CAP_HYPERV_VP_INDEX:
|
||||
|
@ -4592,6 +4603,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
case KVM_CAP_HYPERV_CPUID:
|
||||
case KVM_CAP_HYPERV_ENFORCE_CPUID:
|
||||
case KVM_CAP_SYS_HYPERV_CPUID:
|
||||
#endif
|
||||
case KVM_CAP_PCI_SEGMENT:
|
||||
case KVM_CAP_DEBUGREGS:
|
||||
case KVM_CAP_X86_ROBUST_SINGLESTEP:
|
||||
|
@ -4601,7 +4613,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
case KVM_CAP_GET_TSC_KHZ:
|
||||
case KVM_CAP_KVMCLOCK_CTRL:
|
||||
case KVM_CAP_READONLY_MEM:
|
||||
case KVM_CAP_HYPERV_TIME:
|
||||
case KVM_CAP_IOAPIC_POLARITY_IGNORED:
|
||||
case KVM_CAP_TSC_DEADLINE_TIMER:
|
||||
case KVM_CAP_DISABLE_QUIRKS:
|
||||
|
@ -4712,12 +4723,14 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
r = kvm_x86_ops.nested_ops->get_state ?
|
||||
kvm_x86_ops.nested_ops->get_state(NULL, NULL, 0) : 0;
|
||||
break;
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
case KVM_CAP_HYPERV_DIRECT_TLBFLUSH:
|
||||
r = kvm_x86_ops.enable_l2_tlb_flush != NULL;
|
||||
break;
|
||||
case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
|
||||
r = kvm_x86_ops.nested_ops->enable_evmcs != NULL;
|
||||
break;
|
||||
#endif
|
||||
case KVM_CAP_SMALLER_MAXPHYADDR:
|
||||
r = (int) allow_smaller_maxphyaddr;
|
||||
break;
|
||||
|
@ -4884,9 +4897,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;
|
||||
|
@ -5712,14 +5727,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;
|
||||
|
@ -5731,16 +5743,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;
|
||||
|
@ -5749,6 +5767,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];
|
||||
|
@ -6141,9 +6160,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;
|
||||
|
@ -7201,6 +7222,7 @@ set_pit2_out:
|
|||
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;
|
||||
|
||||
|
@ -7210,6 +7232,7 @@ set_pit2_out:
|
|||
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;
|
||||
|
@ -10588,19 +10611,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);
|
||||
}
|
||||
|
@ -10691,9 +10715,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;
|
||||
|
@ -10746,6 +10772,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;
|
||||
|
@ -10776,6 +10803,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))
|
||||
|
@ -12438,7 +12466,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -211,6 +211,8 @@ int main(void)
|
|||
vm_vaddr_t tsc_page_gva;
|
||||
int stage;
|
||||
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TIME));
|
||||
|
||||
vm = vm_create_with_one_vcpu(&vcpu, guest_main);
|
||||
|
||||
vcpu_set_hv_cpuid(vcpu);
|
||||
|
|
|
@ -240,11 +240,12 @@ int main(int argc, char *argv[])
|
|||
struct ucall uc;
|
||||
int stage;
|
||||
|
||||
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
|
||||
|
||||
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE));
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS));
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_DIRECT_TLBFLUSH));
|
||||
|
||||
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
|
||||
|
||||
hcall_page = vm_vaddr_alloc_pages(vm, 1);
|
||||
memset(addr_gva2hva(vm, hcall_page), 0x0, getpagesize());
|
||||
|
|
|
@ -43,6 +43,8 @@ int main(void)
|
|||
uint64_t *outval;
|
||||
struct ucall uc;
|
||||
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_CPUID));
|
||||
|
||||
/* Verify if extended hypercalls are supported */
|
||||
if (!kvm_cpuid_has(kvm_get_supported_hv_cpuid(),
|
||||
HV_ENABLE_EXTENDED_HYPERCALLS)) {
|
||||
|
|
|
@ -690,6 +690,8 @@ static void guest_test_hcalls_access(void)
|
|||
|
||||
int main(void)
|
||||
{
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_ENFORCE_CPUID));
|
||||
|
||||
pr_info("Testing access to Hyper-V specific MSRs\n");
|
||||
guest_test_msrs_access();
|
||||
|
||||
|
|
|
@ -248,6 +248,8 @@ int main(int argc, char *argv[])
|
|||
int stage = 1, r;
|
||||
struct ucall uc;
|
||||
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_SEND_IPI));
|
||||
|
||||
vm = vm_create_with_one_vcpu(&vcpu[0], sender_guest_code);
|
||||
|
||||
/* Hypercall input/output */
|
||||
|
|
|
@ -158,6 +158,7 @@ int main(int argc, char *argv[])
|
|||
int stage;
|
||||
|
||||
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM));
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_DIRECT_TLBFLUSH));
|
||||
|
||||
/* Create VM */
|
||||
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
|
||||
|
|
|
@ -590,6 +590,8 @@ int main(int argc, char *argv[])
|
|||
struct ucall uc;
|
||||
int stage = 1, r, i;
|
||||
|
||||
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TLBFLUSH));
|
||||
|
||||
vm = vm_create_with_one_vcpu(&vcpu[0], sender_guest_code);
|
||||
|
||||
/* Test data page */
|
||||
|
|
|
@ -125,21 +125,25 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu)
|
|||
|
||||
/*
|
||||
* Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
|
||||
* setting the nested state but flags other than eVMCS must be clear.
|
||||
* The eVMCS flag can be set if the enlightened VMCS capability has
|
||||
* been enabled.
|
||||
* setting the nested state. When the eVMCS flag is not set, the
|
||||
* expected return value is '0'.
|
||||
*/
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->flags = 0;
|
||||
state->hdr.vmx.vmxon_pa = -1ull;
|
||||
state->hdr.vmx.vmcs12_pa = -1ull;
|
||||
test_nested_state_expect_einval(vcpu, state);
|
||||
test_nested_state(vcpu, state);
|
||||
|
||||
state->flags &= KVM_STATE_NESTED_EVMCS;
|
||||
/*
|
||||
* When eVMCS is supported, the eVMCS flag can only be set if the
|
||||
* enlightened VMCS capability has been enabled.
|
||||
*/
|
||||
if (have_evmcs) {
|
||||
state->flags = KVM_STATE_NESTED_EVMCS;
|
||||
test_nested_state_expect_einval(vcpu, state);
|
||||
vcpu_enable_evmcs(vcpu);
|
||||
test_nested_state(vcpu, state);
|
||||
}
|
||||
test_nested_state(vcpu, state);
|
||||
|
||||
/* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
|
||||
state->hdr.vmx.smm.flags = 1;
|
||||
|
|
Loading…
Add table
Reference in a new issue