KVM: SVM: Process ICR on AVIC IPI delivery failure due to invalid target
authorSean Christopherson <seanjc@google.com>
Fri, 6 Jan 2023 01:12:37 +0000 (01:12 +0000)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 13 Jan 2023 15:45:22 +0000 (10:45 -0500)
Emulate ICR writes on AVIC IPI failures due to invalid targets using the
same logic as failures due to invalid types.  AVIC acceleration fails if
_any_ of the targets are invalid, and crucially VM-Exits before sending
IPIs to targets that _are_ valid.  In logical mode, the destination is a
bitmap, i.e. a single IPI can target multiple logical IDs.  Doing nothing
causes KVM to drop IPIs if at least one target is valid and at least one
target is invalid.

Fixes: 18f40c53e10f ("svm: Add VMEXIT handlers for AVIC")
Cc: stable@vger.kernel.org
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-Id: <20230106011306.85230-5-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/svm/avic.c

index 712330b..3b2c88b 100644 (file)
@@ -502,14 +502,18 @@ int avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu)
        trace_kvm_avic_incomplete_ipi(vcpu->vcpu_id, icrh, icrl, id, index);
 
        switch (id) {
+       case AVIC_IPI_FAILURE_INVALID_TARGET:
        case AVIC_IPI_FAILURE_INVALID_INT_TYPE:
                /*
                 * Emulate IPIs that are not handled by AVIC hardware, which
-                * only virtualizes Fixed, Edge-Triggered INTRs.  The exit is
-                * a trap, e.g. ICR holds the correct value and RIP has been
-                * advanced, KVM is responsible only for emulating the IPI.
-                * Sadly, hardware may sometimes leave the BUSY flag set, in
-                * which case KVM needs to emulate the ICR write as well in
+                * only virtualizes Fixed, Edge-Triggered INTRs, and falls over
+                * if _any_ targets are invalid, e.g. if the logical mode mask
+                * is a superset of running vCPUs.
+                *
+                * The exit is a trap, e.g. ICR holds the correct value and RIP
+                * has been advanced, KVM is responsible only for emulating the
+                * IPI.  Sadly, hardware may sometimes leave the BUSY flag set,
+                * in which case KVM needs to emulate the ICR write as well in
                 * order to clear the BUSY flag.
                 */
                if (icrl & APIC_ICR_BUSY)
@@ -525,8 +529,6 @@ int avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu)
                 */
                avic_kick_target_vcpus(vcpu->kvm, apic, icrl, icrh, index);
                break;
-       case AVIC_IPI_FAILURE_INVALID_TARGET:
-               break;
        case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
                WARN_ONCE(1, "Invalid backing page\n");
                break;