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

[PATCH v1 07/28] x86/hvm: avic: add VMCB state initialization


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: dmukhin@xxxxxxxx
  • Date: Wed, 4 Nov 2026 17:33:24 -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=UnFVM1D32Q8PVzU9oZlOxLlg1sYnLTK8jp9jrh0Jn4Y=; b=WT9gSu6eRmP5lypwNONvIoGevIyWoab+h24iU72lA3lA8b/lwQTaWkflWouqTFY/XosVSJeMJGheiVPPpp8UdjsbNONX8j/kIpWBhev3KEEIIP5Zw1BiFdozvQ6a3R28wsASswXMaUJZ78N6ZkoSRaDVT7d/iEjELRlWwJn69qFNnrnhhSLpMvdwj2mzunBaexLNLEFQy8IfsgXiYogyASJgXPLs9IhegmFPOg66l8liRkw9DeomgvO0b0kIEhuh5mhmAGK6zWuydFKbqhVLjsKGZlREJbOLqf8VRx8GPnDKJ24qbuwttvhkF7l12FRRMwALAdM4p27jdNag3H+xvA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Qk+IM3DLHYGiA00opPW3/OfLKt5XNOS0voGkrnZnDePm1mFUOxtpFZ9utrjp+71YEe1RfPSk6Wyb7jQSDc9Cm9iRfWivCxF2xUhNY53mkp6pmGJN2JjwpGRqWRcqXfR6bZjH7Vg2L7PdTiiWtuHzdXGDI60Ng12ZsTDVnjWuYYqfZf8TS7a4sTFWIW55RJjeyAmTI0y6+HCj7MGbFefVPaJIViu2XKFFVnWW8YEFtpwTTQBq3U3+SkYCXJm3f6zXBigiQ/SpJGrT7gHge+PKJ6U/b6XcT6+HxKfUP6JGKJc8Og0LOaWOPsYcHOCYpu0AdZERi9lJ0GVvlXe+GCKgpQ==
  • 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:46 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Pser-m365-app: SER-APP

From: Denis Mukhin <dmukhin@xxxxxxxx>

Update SVM VMCB with AVIC-related data types as per [1].

Install AVIC backing page and logical/physical APIC ID tables mappings
into VMCB.

Set VMCB 'avic_enable' bit to 1 in case of successful initialization.

[1] AMD APM Volumes 1-5 "15.29 Advanced Virtual Interrupt Controller".
Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
 xen/arch/x86/hvm/svm/avic.c | 110 ++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/svm/avic.h |   3 +
 xen/arch/x86/hvm/svm/vmcb.c |   7 +++
 xen/arch/x86/hvm/svm/vmcb.h |  19 +++++--
 4 files changed, 135 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/hvm/svm/avic.c b/xen/arch/x86/hvm/svm/avic.c
index 2c0e113ae34e..bc98661a7057 100644
--- a/xen/arch/x86/hvm/svm/avic.c
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -9,6 +9,16 @@
 #include <xen/param.h>
 
 #include "avic.h"
+#include "vmcb.h"
+
+#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK        GENMASK_ULL(51, 12U)
+#define AVIC_PHYSICAL_ID_TABLE_SIZE_MASK                (0xFFULL)
+
+/*
+ * For AVIC, the max index allowed for physical APIC ID table is 0xfe (254), as
+ * 0xff is a broadcast to all CPUs, i.e. can't be targeted individually.
+ */
+#define AVIC_MAX_PHYSICAL_ID                            (0xFEU)
 
 bool __read_mostly svm_avic_enable;
 
@@ -125,6 +135,106 @@ void svm_avic_domain_relinquish_resources(struct domain 
*d)
     }
 }
 
+static bool avic_vcpu_supported(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+    unsigned int id;
+
+    if ( !svm_avic_enable || !has_vlapic(d) )
+        return false;
+
+    if ( d->max_vcpus * 2 >= AVIC_PHYSICAL_ID_TABLE_SIZE_MASK )
+    {
+        gprintk(XENLOG_WARNING,
+                "%pv: AVIC: unsupported domain max_vcpus %u\n",
+                v, d->max_vcpus);
+        return false;
+    }
+
+    id = GET_xAPIC_ID(vlapic_reg_read(v, APIC_ID));
+    if ( id > AVIC_MAX_PHYSICAL_ID )
+    {
+        gprintk(XENLOG_WARNING,
+                "%pv: AVIC: unsupported APIC ID %u\n",
+                v, id);
+        return false;
+    }
+
+    return true;
+}
+
+static void avic_vcpu_enable(const struct vcpu *v, bool enable)
+{
+    const struct svm_vcpu *sv = &v->arch.hvm.svm;
+    struct vmcb_struct *vmcb = sv->vmcb;
+
+    vmcb->_vintr.fields.x2avic_enable = 0;
+    vmcb->_vintr.fields.avic_enable = enable;
+    vmcb->cleanbits.avic = 0;
+
+    printk(XENLOG_INFO
+           "%pv: AVIC: %s: apic_id=%#x avic_physical_id=%#"PRIx64" 
max_vcpus=%u\n",
+           v,
+           enable ? "enable" : "disable",
+           GET_xAPIC_ID(vlapic_reg_read(v, APIC_ID)),
+           sv->avic_physical_id ? ACCESS_ONCE(*sv->avic_physical_id) :
+                                  0xDEADDEADUL,
+           v->domain->max_vcpus);
+}
+
+int svm_avic_vmcb_create(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+    struct svm_domain *sd = &d->arch.hvm.svm;
+    struct svm_vcpu *sv = &v->arch.hvm.svm;
+    struct vmcb_struct *vmcb = sv->vmcb;
+    const struct vlapic *vlapic = vcpu_vlapic(v);
+    mfn_t mfn;
+    uint64_t entry;
+    unsigned int id;
+
+    if ( !avic_vcpu_supported(v) )
+        return 0;
+
+    vmcb->avic_vapic_bar = APIC_DEFAULT_PHYS_BASE;
+    vmcb->avic_backing_page = page_to_maddr(vlapic->regs_page);
+
+    mfn = domain_page_map_to_mfn(sd->avic_logical_id_table);
+    vmcb->avic_logical_id_table = mfn_to_maddr(mfn);
+
+    mfn = domain_page_map_to_mfn(sd->avic_physical_id_table);
+    vmcb->avic_physical_id_table = mfn_to_maddr(mfn);
+    vmcb->avic_physical_id_table |= (d->max_vcpus * 2) &
+                                    AVIC_PHYSICAL_ID_TABLE_SIZE_MASK;
+
+    id = GET_xAPIC_ID(vlapic_reg_read(v, APIC_ID));
+
+    sv->avic_physical_id = &sd->avic_physical_id_table[id];
+
+    entry = vmcb->avic_backing_page & AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK;
+    entry |= AVIC_PHYSICAL_ID_ENTRY_VALID_MASK;
+
+    ACCESS_ONCE(*sv->avic_physical_id) = entry;
+
+    avic_vcpu_enable(v, true);
+
+    return 0;
+}
+
+void svm_avic_vmcb_destroy(struct vcpu *v)
+{
+    struct svm_vcpu *sv = &v->arch.hvm.svm;
+    struct vmcb_struct *vmcb = sv->vmcb;
+
+    if ( svm_avic_vcpu_enabled(v) )
+        avic_vcpu_enable(v, false);
+
+    vmcb->avic_physical_id_table = 0;
+    vmcb->avic_logical_id_table = 0;
+    vmcb->avic_backing_page = 0;
+    vmcb->avic_vapic_bar = 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/hvm/svm/avic.h b/xen/arch/x86/hvm/svm/avic.h
index 3da62f59b0cf..1084ae683944 100644
--- a/xen/arch/x86/hvm/svm/avic.h
+++ b/xen/arch/x86/hvm/svm/avic.h
@@ -11,4 +11,7 @@ extern bool svm_avic_enable;
 int svm_avic_domain_initialise(struct domain *d);
 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);
+
 #endif /* __SVM_AVIC_H__ */
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index 3ec5bdddf588..c4282bfd6c6e 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -20,6 +20,7 @@
 #include <asm/p2m.h>
 #include <asm/spec_ctrl.h>
 
+#include "avic.h"
 #include "svm.h"
 #include "vmcb.h"
 
@@ -215,6 +216,10 @@ int svm_create_vmcb(struct vcpu *v)
     if ( rc )
         return rc;
 
+    rc = svm_avic_vmcb_create(v);
+    if ( rc )
+        return rc;
+
     paddr = virt_to_maddr(nv->nv_n1vmcx);
     nv->nv_n1vmcx_pa = paddr;
     svm->vmcb_pa = paddr;
@@ -227,6 +232,8 @@ void svm_destroy_vmcb(struct vcpu *v)
     struct nestedvcpu *nv = &vcpu_nestedhvm(v);
     struct svm_vcpu *svm = &v->arch.hvm.svm;
 
+    svm_avic_vmcb_destroy(v);
+
     if ( nv->nv_n1vmcx != NULL )
         free_vmcb(nv->nv_n1vmcx);
 
diff --git a/xen/arch/x86/hvm/svm/vmcb.h b/xen/arch/x86/hvm/svm/vmcb.h
index 8b351679fac5..1ee5da053a9a 100644
--- a/xen/arch/x86/hvm/svm/vmcb.h
+++ b/xen/arch/x86/hvm/svm/vmcb.h
@@ -346,7 +346,9 @@ typedef union
         u64 intr_masking: 1;
         u64 vgif_enable:  1;
         u64 vnmi_enable:  1;
-        u64 :             5;
+        u64 rsvd2:        3;
+        u64 x2avic_enable:1;
+        u64 avic_enable:  1;  /* bit 31 */
         u64 vector:       8;
         u64 rsvd3:       24;
     } fields;
@@ -362,6 +364,10 @@ typedef union
     uint64_t raw;
 } virt_ext_t;
 
+/*
+ * AMD64 Achitecture's Programmer's Manual, Volume 2
+ * 15.15.3 VMCB Clean Field
+ */
 typedef union
 {
     struct {
@@ -377,7 +383,7 @@ typedef union
         bool seg:1;        /* 8:  cs, ds, es, ss, cpl */
         bool cr2:1;        /* 9:  cr2 */
         bool lbr:1;        /* 10: debugctlmsr, last{branch,int}{to,from}ip */
-        bool :1;
+        bool avic:1;       /* 11: AVIC */
         bool cet:1;        /* 12: msr_s_set, ssp, msr_isst */
     };
     uint32_t raw;
@@ -469,7 +475,8 @@ struct vmcb_struct {
         };
         uint64_t _np_ctrl;
     };
-    uint64_t res08[2];
+    uint64_t avic_vapic_bar;    /* offset 0x98 */
+    uint64_t res08;             /* offset 0xA0 */
     intinfo_t event_inj;        /* offset 0xA8 */
     uint64_t _h_cr3;            /* offset 0xB0 - cleanbit 4 */
     virt_ext_t virt_ext;        /* offset 0xB8 */
@@ -478,7 +485,11 @@ struct vmcb_struct {
     uint64_t nextrip;           /* offset 0xC8 */
     uint8_t  guest_ins_len;     /* offset 0xD0 */
     uint8_t  guest_ins[15];     /* offset 0xD1 */
-    uint64_t res10a[8];         /* offset 0xE0 */
+    uint64_t avic_backing_page;      /* offset 0xE0 */
+    uint64_t res09a;                 /* offset 0xE8 */
+    uint64_t avic_logical_id_table;  /* offset 0xF0 */
+    uint64_t avic_physical_id_table; /* offset 0xF8 */
+    uint64_t res10a[4];         /* offset 0x100 pad to save area */
     uint16_t bus_lock_count;    /* offset 0x120 */
     uint16_t res10b[3];         /* offset 0x122 */
     uint64_t res10c[91];        /* offset 0x128 pad to save area */
-- 
2.55.0




 


Rackspace

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