KVM: nVMX: expose VMX capabilities for nested hypervisors to userspace
authorPaolo Bonzini <pbonzini@redhat.com>
Mon, 26 Feb 2018 12:40:09 +0000 (13:40 +0100)
committerRadim Krčmář <rkrcmar@redhat.com>
Tue, 6 Mar 2018 17:40:46 +0000 (18:40 +0100)
Use the new MSR feature framework to tell userspace which VMX capabilities
are available for nested hypervisors.  Before, these were only accessible
with the KVM_GET_MSR VCPU ioctl, after VCPUs had been created.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c

index 9b73ec7..66a77b1 100644 (file)
@@ -958,6 +958,7 @@ static struct vmcs_config {
        u32 cpu_based_2nd_exec_ctrl;
        u32 vmexit_ctrl;
        u32 vmentry_ctrl;
+       struct nested_vmx_msrs nested;
 } vmcs_config;
 
 static struct vmx_capability {
@@ -2689,6 +2690,11 @@ static inline bool nested_vmx_allowed(struct kvm_vcpu *vcpu)
  */
 static void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, bool apicv)
 {
+       if (!nested) {
+               memset(msrs, 0, sizeof(*msrs));
+               return;
+       }
+
        /*
         * Note that as a general rule, the high half of the MSRs (bits in
         * the control fields which may be 1) should be initialized by the
@@ -2713,13 +2719,11 @@ static void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, bool apicv)
        msrs->pinbased_ctls_high &=
                PIN_BASED_EXT_INTR_MASK |
                PIN_BASED_NMI_EXITING |
-               PIN_BASED_VIRTUAL_NMIS;
+               PIN_BASED_VIRTUAL_NMIS |
+               (apicv ? PIN_BASED_POSTED_INTR : 0);
        msrs->pinbased_ctls_high |=
                PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
                PIN_BASED_VMX_PREEMPTION_TIMER;
-       if (apicv)
-               msrs->pinbased_ctls_high |=
-                       PIN_BASED_POSTED_INTR;
 
        /* exit controls */
        rdmsr(MSR_IA32_VMX_EXIT_CTLS,
@@ -3231,7 +3235,16 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu,
 
 static int vmx_get_msr_feature(struct kvm_msr_entry *msr)
 {
-       return 1;
+       switch (msr->index) {
+       case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
+               if (!nested)
+                       return 1;
+               return vmx_get_vmx_msr(&vmcs_config.nested, msr->index, &msr->data);
+       default:
+               return 1;
+       }
+
+       return 0;
 }
 
 /*
@@ -3697,6 +3710,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
        u32 _vmexit_control = 0;
        u32 _vmentry_control = 0;
 
+       memset(vmcs_conf, 0, sizeof(*vmcs_conf));
        min = CPU_BASED_HLT_EXITING |
 #ifdef CONFIG_X86_64
              CPU_BASED_CR8_LOAD_EXITING |
@@ -7091,6 +7105,7 @@ static __init int hardware_setup(void)
                init_vmcs_shadow_fields();
 
        kvm_set_posted_intr_wakeup_handler(wakeup_handler);
+       nested_vmx_setup_ctls_msrs(&vmcs_config.nested, enable_apicv);
 
        kvm_mce_cap_supported |= MCG_LMCE_P;
 
@@ -9822,6 +9837,7 @@ static void __init vmx_check_processor_compat(void *rtn)
        *(int *)rtn = 0;
        if (setup_vmcs_config(&vmcs_conf) < 0)
                *(int *)rtn = -EIO;
+       nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, enable_apicv);
        if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
                printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
                                smp_processor_id());
index 967cc13..294caeb 100644 (file)
@@ -1056,6 +1056,25 @@ static unsigned num_emulated_msrs;
  * can be used by a hypervisor to validate requested CPU features.
  */
 static u32 msr_based_features[] = {
+       MSR_IA32_VMX_BASIC,
+       MSR_IA32_VMX_TRUE_PINBASED_CTLS,
+       MSR_IA32_VMX_PINBASED_CTLS,
+       MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
+       MSR_IA32_VMX_PROCBASED_CTLS,
+       MSR_IA32_VMX_TRUE_EXIT_CTLS,
+       MSR_IA32_VMX_EXIT_CTLS,
+       MSR_IA32_VMX_TRUE_ENTRY_CTLS,
+       MSR_IA32_VMX_ENTRY_CTLS,
+       MSR_IA32_VMX_MISC,
+       MSR_IA32_VMX_CR0_FIXED0,
+       MSR_IA32_VMX_CR0_FIXED1,
+       MSR_IA32_VMX_CR4_FIXED0,
+       MSR_IA32_VMX_CR4_FIXED1,
+       MSR_IA32_VMX_VMCS_ENUM,
+       MSR_IA32_VMX_PROCBASED_CTLS2,
+       MSR_IA32_VMX_EPT_VPID_CAP,
+       MSR_IA32_VMX_VMFUNC,
+
        MSR_F10H_DECFG,
        MSR_IA32_UCODE_REV,
 };