All of lore.kernel.org
 help / color / mirror / Atom feed
From: Janakarajan Natarajan <Janakarajan.Natarajan@amd.com>
To: xen-devel@lists.xen.org
Cc: Jun Nakajima <jun.nakajima@intel.com>,
	Kevin Tian <kevin.tian@intel.com>,
	Stefano Stabellini <sstabellini@kernel.org>,
	Wei Liu <wei.liu2@citrix.com>,
	Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>,
	Janakarajan Natarajan <Janakarajan.Natarajan@amd.com>,
	George Dunlap <George.Dunlap@eu.citrix.com>,
	Andrew Cooper <andrew.cooper3@citrix.com>,
	Ian Jackson <ian.jackson@eu.citrix.com>, Tim Deegan <tim@xen.org>,
	Julien Grall <julien.grall@arm.com>,
	Jan Beulich <jbeulich@suse.com>,
	Boris Ostrovsky <boris.ostrovsky@oracle.com>
Subject: [PATCH v2 04/10] x86/HVM/SVM: Add AVIC initialization code
Date: Mon,  7 May 2018 16:07:47 -0500	[thread overview]
Message-ID: <20180507210753.2280-5-Janakarajan.Natarajan@amd.com> (raw)
In-Reply-To: <20180507210753.2280-1-Janakarajan.Natarajan@amd.com>

From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>

Introduce AVIC base initialization code. This includes:
    * Setting up per-VM data structures.
    * Setting up per-vCPU data structure.
    * Initializing AVIC-related VMCB bit fields.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Janakarajan Natarajan <Janakarajan.Natarajan@amd.com>
---
 xen/arch/x86/hvm/svm/Makefile      |   1 +
 xen/arch/x86/hvm/svm/avic.c        | 190 +++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/svm/svm.c         |   8 +-
 xen/arch/x86/hvm/svm/vmcb.c        |   3 +
 xen/arch/x86/hvm/vlapic.c          |   4 +
 xen/include/asm-x86/hvm/svm/avic.h |  39 ++++++++
 xen/include/asm-x86/hvm/svm/svm.h  |   2 +
 xen/include/asm-x86/hvm/svm/vmcb.h |  18 ++++
 8 files changed, 264 insertions(+), 1 deletion(-)
 create mode 100644 xen/arch/x86/hvm/svm/avic.c
 create mode 100644 xen/include/asm-x86/hvm/svm/avic.h

diff --git a/xen/arch/x86/hvm/svm/Makefile b/xen/arch/x86/hvm/svm/Makefile
index 760d2954da..e0e4a59f7d 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 0000000000..d6b8638bab
--- /dev/null
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -0,0 +1,190 @@
+/*
+ * avic.c: implements AMD Advanced Virtual Interrupt Controller (AVIC) support
+ * Copyright (c) 2018, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/domain_page.h>
+#include <xen/sched.h>
+#include <xen/stdbool.h>
+#include <asm/acpi.h>
+#include <asm/apicdef.h>
+#include <asm/atomic.h>
+#include <asm/event.h>
+#include <asm/hvm/emulate.h>
+#include <asm/hvm/nestedhvm.h>
+#include <asm/hvm/support.h>
+#include <asm/hvm/svm/avic.h>
+#include <asm/hvm/vlapic.h>
+#include <asm/p2m.h>
+#include <asm/page.h>
+
+/* Note: Current max index allowed for physical APIC ID table is 255. */
+#define AVIC_PHY_APIC_ID_MAX    GET_xAPIC_ID(APIC_ID_MASK)
+
+/*
+ * Note:
+ * Currently, svm-avic mode is not supported with nested virtualization.
+ * Therefore, it is not yet currently enabled by default. Once the support
+ * is in-place, this should be enabled by default.
+ */
+bool svm_avic = false;
+
+static const char __section(".bss.page_aligned.const") __aligned(PAGE_SIZE)
+    avic_backing_page[PAGE_SIZE];
+
+static struct avic_physical_id_entry*
+avic_get_physical_id_entry(struct svm_domain *d, unsigned int index)
+{
+    if ( !d->avic_physical_id_table )
+        return NULL;
+
+    /*
+    * Note: APIC ID = 0xFF is used for broadcast.
+    *       APIC ID > 0xFF is reserved.
+    */
+    ASSERT(index < AVIC_PHY_APIC_ID_MAX);
+
+    if ( index >= AVIC_PHY_APIC_ID_MAX )
+        return NULL;
+
+    return &d->avic_physical_id_table[index];
+}
+
+int svm_avic_dom_init(struct domain *d)
+{
+    int ret = 0;
+    struct page_info *pg;
+
+    if ( !svm_avic || !has_vlapic(d) )
+        return 0;
+
+    /*
+     * Note:
+     * AVIC hardware walks the nested page table to check permissions,
+     * but does not use the SPA address specified in the leaf page
+     * table entry since it uses  address in the AVIC_BACKING_PAGE pointer
+     * field of the VMCB. Therefore, we set up a dummy page for APIC.
+     */
+    set_mmio_p2m_entry(d, paddr_to_pfn(APIC_DEFAULT_PHYS_BASE),
+                       _mfn(virt_to_mfn(avic_backing_page)), PAGE_ORDER_4K,
+                       p2m_access_rw);
+
+    /* Init AVIC logical APIC ID table */
+    pg = alloc_domheap_page(d, MEMF_no_owner);
+    if ( !pg )
+    {
+        ret = -ENOMEM;
+        goto err_out;
+    }
+    clear_domain_page(page_to_mfn(pg));
+    d->arch.hvm_domain.svm.avic_logical_id_table_pg = pg;
+    d->arch.hvm_domain.svm.avic_logical_id_table = __map_domain_page_global(pg);
+
+    /* Init AVIC physical APIC ID table */
+    pg = alloc_domheap_page(d, MEMF_no_owner);
+    if ( !pg )
+    {
+        ret = -ENOMEM;
+        goto err_out;
+    }
+    clear_domain_page(page_to_mfn(pg));
+    d->arch.hvm_domain.svm.avic_physical_id_table_pg = pg;
+    d->arch.hvm_domain.svm.avic_physical_id_table = __map_domain_page_global(pg);
+
+    return ret;
+ err_out:
+    svm_avic_dom_destroy(d);
+    return ret;
+}
+
+void svm_avic_dom_destroy(struct domain *d)
+{
+    if ( !svm_avic || !has_vlapic(d) )
+        return;
+
+    if ( d->arch.hvm_domain.svm.avic_physical_id_table )
+    {
+        unmap_domain_page_global(d->arch.hvm_domain.svm.avic_physical_id_table);
+        free_domheap_page(d->arch.hvm_domain.svm.avic_physical_id_table_pg);
+        d->arch.hvm_domain.svm.avic_physical_id_table_pg = NULL;
+        d->arch.hvm_domain.svm.avic_physical_id_table = NULL;
+    }
+
+    if ( d->arch.hvm_domain.svm.avic_logical_id_table)
+    {
+        unmap_domain_page_global(d->arch.hvm_domain.svm.avic_logical_id_table);
+        free_domheap_page(d->arch.hvm_domain.svm.avic_logical_id_table_pg);
+        d->arch.hvm_domain.svm.avic_logical_id_table_pg = NULL;
+        d->arch.hvm_domain.svm.avic_logical_id_table = NULL;
+    }
+}
+
+bool svm_avic_vcpu_enabled(const struct vcpu *v)
+{
+    const struct arch_svm_struct *s = &v->arch.hvm_svm;
+    const struct vmcb_struct *vmcb = s->vmcb;
+
+    return vmcb->_vintr.fields.avic_enable;
+}
+
+int svm_avic_init_vmcb(struct vcpu *v)
+{
+    u32 apic_id;
+    struct arch_svm_struct *s = &v->arch.hvm_svm;
+    struct vmcb_struct *vmcb = s->vmcb;
+    struct svm_domain *d = &v->domain->arch.hvm_domain.svm;
+    const struct vlapic *vlapic = vcpu_vlapic(v);
+    struct avic_physical_id_entry *entry;
+
+    if ( !svm_avic || !has_vlapic(v->domain) )
+        return 0;
+
+    if ( !vlapic || !vlapic->regs_page )
+        return -EINVAL;
+
+    apic_id = vlapic_reg_read(vcpu_vlapic(v), APIC_ID);
+    s->avic_last_phy_id = avic_get_physical_id_entry(d, GET_xAPIC_ID(apic_id));
+    if ( !s->avic_last_phy_id )
+        return -EINVAL;
+
+    vmcb->avic_bk_pg_pa = page_to_maddr(vlapic->regs_page);
+    vmcb->avic_logical_id_table_pa = mfn_to_maddr(domain_page_map_to_mfn(d->avic_logical_id_table));
+    vmcb->avic_physical_id_table_pa = mfn_to_maddr(domain_page_map_to_mfn(d->avic_physical_id_table));
+
+    /* Set Physical ID Table Pointer [7:0] to max apic id of the domain */
+    vmcb->avic_physical_id_table_pa |= (v->domain->max_vcpus * 2) & 0xFF;
+
+    entry = s->avic_last_phy_id;
+    entry->bk_pg_ptr_mfn = (vmcb->avic_bk_pg_pa) >> PAGE_SHIFT;
+    entry->is_running = 0;
+    entry->valid = 1;
+
+    vmcb->avic_vapic_bar = APIC_DEFAULT_PHYS_BASE;
+    vmcb->cleanbits.fields.avic = 0;
+
+    vmcb->_vintr.fields.avic_enable = 1;
+
+    return 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/svm.c b/xen/arch/x86/hvm/svm/svm.c
index c7616456dd..c264353e69 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -47,6 +47,7 @@
 #include <asm/hvm/svm/asid.h>
 #include <asm/hvm/svm/svm.h>
 #include <asm/hvm/svm/vmcb.h>
+#include <asm/hvm/svm/avic.h>
 #include <asm/hvm/svm/emulate.h>
 #include <asm/hvm/svm/intr.h>
 #include <asm/hvm/svm/svmdebug.h>
@@ -1244,11 +1245,12 @@ static int svm_domain_initialise(struct domain *d)
 
     d->arch.ctxt_switch = &csw;
 
-    return 0;
+    return svm_avic_dom_init(d);
 }
 
 static void svm_domain_destroy(struct domain *d)
 {
+    svm_avic_dom_destroy(d);
 }
 
 static int svm_vcpu_initialise(struct vcpu *v)
@@ -1713,6 +1715,9 @@ const struct hvm_function_table * __init start_svm(void)
     if ( cpu_has_tsc_ratio )
         svm_function_table.tsc_scaling.ratio_frac_bits = 32;
 
+    if ( !cpu_has_svm_avic )
+        svm_avic = 0;
+
 #define P(p,s) if ( p ) { printk(" - %s\n", s); printed = 1; }
     P(cpu_has_svm_npt, "Nested Page Tables (NPT)");
     P(cpu_has_svm_lbrv, "Last Branch Record (LBR) Virtualisation");
@@ -1724,6 +1729,7 @@ const struct hvm_function_table * __init start_svm(void)
     P(cpu_has_pause_filter, "Pause-Intercept Filter");
     P(cpu_has_pause_thresh, "Pause-Intercept Filter Threshold");
     P(cpu_has_tsc_ratio, "TSC Rate MSR");
+    P(cpu_has_svm_avic, svm_avic ? "AVIC (enabled)" : "AVIC (disabled)");
 #undef P
 
     if ( !printed )
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index ae60d8dc1c..7ade023cfe 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -27,6 +27,7 @@
 #include <asm/msr-index.h>
 #include <asm/p2m.h>
 #include <asm/hvm/support.h>
+#include <asm/hvm/svm/avic.h>
 #include <asm/hvm/svm/svm.h>
 #include <asm/hvm/svm/svmdebug.h>
 
@@ -215,6 +216,8 @@ static int construct_vmcb(struct vcpu *v)
             vmcb->_pause_filter_thresh = SVM_PAUSETHRESH_INIT;
     }
 
+    svm_avic_init_vmcb(v);
+
     vmcb->cleanbits.bytes = 0;
 
     return 0;
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index 60d1f7e748..eb71cc21ed 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -1597,6 +1597,10 @@ int vlapic_init(struct vcpu *v)
 
     if (vlapic->regs_page == NULL)
     {
+        /*
+         * SVM AVIC depends on the vlapic->regs_page being a full
+         * page allocation as it is also used for vAPIC backing page.
+         */
         vlapic->regs_page = alloc_domheap_page(v->domain, MEMF_no_owner);
         if ( vlapic->regs_page == NULL )
         {
diff --git a/xen/include/asm-x86/hvm/svm/avic.h b/xen/include/asm-x86/hvm/svm/avic.h
new file mode 100644
index 0000000000..0c01a40ff5
--- /dev/null
+++ b/xen/include/asm-x86/hvm/svm/avic.h
@@ -0,0 +1,39 @@
+#ifndef _SVM_AVIC_H_
+#define _SVM_AVIC_H_
+
+#include <xen/compiler.h>
+
+enum avic_incmp_ipi_err_code {
+    AVIC_INCMP_IPI_ERR_INVALID_INT_TYPE,
+    AVIC_INCMP_IPI_ERR_TARGET_NOT_RUN,
+    AVIC_INCMP_IPI_ERR_INV_TARGET,
+    AVIC_INCMP_IPI_ERR_INV_BK_PAGE,
+};
+
+typedef union avic_logical_id_entry {
+    u32 raw;
+    struct __packed {
+        u32 guest_phy_apic_id : 8;
+        u32 res               : 23;
+        u32 valid             : 1;
+    };
+} avic_logical_id_entry_t;
+
+struct __packed avic_physical_id_entry {
+        u64 host_phy_apic_id  : 8;
+        u64 res1              : 4;
+        u64 bk_pg_ptr_mfn     : 40;
+        u64 res2              : 10;
+        u64 is_running        : 1;
+        u64 valid             : 1;
+};
+
+extern bool svm_avic;
+
+int svm_avic_dom_init(struct domain *d);
+void svm_avic_dom_destroy(struct domain *d);
+
+bool svm_avic_vcpu_enabled(const struct vcpu *v);
+int svm_avic_init_vmcb(struct vcpu *v);
+
+#endif /* _SVM_AVIC_H_ */
diff --git a/xen/include/asm-x86/hvm/svm/svm.h b/xen/include/asm-x86/hvm/svm/svm.h
index 4e5e142910..983750fee9 100644
--- a/xen/include/asm-x86/hvm/svm/svm.h
+++ b/xen/include/asm-x86/hvm/svm/svm.h
@@ -65,6 +65,7 @@ extern u32 svm_feature_flags;
 #define SVM_FEATURE_DECODEASSISTS  7 /* Decode assists support */
 #define SVM_FEATURE_PAUSEFILTER   10 /* Pause intercept filter support */
 #define SVM_FEATURE_PAUSETHRESH   12 /* Pause intercept filter support */
+#define SVM_FEATURE_AVIC          13 /* AVIC Support */
 #define SVM_FEATURE_VLOADSAVE     15 /* virtual vmload/vmsave */
 #define SVM_FEATURE_VGIF          16 /* Virtual GIF */
 
@@ -79,6 +80,7 @@ extern u32 svm_feature_flags;
 #define cpu_has_pause_filter  cpu_has_svm_feature(SVM_FEATURE_PAUSEFILTER)
 #define cpu_has_pause_thresh  cpu_has_svm_feature(SVM_FEATURE_PAUSETHRESH)
 #define cpu_has_tsc_ratio     cpu_has_svm_feature(SVM_FEATURE_TSCRATEMSR)
+#define cpu_has_svm_avic      cpu_has_svm_feature(SVM_FEATURE_AVIC)
 #define cpu_has_svm_vloadsave cpu_has_svm_feature(SVM_FEATURE_VLOADSAVE)
 
 #define SVM_PAUSEFILTER_INIT    4000
diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h
index 591d98fc8c..e625884c8b 100644
--- a/xen/include/asm-x86/hvm/svm/vmcb.h
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h
@@ -21,6 +21,7 @@
 
 #include <xen/types.h>
 #include <asm/hvm/emulate.h>
+#include <asm/hvm/svm/avic.h>
 
 
 /* general 1 intercepts */
@@ -500,6 +501,21 @@ struct vmcb_struct {
 };
 
 struct svm_domain {
+    /*
+     * This per-domain table is used by the hardware to locate
+     * the vAPIC backing page to be used to deliver interrupts
+     * based on the guest physical APIC ID.
+     */
+    struct avic_physical_id_entry *avic_physical_id_table;
+    struct page_info *avic_physical_id_table_pg;
+
+    /*
+     * This per-domain table is used by the hardware to map
+     * logically addressed interrupt requests (w/ guest logical APIC id)
+     * to the guest physical APIC ID.
+     */
+    avic_logical_id_entry_t *avic_logical_id_table;
+    struct page_info *avic_logical_id_table_pg;
 };
 
 struct arch_svm_struct {
@@ -533,6 +549,8 @@ struct arch_svm_struct {
         u64 length;
         u64 status;
     } osvw;
+
+    struct avic_physical_id_entry *avic_last_phy_id;
 };
 
 struct vmcb_struct *alloc_vmcb(void);
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

  parent reply	other threads:[~2018-05-07 21:07 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-07 21:07 [PATCH v2 00/10] Introduce AMD SVM AVIC Janakarajan Natarajan
2018-05-07 21:07 ` [PATCH v2 01/10] x86/SVM: Modify VMCB fields to add AVIC support Janakarajan Natarajan
2018-05-07 21:07 ` [PATCH v2 02/10] x86/HVM: Rename vlapic_read_aligned() to vlapic_reg_read() Janakarajan Natarajan
2018-05-08 10:12   ` Wei Liu
2018-05-16 14:36   ` Jan Beulich
2018-05-07 21:07 ` [PATCH v2 03/10] x86/HVM: Make vlapic_reg_read/write() non-static Janakarajan Natarajan
2018-05-16 14:38   ` Jan Beulich
2018-05-16 14:44   ` Jan Beulich
2018-05-07 21:07 ` Janakarajan Natarajan [this message]
2018-05-16 15:29   ` [PATCH v2 04/10] x86/HVM/SVM: Add AVIC initialization code Jan Beulich
2018-05-16 15:41     ` Andrew Cooper
2018-05-21 18:41     ` Natarajan, Janakarajan
2018-05-22  9:19       ` Jan Beulich
2018-05-07 21:07 ` [PATCH v2 05/10] x86/SVM: Add AVIC vmexit handlers Janakarajan Natarajan
2018-05-16 15:56   ` Jan Beulich
2018-05-29 21:49     ` Natarajan, Janakarajan
2018-05-29 23:33       ` Andrew Cooper
2018-05-30  7:24         ` Jan Beulich
2018-05-30 18:30           ` Natarajan, Janakarajan
2018-05-30 23:23             ` Andrew Cooper
2018-05-07 21:07 ` [PATCH v2 06/10] x86/SVM: Add vcpu scheduling support for AVIC Janakarajan Natarajan
2018-05-17 14:45   ` Jan Beulich
2018-05-07 21:07 ` [PATCH v2 07/10] x86/SVM: Add interrupt management code via AVIC Janakarajan Natarajan
2018-05-17 14:50   ` Jan Beulich
2018-05-30 19:47     ` Natarajan, Janakarajan
2018-05-07 21:07 ` [PATCH v2 08/10] x86/HVM: Hook up miscellaneous AVIC functions Janakarajan Natarajan
2018-05-07 21:07 ` [PATCH v2 09/10] x86/SVM: Introduce svm command line option Janakarajan Natarajan
2018-05-17 14:54   ` Jan Beulich
2018-05-07 21:07 ` [PATCH v2 10/10] x86/SVM: Append AMD AVIC related data to IRQ keyhandler 'i' Janakarajan Natarajan
2018-05-17 14:56   ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180507210753.2280-5-Janakarajan.Natarajan@amd.com \
    --to=janakarajan.natarajan@amd.com \
    --cc=George.Dunlap@eu.citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=julien.grall@arm.com \
    --cc=jun.nakajima@intel.com \
    --cc=kevin.tian@intel.com \
    --cc=sstabellini@kernel.org \
    --cc=suravee.suthikulpanit@amd.com \
    --cc=tim@xen.org \
    --cc=wei.liu2@citrix.com \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.