KVM: nVMX: add KVM_CAP_HYPERV_ENLIGHTENED_VMCS capability
authorVitaly Kuznetsov <vkuznets@redhat.com>
Tue, 16 Oct 2018 16:50:01 +0000 (18:50 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 16 Oct 2018 22:30:14 +0000 (00:30 +0200)
Enlightened VMCS is opt-in. The current version does not contain all
fields supported by nested VMX so we must not advertise the
corresponding VMX features if enlightened VMCS is enabled.

Userspace is given the enlightened VMCS version supported by KVM as
part of enabling KVM_CAP_HYPERV_ENLIGHTENED_VMCS. The version is to
be advertised to the nested hypervisor, currently done via a cpuid
leaf for Hyper-V.

Suggested-by: Ladi Prosek <lprosek@redhat.com>
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Reviewed-by: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
include/uapi/linux/kvm.h

index 4b09d4aa9bf43b3f1632b24273fa55b244e68467..258fc2c8530179e9a8800843822ebf5c691b1a44 100644 (file)
@@ -1179,6 +1179,9 @@ struct kvm_x86_ops {
        int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp);
 
        int (*get_msr_feature)(struct kvm_msr_entry *entry);
+
+       int (*nested_enable_evmcs)(struct kvm_vcpu *vcpu,
+                                  uint16_t *vmcs_version);
 };
 
 struct kvm_arch_async_pf {
index 2936c63bcc2f14c10c75a24fd4600111ece8d721..47b07211c5b1ea414af9f7a6f45abf7d2510ab29 100644 (file)
@@ -7036,6 +7036,13 @@ failed:
        return ret;
 }
 
+static int nested_enable_evmcs(struct kvm_vcpu *vcpu,
+                                  uint16_t *vmcs_version)
+{
+       /* Intel-only feature */
+       return -ENODEV;
+}
+
 static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .cpu_has_kvm_support = has_svm,
        .disabled_by_bios = is_disabled,
@@ -7165,6 +7172,8 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .mem_enc_op = svm_mem_enc_op,
        .mem_enc_reg_region = svm_register_enc_region,
        .mem_enc_unreg_region = svm_unregister_enc_region,
+
+       .nested_enable_evmcs = nested_enable_evmcs,
 };
 
 static int __init svm_init(void)
index 509d4e34dd62a852bce31a605b2a9010aa5e1e7c..459cdaa0d1cd8ee0516bf5d264bde290461a54fe 100644 (file)
@@ -846,6 +846,13 @@ struct nested_vmx {
 
        bool change_vmcs01_virtual_apic_mode;
 
+       /*
+        * Enlightened VMCS has been enabled. It does not mean that L1 has to
+        * use it. However, VMX features available to L1 will be limited based
+        * on what the enlightened VMCS supports.
+        */
+       bool enlightened_vmcs_enabled;
+
        /* L2 must run next, and mustn't decide to exit to L1. */
        bool nested_run_pending;
 
@@ -1589,6 +1596,34 @@ static inline void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) {}
 static inline void evmcs_touch_msr_bitmap(void) {}
 #endif /* IS_ENABLED(CONFIG_HYPERV) */
 
+static int nested_enable_evmcs(struct kvm_vcpu *vcpu,
+                              uint16_t *vmcs_version)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       /* We don't support disabling the feature for simplicity. */
+       if (vmx->nested.enlightened_vmcs_enabled)
+               return 0;
+
+       vmx->nested.enlightened_vmcs_enabled = true;
+
+       /*
+        * vmcs_version represents the range of supported Enlightened VMCS
+        * versions: lower 8 bits is the minimal version, higher 8 bits is the
+        * maximum supported version. KVM supports versions from 1 to
+        * KVM_EVMCS_VERSION.
+        */
+       *vmcs_version = (KVM_EVMCS_VERSION << 8) | 1;
+
+       vmx->nested.msrs.pinbased_ctls_high &= ~EVMCS1_UNSUPPORTED_PINCTRL;
+       vmx->nested.msrs.entry_ctls_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL;
+       vmx->nested.msrs.exit_ctls_high &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL;
+       vmx->nested.msrs.secondary_ctls_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC;
+       vmx->nested.msrs.vmfunc_controls &= ~EVMCS1_UNSUPPORTED_VMFUNC;
+
+       return 0;
+}
+
 static inline bool is_exception_n(u32 intr_info, u8 vector)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
@@ -14505,6 +14540,8 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
        .pre_enter_smm = vmx_pre_enter_smm,
        .pre_leave_smm = vmx_pre_leave_smm,
        .enable_smi_window = enable_smi_window,
+
+       .nested_enable_evmcs = nested_enable_evmcs,
 };
 
 static void vmx_cleanup_l1d_flush(void)
index eee871ad4aded304d6b171286a300f73d01374d9..50f308499ce55ffdf527526c77f9af84b7e74914 100644 (file)
@@ -2913,6 +2913,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_HYPERV_EVENTFD:
        case KVM_CAP_HYPERV_TLBFLUSH:
        case KVM_CAP_HYPERV_SEND_IPI:
+       case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
        case KVM_CAP_PCI_SEGMENT:
        case KVM_CAP_DEBUGREGS:
        case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -3700,6 +3701,10 @@ static int kvm_set_guest_paused(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;
 
@@ -3712,6 +3717,16 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
                        return -EINVAL;
                return kvm_hv_activate_synic(vcpu, cap->cap ==
                                             KVM_CAP_HYPERV_SYNIC2);
+       case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
+               r = kvm_x86_ops->nested_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;
+
        default:
                return -EINVAL;
        }
index 97780a0277fe02d85e333f9b06e34668f31abba8..a2f2b88455021a8033ad45286ebe58acbbb1d053 100644 (file)
@@ -963,6 +963,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_PPC_NESTED_HV 160
 #define KVM_CAP_HYPERV_SEND_IPI 161
 #define KVM_CAP_COALESCED_PIO 162
+#define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163
 
 #ifdef KVM_CAP_IRQ_ROUTING