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

[PATCH v1 21/28] x86/hvm: enable debug hypercall for posted interrupts


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: dmukhin@xxxxxxxx
  • Date: Wed, 4 Nov 2026 17:33:38 -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=KVyHg65VjisPRHtr2bi3zOba6+8hFJxogzy5Htt3tIA=; b=xuI99meYZ88eoqWiLiJJ7Z6CMzqYAyVR7fJcl3n1b6KXZHDoMTklQJo61kUHZwyBfiBC7BkAm8E4ikAJUgngYiZP0HYmBBuHHjG217lZVc/TdoAQ7Ahq5vDlCFeo0Udy8YVMJO3goOLF5Ml5ifT5owCfESYh4YmgYDUwvvSWIcFKEHuCNR2MrqLjeWvA0xNK1pbcYTTMJS1pcAujT4SjuJBeTYj6vv5dtASDhf12v2kdFoXm34C+cuWFuyTHM8YRNIVGzPNFL9Wen8HuDR5GrQKiSKft1q3So7bYPXnldmqU4mtHLBIXHT3uLj2g/c82TNlgwguu7FlwUfCEioWfOg==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=oN32ZjSXMeUgAeAbQgRqTcSOS9PzvwRUAgpE2l1IBS2XlzAY27M7Kw4XRqVoCvQVePfORLzvtk2mNU2ZfYdcQduufqu4nVflH+94pDV5xMHswsmYrP1CPYhWL1FZh3xLzQzBTNF/tX6AodYKiTU9CRbNTP8/weXl3W/Coc+M3JeDlmUUewvfYCmoMIz6RCfXC3tgFq1i0Qkosf9QydWtzzdA6iGnuwG3TozbcGuqkoUULwsGghCALS0hjkIVurarBNldPtfgWeA3JLAFwzFXKmtV/UguqPQrnF/MIs5X+L+PS6IZ64jt21m9oxY8WjyYntwODLmFOPEEqriHDFBpuw==
  • 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:35:12 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Pser-m365-app: SER-APP

From: Denis Mukhin <dmukhin@xxxxxxxx>

There is a need to change AVIC behavior at run-time to enable feature
testing.

Add new subcommand XEN_DOMCTL_DEBUG_OP_POSTED_INTR for XEN_DOMCTL_debug_op
hypercall.

Perform necessary plumbing through hvm_function_table and export
convenience functions for AVIC.

Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
 xen/arch/x86/hvm/hvm.c             |  15 ++++
 xen/arch/x86/hvm/svm/avic.c        | 132 +++++++++++++++++++++++++++++
 xen/arch/x86/hvm/svm/avic.h        |   2 +
 xen/arch/x86/hvm/svm/svm.c         |   1 +
 xen/arch/x86/include/asm/hvm/hvm.h |  17 ++++
 xen/include/public/domctl.h        |   1 +
 6 files changed, 168 insertions(+)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 42139837904a..a6ca56b08942 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -5257,6 +5257,21 @@ int hvm_debug_op(struct domain *d, unsigned int op, 
unsigned int vcpu,
 
         break;
 
+    case XEN_DOMCTL_DEBUG_OP_POSTED_INTR:
+        gdprintk(XENLOG_G_INFO,
+                "%pd: XEN_DOMCTL_DEBUG_OP_POSTED_INTR %u\n",
+                d, arg);
+
+        if ( current->domain != d )
+            domain_pause(d);
+
+        rc = hvm_debug_posted_intr(d, arg);
+
+        if ( current->domain != d )
+            domain_unpause(d);
+
+        break;
+
     default:
         return -ENOSYS;
     }
diff --git a/xen/arch/x86/hvm/svm/avic.c b/xen/arch/x86/hvm/svm/avic.c
index 4dcd2c94ea87..ca779be22eea 100644
--- a/xen/arch/x86/hvm/svm/avic.c
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -729,6 +729,81 @@ void cf_check svm_avic_hvm_deliver_posted_intr(struct vcpu 
*v, uint8_t vector)
     }
 }
 
+static void avic_domain_noaccel_state_sync(struct domain *d)
+{
+    struct svm_domain *sd = &d->arch.hvm.svm;
+    struct vcpu *v;
+
+    memset(sd->avic_logical_id_table, 0, PAGE_SIZE);
+
+    for_each_vcpu ( d, v )
+    {
+        struct svm_vcpu *sv = &v->arch.hvm.svm;
+        uint32_t ldr = vlapic_reg_read(v, APIC_LDR);
+        uint32_t dfr = vlapic_reg_read(v, APIC_DFR);
+        uint32_t id = GET_xAPIC_ID(vlapic_reg_read(v, APIC_ID));
+
+        sv->avic_ldr = ldr;
+        sv->avic_dfr = dfr;
+
+        avic_ldr_write(v, id, ldr);
+    }
+}
+
+static void avic_domain_enable(struct domain *d)
+{
+    struct vcpu *v;
+    int rc;
+
+    rc = avic_set_mmio_p2m_entry(d);
+    if ( rc )
+        goto out;
+
+    /* Re-load LDR/DFR from vLAPIC */
+    avic_domain_noaccel_state_sync(d);
+
+    for_each_vcpu ( d, v )
+    {
+        /* VINTR=0 */
+        svm_clear_intr_window(v);
+
+        /* VMCB.avic_enable=1 */
+        avic_vcpu_enable(v, true);
+    }
+
+    return;
+
+ out:
+    gdprintk(XENLOG_INFO,
+             "%pd: AVIC: failed to enable APIC MMIO access: %d\n",
+             d, rc);
+}
+
+static void avic_domain_disable(struct domain *d)
+{
+    struct vcpu *v;
+    int rc;
+
+    for_each_vcpu ( d, v )
+    {
+        /* IsRunning=0 */
+        avic_vcpu_clear_running(v);
+
+        /* VMCB.avic_enable=0 */
+        avic_vcpu_enable(v, false);
+
+        avic_stats_reset(v);
+    }
+
+    rc = avic_clear_mmio_p2m_entry(d);
+    if ( !rc )
+        return;
+
+    gdprintk(XENLOG_INFO,
+             "%pd: AVIC: failed to disable APIC MMIO access: %d\n",
+             d, rc);
+}
+
 void cf_check svm_avic_hvm_dump_posted_intr(const struct vcpu *v)
 {
     const struct svm_vcpu *sv = &v->arch.hvm.svm;
@@ -752,6 +827,63 @@ void cf_check svm_avic_hvm_dump_posted_intr(const struct 
vcpu *v)
            sv->avic_cnt_kick);
 }
 
+static void avic_domain_dump_stats(struct domain *d)
+{
+    struct vcpu *v;
+
+    for_each_vcpu ( d, v )
+    {
+        svm_avic_hvm_dump_posted_intr(v);
+        avic_stats_reset(v);
+    }
+}
+
+/* Interrupt acceleration control operations. */
+enum {
+    POSTED_INTR_DISABLE     = 0,
+    POSTED_INTR_ENABLE      = 1,
+    POSTED_INTR_DUMP_STATS  = 2,
+};
+
+void cf_check svm_avic_hvm_debug_posted_intr(struct domain *d,
+                                             unsigned int arg)
+{
+    struct vcpu *v;
+
+    /* Ensure no vCPU can VMRUN while updating VMCB for AVIC. */
+    for_each_vcpu ( d, v )
+    {
+        if ( !avic_vcpu_supported(v) )
+            goto out;
+
+        if ( v != current )
+            vcpu_pause(v);
+    }
+
+    switch ( arg ) {
+    case POSTED_INTR_DISABLE:
+        avic_domain_disable(d);
+        break;
+
+    case POSTED_INTR_ENABLE:
+        avic_domain_enable(d);
+        break;
+
+    case POSTED_INTR_DUMP_STATS:
+        avic_domain_dump_stats(d);
+        break;
+
+    default:
+        ASSERT_UNREACHABLE();
+        break;
+    }
+
+ out:
+    for_each_vcpu ( d, v )
+        if ( v != current )
+            vcpu_unpause(v);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/hvm/svm/avic.h b/xen/arch/x86/hvm/svm/avic.h
index 24d5fab59b29..e40aa77264ad 100644
--- a/xen/arch/x86/hvm/svm/avic.h
+++ b/xen/arch/x86/hvm/svm/avic.h
@@ -34,5 +34,7 @@ void svm_avic_vcpu_switch_from(struct vcpu *v);
 
 void cf_check svm_avic_hvm_deliver_posted_intr(struct vcpu *v, uint8_t vector);
 void cf_check svm_avic_hvm_dump_posted_intr(const struct vcpu *v);
+void cf_check svm_avic_hvm_debug_posted_intr(struct domain *d,
+                                             unsigned int arg);
 
 #endif /* __SVM_AVIC_H__ */
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 83977d411b0a..f2eb01799c63 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -2520,6 +2520,7 @@ static void __init svm_avic_start(void)
 
     svm_function_table.deliver_posted_intr = svm_avic_hvm_deliver_posted_intr;
     svm_function_table.dump_posted_intr = svm_avic_hvm_dump_posted_intr;
+    svm_function_table.debug_posted_intr = svm_avic_hvm_debug_posted_intr;
 
     svm_function_table.caps.virtual_intr_delivery = true;
 }
diff --git a/xen/arch/x86/include/asm/hvm/hvm.h 
b/xen/arch/x86/include/asm/hvm/hvm.h
index 6efc533b35df..d44f136fae8f 100644
--- a/xen/arch/x86/include/asm/hvm/hvm.h
+++ b/xen/arch/x86/include/asm/hvm/hvm.h
@@ -218,6 +218,7 @@ struct hvm_function_table {
     void (*process_isr)(int isr, struct vcpu *v);
     void (*deliver_posted_intr)(struct vcpu *v, u8 vector);
     void (*dump_posted_intr)(const struct vcpu *v);
+    void (*debug_posted_intr)(struct domain *d, unsigned int arg);
     void (*sync_pir_to_irr)(struct vcpu *v);
     bool (*test_pir)(const struct vcpu *v, uint8_t vector);
     void (*handle_eoi)(uint8_t vector, int isr);
@@ -859,6 +860,16 @@ static inline void hvm_dump_posted_intr(const struct vcpu 
*v)
         alternative_vcall(hvm_funcs.dump_posted_intr, v);
 }
 
+static inline int hvm_debug_posted_intr(struct domain *d, unsigned int arg)
+{
+    if ( !hvm_funcs.debug_posted_intr )
+        return -ENOSYS;
+
+    alternative_vcall(hvm_funcs.debug_posted_intr, d, arg);
+
+    return 0;
+}
+
 #else  /* CONFIG_HVM */
 
 #define hvm_enabled false
@@ -971,6 +982,12 @@ static inline void hvm_dump_posted_intr(const struct vcpu 
*v)
     ASSERT_UNREACHABLE();
 }
 
+static inline int hvm_debug_posted_intr(struct domain *d, unsigned int arg)
+{
+    ASSERT_UNREACHABLE();
+    return -EOPNOTSUPP;
+}
+
 #define is_viridian_domain(d) ((void)(d), false)
 #define is_viridian_vcpu(v) ((void)(v), false)
 #define has_viridian_time_ref_count(d) ((void)(d), false)
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 546d9a8ac9c0..b72164f61ce2 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -765,6 +765,7 @@ struct xen_domctl_subscribe {
 /* XEN_DOMCTL_debug_op */
 #define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF         0
 #define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON          1
+#define XEN_DOMCTL_DEBUG_OP_POSTED_INTR             3
 struct xen_domctl_debug_op {
     uint32_t op;   /* IN */
     uint32_t vcpu; /* IN */
-- 
2.55.0




 


Rackspace

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