| From b70d66c82c3fa1ef671aaf27bae935c5c2ed5649 Mon Sep 17 00:00:00 2001 |
| From: Vitaly Kuznetsov <vkuznets@redhat.com> |
| Date: Thu, 20 Feb 2020 18:22:04 +0100 |
| Subject: [PATCH] KVM: nVMX: clear PIN_BASED_POSTED_INTR from nested |
| pinbased_ctls only when apicv is globally disabled |
| |
| commit a4443267800af240072280c44521caab61924e55 upstream. |
| |
| When apicv is disabled on a vCPU (e.g. by enabling KVM_CAP_HYPERV_SYNIC*), |
| nothing happens to VMX MSRs on the already existing vCPUs, however, all new |
| ones are created with PIN_BASED_POSTED_INTR filtered out. This is very |
| confusing and results in the following picture inside the guest: |
| |
| $ rdmsr -ax 0x48d |
| ff00000016 |
| 7f00000016 |
| 7f00000016 |
| 7f00000016 |
| |
| This is observed with QEMU and 4-vCPU guest: QEMU creates vCPU0, does |
| KVM_CAP_HYPERV_SYNIC2 and then creates the remaining three. |
| |
| L1 hypervisor may only check CPU0's controls to find out what features |
| are available and it will be very confused later. Switch to setting |
| PIN_BASED_POSTED_INTR control based on global 'enable_apicv' setting. |
| |
| Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h |
| index f6cd554ff2e8..7cd3f8683b8c 100644 |
| --- a/arch/x86/kvm/vmx/capabilities.h |
| +++ b/arch/x86/kvm/vmx/capabilities.h |
| @@ -12,6 +12,7 @@ extern bool __read_mostly enable_ept; |
| extern bool __read_mostly enable_unrestricted_guest; |
| extern bool __read_mostly enable_ept_ad_bits; |
| extern bool __read_mostly enable_pml; |
| +extern bool __read_mostly enable_apicv; |
| extern int __read_mostly pt_mode; |
| |
| #define PT_MODE_SYSTEM 0 |
| diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c |
| index 736ceceb2ebe..8e1ee1dfceb1 100644 |
| --- a/arch/x86/kvm/vmx/nested.c |
| +++ b/arch/x86/kvm/vmx/nested.c |
| @@ -5569,8 +5569,7 @@ void nested_vmx_vcpu_setup(void) |
| * bit in the high half is on if the corresponding bit in the control field |
| * may be on. See also vmx_control_verify(). |
| */ |
| -void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps, |
| - bool apicv) |
| +void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps) |
| { |
| /* |
| * Note that as a general rule, the high half of the MSRs (bits in |
| @@ -5597,7 +5596,7 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps, |
| PIN_BASED_EXT_INTR_MASK | |
| PIN_BASED_NMI_EXITING | |
| PIN_BASED_VIRTUAL_NMIS | |
| - (apicv ? PIN_BASED_POSTED_INTR : 0); |
| + (enable_apicv ? PIN_BASED_POSTED_INTR : 0); |
| msrs->pinbased_ctls_high |= |
| PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | |
| PIN_BASED_VMX_PREEMPTION_TIMER; |
| diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h |
| index bbec76bb4f1a..161c305de3f3 100644 |
| --- a/arch/x86/kvm/vmx/nested.h |
| +++ b/arch/x86/kvm/vmx/nested.h |
| @@ -7,8 +7,7 @@ |
| #include "vmx.h" |
| |
| void vmx_leave_nested(struct kvm_vcpu *vcpu); |
| -void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps, |
| - bool apicv); |
| +void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps); |
| void nested_vmx_hardware_unsetup(void); |
| __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *)); |
| void nested_vmx_vcpu_setup(void); |
| diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c |
| index c6b597e13f46..4c414f5213e5 100644 |
| --- a/arch/x86/kvm/vmx/vmx.c |
| +++ b/arch/x86/kvm/vmx/vmx.c |
| @@ -95,7 +95,7 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO); |
| static bool __read_mostly fasteoi = 1; |
| module_param(fasteoi, bool, S_IRUGO); |
| |
| -static bool __read_mostly enable_apicv = 1; |
| +bool __read_mostly enable_apicv = 1; |
| module_param(enable_apicv, bool, S_IRUGO); |
| |
| /* |
| @@ -6676,8 +6676,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) |
| |
| if (nested) |
| nested_vmx_setup_ctls_msrs(&vmx->nested.msrs, |
| - vmx_capability.ept, |
| - kvm_vcpu_apicv_active(&vmx->vcpu)); |
| + vmx_capability.ept); |
| else |
| memset(&vmx->nested.msrs, 0, sizeof(vmx->nested.msrs)); |
| |
| @@ -6760,8 +6759,7 @@ static void __init vmx_check_processor_compat(void *rtn) |
| if (setup_vmcs_config(&vmcs_conf, &vmx_cap) < 0) |
| *(int *)rtn = -EIO; |
| if (nested) |
| - nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept, |
| - enable_apicv); |
| + nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept); |
| if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) { |
| printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n", |
| smp_processor_id()); |
| @@ -7632,7 +7630,7 @@ static __init int hardware_setup(void) |
| |
| if (nested) { |
| nested_vmx_setup_ctls_msrs(&vmcs_config.nested, |
| - vmx_capability.ept, enable_apicv); |
| + vmx_capability.ept); |
| |
| r = nested_vmx_hardware_setup(kvm_vmx_exit_handlers); |
| if (r) |
| -- |
| 2.7.4 |
| |