[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v1 08/28] x86/hvm: avic: add AVIC_INCOMP_IPI VMEXIT handler


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: dmukhin@xxxxxxxx
  • Date: Wed, 4 Nov 2026 17:33:25 -0800
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 148.163.138.245) smtp.rcpttodomain=lists.xenproject.org smtp.mailfrom=ford.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=ford.com; dkim=pass (signature was verified) header.d=saarlouis.ford.com; dkim=pass (signature was verified) header.d=ford.com; arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=aIjZuqVWwlCdqrpZV1nVy5ZvbYSxc2s85Odwd4BoSOI=; b=D3t+mek+f+K/LrZcYCYSA36gK4YMRpBq8xIhxZSLQPftDzkmYcMVAABj9BEQ6AgD0XzwFkfK77aiUkhH8IQ4ozRkOQYG8aCLL6VkHOhzz4popghYXy6URKortGwyNbfUtdXmktjc8fDNgNgaRHgq3CYr/lD0DG/5wF8anCgKnvHTvP0sJ/ini6BRE4Q4a6mPpeUmbFO91glDl9Yr23acFlY+6LqB13DDPSc0s6P+qW/H0F2fgN7qO5W/pzmTT834VeaK//k8jLTJkD/+6g4AQppuMFfquyXmNGkkUD+UzCUC3+D7xmwZvJuqPEMJBpNVc+vhjGg8SZ8Ohh3szUvZgA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=gCyz5K8il4bPwxEo6dLcI/ThcsHVFL30BqxMGdjq31u8VCAu58GcCJ3IuhdT2tXlmkFT3BaYpsEk0KOpiwAPJn2k7zMR8csP5Pjk8Thl8aip8h4I9rd+LMmqI3vVWx5jLVY1P0jtS5wnid/3ImNLsRHIB9AQLWqMdM1cJDcaXKIhF0qAXufasXSCXW8SfMNSHm3gOQyJQ5cZr5m9nLsWSUzK9HJUNUgj+c2H7fPpMbUXd1+0+vCQrzChOkxF3oT0iOHffvUZvbJK2udHU6KwX8WCU4e8MHLLf+gz/J724bUjDPmZ0jorrPisqJl/9HxjKbs8+O+2vtVzB5fsyM6Xsg==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=ppford header.d=ford.com header.i="@ford.com" header.h="Cc:Content-Transfer-Encoding:Content-Type:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"; dkim=pass header.s=selector2-azureford-onmicrosoft-com header.d=azureford.onmicrosoft.com header.i="@azureford.onmicrosoft.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"; dkim=pass header.s=ppserprodsaar header.d=saarlouis.ford.com header.i="@saarlouis.ford.com" header.h="Cc:Content-Transfer-Encoding:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"; dkim=pass header.s=ppfserpocford header.d=ford.com header.i="@ford.com" header.h="Cc:Content-Transfer-Encoding:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"
  • Cc: andrew.cooper3@xxxxxxxxxx, jason.andryuk@xxxxxxx, jbeulich@xxxxxxxx, roger@xxxxxxxxxxxxxx, teddy.astie@xxxxxxxxxx, dmukhin@xxxxxxx, Denis Mukhin <dmukhin@xxxxxxxx>
  • Delivery-date: Thu, 05 Nov 2026 01:34:58 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Pser-m365-app: SER-APP

From: Denis Mukhin <dmukhin@xxxxxxxx>

Introduce new VMEXIT reason 0x401 [1] to handle the case when an IPI cannot
be delivered to all targeted guest virtual processors because at least one
guest virtual processor was not allocated to a physical core at the time.

If incomplete IPI occurs, try to emulate an IPI.

[1] AMD64 APM Volume 2, Table 15-22 "Guest vAPIC Register Access Behavior"
Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
 xen/arch/x86/hvm/svm/avic.c              | 115 +++++++++++++++++++++++
 xen/arch/x86/hvm/svm/avic.h              |   2 +
 xen/arch/x86/hvm/svm/svm.c               |   4 +
 xen/arch/x86/hvm/svm/vmcb.h              |   7 ++
 xen/arch/x86/include/asm/hvm/svm-types.h |  10 ++
 5 files changed, 138 insertions(+)

diff --git a/xen/arch/x86/hvm/svm/avic.c b/xen/arch/x86/hvm/svm/avic.c
index bc98661a7057..0cfb21cb8e3f 100644
--- a/xen/arch/x86/hvm/svm/avic.c
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -9,6 +9,7 @@
 #include <xen/param.h>
 
 #include "avic.h"
+#include "svm.h"
 #include "vmcb.h"
 
 #define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK        GENMASK_ULL(51, 12U)
@@ -235,6 +236,120 @@ void svm_avic_vmcb_destroy(struct vcpu *v)
     vmcb->avic_vapic_bar = 0;
 }
 
+/*
+ * Handle the AVIC_INCOMP_IPI #VMEXIT when AVIC is enabled.
+ *
+ * The hardware generates this fault when an IPI could not be delivered to
+ * all targeted guest virtual processors because at least one guest virtual
+ * processor was not allocated to a physical core at the time.
+ */
+void svm_avic_vmexit_incomp_ipi(struct cpu_user_regs *regs)
+{
+    struct vcpu *v = current;
+    struct domain *d = v->domain;
+    struct svm_vcpu *sv = &v->arch.hvm.svm;
+    const struct vmcb_struct *vmcb = sv->vmcb;
+    uint32_t icrh = vmcb->exitinfo1 >> 32;
+    uint32_t icrl = vmcb->exitinfo1;
+    uint32_t id = vmcb->exitinfo2 >> 32;
+    uint32_t index = vmcb->exitinfo2 & 0x1FFU;
+
+    if ( id >= AVIC_IPI_FAILURE_MAX )
+    {
+        domain_crash(
+            d, "%pv: AVIC: Unknown IPI interception (exitinfo1=%#"PRIx64" 
exitinfo2=%#"PRIx64")\n",
+            v, vmcb->exitinfo1, vmcb->exitinfo2);
+        return;
+    }
+
+    BUG_ON(sv->avic_physical_id == NULL);
+
+    switch ( id )
+    {
+    case AVIC_IPI_FAILURE_INVALID_INT_TYPE:
+        /*
+         * AVIC hardware handles the delivery of IPIs when the specified
+         * Message Type is Fixed (also known as fixed delivery mode) and the
+         * Trigger Mode is edge-triggered. The hardware also supports self and
+         * broadcast delivery modes specified via the Destination
+         * Shorthand(DSH) field of the ICRL. Logical and physical APIC ID
+         * formats are supported. All other IPI types cause a #VMEXIT, which
+         * needs to emulated.
+         */
+        gprintk(XENLOG_ERR,
+                "%pv: AVIC: Invalid IPI type (icr=%#08x:%08x, idx=%u)"
+                " avic_physical_id=%#"PRIx64"\n",
+                v, icrh, icrl, index, ACCESS_ONCE(*sv->avic_physical_id));
+
+        vlapic_reg_write(v, APIC_ICR2, icrh);
+        vlapic_reg_write(v, APIC_ICR,  icrl);
+
+        break;
+
+    case AVIC_IPI_FAILURE_INVALID_TARGET:
+        /*
+         * AVIC can report an invalid target for guest IPIs, for example when
+         * a logical destination mask contains IDs that are not backed by
+         * vCPUs. This is guest-controlled input and is not a reason to crash
+         * the domain. Handle invalid-target exits like unsupported interrupt
+         * types.
+         */
+        gprintk(XENLOG_ERR,
+                "%pv: AVIC: Invalid IPI target (icr=%#08x:%08x, idx=%u)"
+                " avic_physical_id=%#"PRIx64"\n",
+                v, icrh, icrl, index, ACCESS_ONCE(*sv->avic_physical_id));
+
+        vlapic_reg_write(v, APIC_ICR2, icrh);
+        vlapic_reg_write(v, APIC_ICR,  icrl);
+
+        break;
+
+    case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING:
+    {
+        /*
+         * At this point, we expect that the AVIC HW has already set the
+         * appropriate IRR bits on the valid target vCPUs. Kick all the
+         * appropriate vCPUs (e.g. logically addressed or broadcast IPI).
+         */
+        struct vcpu *target;
+        uint32_t dest = GET_xAPIC_DEST_FIELD(icrh);
+        uint32_t short_hand = icrl & APIC_SHORT_MASK;
+        bool dest_mode = icrl & APIC_DEST_MASK;
+
+        for_each_vcpu ( d, target )
+        {
+            if ( target == v )
+                continue;
+
+            if ( vlapic_match_dest(vcpu_vlapic(target),
+                                   vcpu_vlapic(v),
+                                   short_hand, dest, dest_mode) )
+            {
+                vcpu_kick(target);
+            }
+        }
+
+        break;
+    }
+
+    case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
+        domain_crash(
+            d, "%pv: AVIC: Invalid backing page (icr=%#08x:%08x, idx=%u)\n",
+            v, icrh, icrl, index);
+        break;
+
+    case AVIC_IPI_FAILURE_INVALID_IPI_VECTOR:
+        domain_crash(
+            d, "%pv: AVIC: Invalid IPI with vector < 16 (%#x)\n",
+            v, index);
+        break;
+
+    default:
+        ASSERT_UNREACHABLE();
+        break;
+    }
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/hvm/svm/avic.h b/xen/arch/x86/hvm/svm/avic.h
index 1084ae683944..2668d4481425 100644
--- a/xen/arch/x86/hvm/svm/avic.h
+++ b/xen/arch/x86/hvm/svm/avic.h
@@ -14,4 +14,6 @@ void svm_avic_domain_relinquish_resources(struct domain *d);
 int svm_avic_vmcb_create(struct vcpu *v);
 void svm_avic_vmcb_destroy(struct vcpu *v);
 
+void svm_avic_vmexit_incomp_ipi(struct cpu_user_regs *regs);
+
 #endif /* __SVM_AVIC_H__ */
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 8b7bfed0049f..693b5c29287a 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -3078,6 +3078,10 @@ void asmlinkage svm_vmexit_handler(void)
         vmcb->bus_lock_count = 1;
         break;
 
+    case VMEXIT_AVIC_INCOMP_IPI:
+        svm_avic_vmexit_incomp_ipi(regs);
+        break;
+
     default:
     unexpected_exit_type:
         gprintk(XENLOG_ERR, "Unexpected vmexit: reason %#"PRIx64", "
diff --git a/xen/arch/x86/hvm/svm/vmcb.h b/xen/arch/x86/hvm/svm/vmcb.h
index 1ee5da053a9a..532382bd02f3 100644
--- a/xen/arch/x86/hvm/svm/vmcb.h
+++ b/xen/arch/x86/hvm/svm/vmcb.h
@@ -291,6 +291,13 @@ enum VMEXIT_EXITCODE
     VMEXIT_BUS_LOCK         = 165, /* 0xa5 */
     /* Remember to also update VMEXIT_NPF_PERFC! */
     VMEXIT_NPF              = 1024, /* 0x400, nested paging fault */
+
+    /*
+     * AMD64 Architecture Programmer's Manual Volume 2: System Programming
+     * Table 15-22. Guest vAPIC Register Access Behavior
+     */
+    VMEXIT_AVIC_INCOMP_IPI  = 1025, /* 0x401 */
+
     /* Remember to also update SVM_PERF_EXIT_REASON_SIZE! */
     VMEXIT_INVALID          =  -1
 };
diff --git a/xen/arch/x86/include/asm/hvm/svm-types.h 
b/xen/arch/x86/include/asm/hvm/svm-types.h
index 30bdaf27a856..93629418c225 100644
--- a/xen/arch/x86/include/asm/hvm/svm-types.h
+++ b/xen/arch/x86/include/asm/hvm/svm-types.h
@@ -25,6 +25,16 @@ struct svm_domain {
     uint64_t *avic_physical_id_table;
 };
 
+/* AVIC_INCOMP_IPI #VMEXIT reason. */
+enum avic_ipi_failure_cause {
+    AVIC_IPI_FAILURE_INVALID_INT_TYPE       = 0,
+    AVIC_IPI_FAILURE_TARGET_NOT_RUNNING     = 1,
+    AVIC_IPI_FAILURE_INVALID_TARGET         = 2,
+    AVIC_IPI_FAILURE_INVALID_BACKING_PAGE   = 3,
+    AVIC_IPI_FAILURE_INVALID_IPI_VECTOR     = 4,
+    AVIC_IPI_FAILURE_MAX,
+};
+
 struct svm_vcpu {
     struct vmcb_struct *vmcb;
     unsigned long *msrpm;
-- 
2.55.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.