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

[PATCH v1 04/28] x86/hvm: avic: add domain state initialization


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: dmukhin@xxxxxxxx
  • Date: Wed, 4 Nov 2026 17:33:21 -0800
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 205.220.161.53) 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=/rytJLaOrpToKNYYdwh3BV0gO7/pEbXcSOViRTflAPA=; b=NsF55cMiba715zDOShXRt6ypcFjJoyhJMqUD1SysBTYjlijjiV+0w/9pkDjEVnKTo3r8nisO5Ar6BRCXcxb53PTDx69KIZlzPqGBK/sQ1+E6J9ySIdHWJBq+uS5lRMPtmeNjAqskP1ftffQ66FhWoOWyhlc2BWtwciDqgf7apKp+Mm/JkvfNEXDPNh+Cu1+3ADVaWSMcY2HiiJdCs3ksw7TDmcrK7/fEa71bOqjo6M5HLMyede1Xn7apojN2aWHb+AkpaNkM698JrlkXFZ/TjC8nyk80+TAf+tjkxXSPYlbTFkrUuVeBUH04ofjDZ0zf9I429+IYPEKMZj3Ypjz1Mg==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=mhZ9hwWCX3syEKEYwKmHkMudbA/p72i12cd9lpTHetNDwFwv4evyKh/wmU0KDBYw9qNEhasOF6U7bXSKwKEZiD9eKKXYEHb2GMmyL30wUkZgTViAEq6q4WVwLNJO5/mdZdg1H8zUMD0lzxAEXrV1YO9CW1fR8pbRcG3e8ZLOpbOewpQKG4jwxOp7PTUdzqu/5lCHDLCaGdKC6Eo0VVUFJtyVOyxwFIGZPP9CLKc/0oQu4NIj4KwUkX6V0kHOq4bUq/l2m9KeS1O0tXZdcb/Y0ymYFNiTNeyyB8jtIJm+7dlmQTvfUryzrWoSFYb8jFuSL2nRIeRSA50jL4WIEGaygA==
  • 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:32 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Pser-m365-app: SER-APP

From: Denis Mukhin <dmukhin@xxxxxxxx>

Establish per-domain SVM AVIC backing page mapping and SPA mappings
for APIC physical/logical ID tables. Use MEMF_no_refcount mappings
similarly to Intel's VMX APICv setup.

Gate per-domain AVIC state initialization behind 'svm_avic=' command
line option.

Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
 xen/arch/x86/hvm/svm/Makefile            |   1 +
 xen/arch/x86/hvm/svm/avic.c              | 136 +++++++++++++++++++++++
 xen/arch/x86/hvm/svm/avic.h              |  14 +++
 xen/arch/x86/hvm/svm/svm.c               |  20 ++++
 xen/arch/x86/include/asm/hvm/svm-types.h |   8 ++
 5 files changed, 179 insertions(+)
 create mode 100644 xen/arch/x86/hvm/svm/avic.c
 create mode 100644 xen/arch/x86/hvm/svm/avic.h

diff --git a/xen/arch/x86/hvm/svm/Makefile b/xen/arch/x86/hvm/svm/Makefile
index 8a072cafd572..7dd16e32a77d 100644
--- a/xen/arch/x86/hvm/svm/Makefile
+++ b/xen/arch/x86/hvm/svm/Makefile
@@ -1,4 +1,5 @@
 obj-y += asid.o
+obj-y += avic.o
 obj-y += emulate.o
 obj-bin-y += entry.o
 obj-y += intr.o
diff --git a/xen/arch/x86/hvm/svm/avic.c b/xen/arch/x86/hvm/svm/avic.c
new file mode 100644
index 000000000000..2c0e113ae34e
--- /dev/null
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AMD Advanced Virtual Interrupt Controller (AVIC)
+ */
+
+#include <asm/hvm/emulate.h>
+#include <asm/msr.h>
+#include <asm/p2m.h>
+#include <xen/param.h>
+
+#include "avic.h"
+
+bool __read_mostly svm_avic_enable;
+
+static const char __section(".bss.page_aligned.const") __aligned(PAGE_SIZE)
+    avic_apic_access_page[PAGE_SIZE];
+
+static int cf_check avic_parse_cmdline(const char *s)
+{
+    int rc;
+
+    rc = parse_bool(s, NULL);
+    if ( rc != -1 )
+    {
+        svm_avic_enable = !!rc;
+    }
+    else if ( *s == '\0' )
+    {
+        svm_avic_enable = true;
+    }
+    else
+    {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+custom_param("svm_avic", avic_parse_cmdline);
+
+/*
+ * Enable guest accesses to APIC_DEFAULT_PHYS_BASE.
+ *
+ * AVIC walks the nested page table to check access permissions, but
+ * ignores the SPA from the leaf entry and instead uses the address in
+ * VMCB.avic_backing_page.
+ *
+ * Install a mapping so APIC accesses don't trap to Xen while xAPIC is
+ * accelerated.
+ */
+static int avic_set_mmio_p2m_entry(struct domain *d)
+{
+    gfn_t gfn = _gfn(paddr_to_pfn(APIC_DEFAULT_PHYS_BASE));
+    mfn_t mfn = _mfn(virt_to_mfn(avic_apic_access_page));
+
+    return map_mmio_regions(d, gfn, 1, mfn);
+}
+
+static int avic_clear_mmio_p2m_entry(struct domain *d)
+{
+    gfn_t gfn = _gfn(paddr_to_pfn(APIC_DEFAULT_PHYS_BASE));
+    mfn_t mfn = _mfn(virt_to_mfn(avic_apic_access_page));
+
+    return unmap_mmio_regions(d, gfn, 1, mfn);
+}
+
+int svm_avic_domain_initialise(struct domain *d)
+{
+    struct svm_domain *sd = &d->arch.hvm.svm;
+    struct page_info *pg;
+    mfn_t mfn;
+
+    if ( !svm_avic_enable || !has_vlapic(d) )
+        return 0;
+
+    /* AVIC logical APIC ID table */
+    pg = alloc_domheap_page(d, MEMF_no_refcount);
+    if ( !pg )
+        return -ENOMEM;
+
+    mfn = page_to_mfn(pg);
+    clear_domain_page(mfn);
+
+    sd->avic_logical_id_table_mfn = mfn;
+    sd->avic_logical_id_table = map_domain_page_global(mfn);
+
+    /* AVIC physical APIC ID table */
+    pg = alloc_domheap_page(d, MEMF_no_refcount);
+    if ( !pg )
+        return -ENOMEM;
+
+    mfn = page_to_mfn(pg);
+    clear_domain_page(mfn);
+
+    sd->avic_physical_id_table_mfn = mfn;
+    sd->avic_physical_id_table = map_domain_page_global(mfn);
+
+    return avic_set_mmio_p2m_entry(d);
+}
+
+void svm_avic_domain_relinquish_resources(struct domain *d)
+{
+    struct svm_domain *sd = &d->arch.hvm.svm;
+    mfn_t mfn;
+
+    (void)avic_clear_mmio_p2m_entry(d);
+
+    mfn = sd->avic_physical_id_table_mfn;
+    if ( !mfn_eq(mfn, _mfn(0)) )
+    {
+        unmap_domain_page_global(sd->avic_physical_id_table);
+        sd->avic_physical_id_table = NULL;
+
+        free_domheap_page(mfn_to_page(mfn));
+        sd->avic_physical_id_table_mfn = _mfn(0);
+    }
+
+    mfn = sd->avic_logical_id_table_mfn;
+    if ( !mfn_eq(mfn, _mfn(0)) )
+    {
+        unmap_domain_page_global(sd->avic_logical_id_table);
+        sd->avic_logical_id_table = NULL;
+
+        free_domheap_page(mfn_to_page(mfn));
+        sd->avic_logical_id_table_mfn = _mfn(0);
+    }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/x86/hvm/svm/avic.h b/xen/arch/x86/hvm/svm/avic.h
new file mode 100644
index 000000000000..3da62f59b0cf
--- /dev/null
+++ b/xen/arch/x86/hvm/svm/avic.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AMD Advanced Virtual Interrupt Controller (AVIC)
+ */
+
+#ifndef __SVM_AVIC_H__
+#define __SVM_AVIC_H__
+
+extern bool svm_avic_enable;
+
+int svm_avic_domain_initialise(struct domain *d);
+void svm_avic_domain_relinquish_resources(struct domain *d);
+
+#endif /* __SVM_AVIC_H__ */
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index db81dad4b681..8b7bfed0049f 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -40,6 +40,7 @@
 
 #include <public/sched.h>
 
+#include "avic.h"
 #include "nestedhvm.h"
 #include "svm.h"
 #include "vmcb.h"
@@ -1084,6 +1085,11 @@ static int cf_check svm_domain_initialise(struct domain 
*d)
         .to   = svm_ctxt_switch_to,
         .tail = svm_do_resume,
     };
+    int rc;
+
+    rc = svm_avic_domain_initialise(d);
+    if ( rc )
+        return rc;
 
     d->arch.ctxt_switch = &csw;
 
@@ -1095,6 +1101,11 @@ static int cf_check svm_domain_initialise(struct domain 
*d)
     return 0;
 }
 
+static void cf_check svm_domain_relinquish_resources(struct domain *d)
+{
+    svm_avic_domain_relinquish_resources(d);
+}
+
 static int cf_check svm_vcpu_initialise(struct vcpu *v)
 {
     int rc;
@@ -2384,6 +2395,7 @@ static struct hvm_function_table __initdata_cf_clobber 
svm_function_table = {
     .cpu_up               = svm_cpu_up,
     .cpu_down             = svm_cpu_down,
     .domain_initialise    = svm_domain_initialise,
+    .domain_relinquish_resources = svm_domain_relinquish_resources,
     .vcpu_initialise      = svm_vcpu_initialise,
     .vcpu_destroy         = svm_vcpu_destroy,
     .save_cpu_ctxt        = svm_save_vmcb_ctxt,
@@ -2464,6 +2476,12 @@ static void __init print_svm_features(void)
         printk(" - none\n");
 }
 
+static void __init svm_avic_start(void)
+{
+    if ( !cpu_has_svm_avic || pv_shim )
+        svm_avic_enable = false;
+}
+
 const struct hvm_function_table * __init start_svm(void)
 {
     svm_host_osvw_reset();
@@ -2487,6 +2505,8 @@ const struct hvm_function_table * __init start_svm(void)
     if ( cpu_has_tsc_ratio )
         svm_function_table.tsc_scaling.ratio_frac_bits = 32;
 
+    svm_avic_start();
+
     svm_function_table.caps.hap = cpu_has_svm_npt;
     svm_function_table.caps.hap_superpage_2mb = true;
     svm_function_table.caps.hap_superpage_1gb = cpu_has_page1gb;
diff --git a/xen/arch/x86/include/asm/hvm/svm-types.h 
b/xen/arch/x86/include/asm/hvm/svm-types.h
index 71427b3c11d1..30bdaf27a856 100644
--- a/xen/arch/x86/include/asm/hvm/svm-types.h
+++ b/xen/arch/x86/include/asm/hvm/svm-types.h
@@ -15,6 +15,14 @@ struct svm_domain {
             uint64_t status;
         };
     } osvw;
+
+    /*
+     * Domain AVIC state.
+     */
+    mfn_t avic_logical_id_table_mfn;
+    uint32_t *avic_logical_id_table;
+    mfn_t avic_physical_id_table_mfn;
+    uint64_t *avic_physical_id_table;
 };
 
 struct svm_vcpu {
-- 
2.55.0




 


Rackspace

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