All of lore.kernel.org
 help / color / mirror / Atom feed
From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
To: xen-devel@lists.xen.org
Cc: andrew.cooper3@citrix.com,
	Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>,
	jbeulich@suse.com, sherry.hurwitz@amd.com
Subject: [RFC PATCH 5/9] x86/HVM/SVM: Add AVIC initialization code
Date: Mon, 19 Sep 2016 00:52:44 -0500	[thread overview]
Message-ID: <1474264368-4104-6-git-send-email-suravee.suthikulpanit@amd.com> (raw)
In-Reply-To: <1474264368-4104-1-git-send-email-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.

This patch also introduces a new Xen parameter (svm-avic),
which can be used to enable/disable AVIC support.
Currently, this svm-avic is disabled by default.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
---
 xen/arch/x86/hvm/svm/Makefile      |   1 +
 xen/arch/x86/hvm/svm/avic.c        | 217 +++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/svm/svm.c         |  17 ++-
 xen/arch/x86/hvm/svm/vmcb.c        |   3 +
 xen/include/asm-x86/hvm/svm/avic.h |  40 +++++++
 xen/include/asm-x86/hvm/svm/svm.h  |   2 +
 xen/include/asm-x86/hvm/svm/vmcb.h |  10 ++
 7 files changed, 289 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 760d295..e0e4a59 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 0000000..70bac69
--- /dev/null
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -0,0 +1,217 @@
+#include <xen/domain_page.h>
+#include <xen/sched.h>
+#include <xen/stdbool.h>
+#include <asm/acpi.h>
+#include <asm/apicdef.h>
+#include <asm/event.h>
+#include <asm/p2m.h>
+#include <asm/page.h>
+#include <asm/hvm/nestedhvm.h>
+#include <asm/hvm/svm/avic.h>
+#include <asm/hvm/vlapic.h>
+#include <asm/hvm/emulate.h>
+#include <asm/hvm/support.h>
+
+/* NOTE: Current max index allowed for physical APIC ID table is 255 */
+#define AVIC_PHY_APIC_ID_MAX    0xFF
+
+#define AVIC_DOORBELL           0xc001011b
+#define AVIC_HPA_MASK           ~((0xFFFULL << 52) || 0xFFF)
+#define AVIC_APIC_BAR_MASK      0xFFFFFFFFFF000ULL
+
+bool_t svm_avic = 0;
+boolean_param("svm-avic", svm_avic);
+
+static struct svm_avic_phy_ait_entry *
+avic_get_phy_ait_entry(struct vcpu *v, int index)
+{
+    struct svm_avic_phy_ait_entry *avic_phy_ait;
+    struct svm_domain *d = &v->domain->arch.hvm_domain.svm;
+
+    if ( !d->avic_phy_ait_mfn )
+        return NULL;
+
+    /**
+    * Note: APIC ID = 0xff is used for broadcast.
+    *       APIC ID > 0xff is reserved.
+    */
+    if ( index >= 0xff )
+        return NULL;
+
+    avic_phy_ait = mfn_to_virt(d->avic_phy_ait_mfn);
+
+    return &avic_phy_ait[index];
+}
+
+/***************************************************************
+ * AVIC APIs
+ */
+int svm_avic_dom_init(struct domain *d)
+{
+    int ret = 0;
+    struct page_info *pg;
+    unsigned long mfn;
+
+    if ( !svm_avic )
+        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 here _mfn(0).
+     */
+    if ( !d->arch.hvm_domain.svm.avic_access_page_done )
+    {
+        set_mmio_p2m_entry(d, paddr_to_pfn(APIC_DEFAULT_PHYS_BASE),
+                           _mfn(0), PAGE_ORDER_4K,
+                           p2m_get_hostp2m(d)->default_access);
+        d->arch.hvm_domain.svm.avic_access_page_done = true;
+    }
+
+    /* Init AVIC log APIC ID table */
+    pg = alloc_domheap_page(d, MEMF_no_owner);
+    if ( !pg )
+    {
+        dprintk(XENLOG_ERR, "alloc AVIC logical APIC ID table error: %d\n",
+                d->domain_id);
+        ret = -ENOMEM;
+        goto err_out;
+    }
+    mfn = page_to_mfn(pg);
+    clear_domain_page(_mfn(mfn));
+    d->arch.hvm_domain.svm.avic_log_ait_mfn = mfn;
+
+    /* Init AVIC phy APIC ID table */
+    pg = alloc_domheap_page(d, MEMF_no_owner);
+    if ( !pg )
+    {
+        dprintk(XENLOG_ERR, "alloc AVIC physical APIC ID table error: %d\n",
+                d->domain_id);
+        ret = -ENOMEM;
+        goto err_out;
+    }
+    mfn = page_to_mfn(pg);
+    clear_domain_page(_mfn(mfn));
+    d->arch.hvm_domain.svm.avic_phy_ait_mfn = mfn;
+
+    return ret;
+err_out:
+    svm_avic_dom_destroy(d);
+    return ret;
+}
+
+void svm_avic_dom_destroy(struct domain *d)
+{
+    if ( !svm_avic )
+        return;
+
+    if ( d->arch.hvm_domain.svm.avic_phy_ait_mfn )
+    {
+        free_domheap_page(mfn_to_page(d->arch.hvm_domain.svm.avic_phy_ait_mfn));
+        d->arch.hvm_domain.svm.avic_phy_ait_mfn = 0;
+    }
+
+    if ( d->arch.hvm_domain.svm.avic_log_ait_mfn )
+    {
+        free_domheap_page(mfn_to_page(d->arch.hvm_domain.svm.avic_log_ait_mfn));
+        d->arch.hvm_domain.svm.avic_log_ait_mfn = 0;
+    }
+}
+
+/**
+ * Note: At this point, vlapic->regs_page is already initialized.
+ */
+int svm_avic_init_vcpu(struct vcpu *v)
+{
+    struct vlapic *vlapic = vcpu_vlapic(v);
+    struct arch_svm_struct *s = &v->arch.hvm_svm;
+
+    if ( svm_avic )
+        s->avic_bk_pg = vlapic->regs_page;
+    return 0;
+}
+
+void svm_avic_destroy_vcpu(struct vcpu *v)
+{
+    struct arch_svm_struct *s = &v->arch.hvm_svm;
+
+    if ( svm_avic && s->avic_bk_pg )
+        s->avic_bk_pg = NULL;
+}
+
+bool_t svm_avic_vcpu_enabled(struct vcpu *v)
+{
+    struct arch_svm_struct *s = &v->arch.hvm_svm;
+    struct vmcb_struct *vmcb = s->vmcb;
+
+    return ( svm_avic && vmcb->_vintr.fields.avic_enable);
+}
+
+static inline u32 *
+avic_get_bk_page_entry(struct vcpu *v, u32 offset)
+{
+    struct arch_svm_struct *s = &v->arch.hvm_svm;
+    struct page_info *pg = s->avic_bk_pg;
+    char *tmp;
+
+    if ( !pg )
+        return NULL;
+
+    tmp = (char *) page_to_virt(pg);
+    return (u32*)(tmp+offset);
+}
+
+void svm_avic_update_vapic_bar(struct vcpu *v, uint64_t data)
+{
+    struct arch_svm_struct *s = &v->arch.hvm_svm;
+
+    s->vmcb->avic_vapic_bar = data & AVIC_APIC_BAR_MASK;
+    s->vmcb->cleanbits.fields.avic = 0;
+}
+
+int svm_avic_init_vmcb(struct vcpu *v)
+{
+    paddr_t ma;
+    u32 apic_id_reg;
+    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;
+    struct svm_avic_phy_ait_entry entry;
+
+    if ( !svm_avic )
+        return 0;
+
+    vmcb->avic_bk_pg_pa = page_to_maddr(s->avic_bk_pg) & AVIC_HPA_MASK;
+    ma = d->avic_log_ait_mfn;
+    vmcb->avic_log_apic_id = (ma << PAGE_SHIFT) & AVIC_HPA_MASK;
+    ma = d->avic_phy_ait_mfn;
+    vmcb->avic_phy_apic_id = (ma << PAGE_SHIFT) & AVIC_HPA_MASK;
+    vmcb->avic_phy_apic_id |= AVIC_PHY_APIC_ID_MAX;
+
+    dprintk(XENLOG_DEBUG, "SVM: %s: bpa=%#llx, lpa=%#llx, ppa=%#llx\n",
+           __func__, (unsigned long long)vmcb->avic_bk_pg_pa,
+           (unsigned long long) vmcb->avic_log_apic_id,
+           (unsigned long long) vmcb->avic_phy_apic_id);
+
+
+    apic_id_reg = *avic_get_bk_page_entry(v, APIC_ID);
+    s->avic_phy_id_cache = avic_get_phy_ait_entry(v, apic_id_reg >> 24);
+    if ( !s->avic_phy_id_cache )
+        return -EINVAL;
+
+    entry = *(s->avic_phy_id_cache);
+    smp_rmb();
+    entry.bk_pg_ptr = (vmcb->avic_bk_pg_pa >> 12) & 0xffffffffff;
+    entry.is_running= 0;
+    entry.valid = 1;
+    *(s->avic_phy_id_cache) = entry;
+    smp_wmb();
+
+    svm_avic_update_vapic_bar(v, APIC_DEFAULT_PHYS_BASE);
+
+    vmcb->_vintr.fields.avic_enable = 1;
+
+    return 0;
+}
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 679e615..bcb7df4 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -48,6 +48,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>
@@ -1164,11 +1165,12 @@ void svm_host_osvw_init()
 
 static int svm_domain_initialise(struct domain *d)
 {
-    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)
@@ -1181,6 +1183,13 @@ static int svm_vcpu_initialise(struct vcpu *v)
 
     v->arch.hvm_svm.launch_core = -1;
 
+    if ( (rc = svm_avic_init_vcpu(v)) != 0 )
+    {
+        dprintk(XENLOG_WARNING,
+                "Failed to initiazlize AVIC vcpu.\n");
+        return rc;
+    }
+
     if ( (rc = svm_create_vmcb(v)) != 0 )
     {
         dprintk(XENLOG_WARNING,
@@ -1200,6 +1209,7 @@ static int svm_vcpu_initialise(struct vcpu *v)
 
 static void svm_vcpu_destroy(struct vcpu *v)
 {
+    svm_avic_destroy_vcpu(v);
     vpmu_destroy(v);
     svm_destroy_vmcb(v);
     passive_domain_destroy(v);
@@ -1464,6 +1474,7 @@ const struct hvm_function_table * __init start_svm(void)
     P(cpu_has_svm_decode, "DecodeAssists");
     P(cpu_has_pause_filter, "Pause-Intercept Filter");
     P(cpu_has_tsc_ratio, "TSC Rate MSR");
+    P(cpu_has_svm_avic, "AVIC");
 #undef P
 
     if ( !printed )
@@ -1809,6 +1820,10 @@ static int svm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
 
     switch ( msr )
     {
+    case MSR_IA32_APICBASE:
+        if ( svm_avic_vcpu_enabled(v) )
+            svm_avic_update_vapic_bar(v, msr_content);
+        break;
     case MSR_IA32_SYSENTER_CS:
     case MSR_IA32_SYSENTER_ESP:
     case MSR_IA32_SYSENTER_EIP:
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index 9ea014f..9ee7fc7 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -28,6 +28,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>
 
@@ -225,6 +226,8 @@ static int construct_vmcb(struct vcpu *v)
         vmcb->_general1_intercepts |= GENERAL1_INTERCEPT_PAUSE;
     }
 
+    svm_avic_init_vmcb(v);
+
     vmcb->cleanbits.bytes = 0;
 
     return 0;
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 0000000..9508486
--- /dev/null
+++ b/xen/include/asm-x86/hvm/svm/avic.h
@@ -0,0 +1,40 @@
+#ifndef _SVM_AVIC_H_
+#define _SVM_AVIC_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,
+};
+
+struct __attribute__ ((__packed__))
+svm_avic_log_ait_entry {
+    u32 guest_phy_apic_id : 8;
+    u32 res               : 23;
+    u32 valid             : 1;
+};
+
+struct __attribute__ ((__packed__))
+svm_avic_phy_ait_entry {
+    u64 host_phy_apic_id  : 8;
+    u64 res1              : 4;
+    u64 bk_pg_ptr         : 40;
+    u64 res2              : 10;
+    u64 is_running        : 1;
+    u64 valid             : 1;
+};
+
+extern bool_t svm_avic;
+
+int svm_avic_dom_init(struct domain *d);
+void svm_avic_dom_destroy(struct domain *d);
+
+int svm_avic_init_vcpu(struct vcpu *v);
+void svm_avic_destroy_vcpu(struct vcpu *v);
+bool_t svm_avic_vcpu_enabled(struct vcpu *v);
+
+void svm_avic_update_vapic_bar(struct vcpu *v,uint64_t data);
+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 c954b7e..fea61bb 100644
--- a/xen/include/asm-x86/hvm/svm/svm.h
+++ b/xen/include/asm-x86/hvm/svm/svm.h
@@ -81,6 +81,7 @@ extern u32 svm_feature_flags;
 #define SVM_FEATURE_FLUSHBYASID    6 /* TLB flush by ASID support */
 #define SVM_FEATURE_DECODEASSISTS  7 /* Decode assists support */
 #define SVM_FEATURE_PAUSEFILTER   10 /* Pause intercept filter support */
+#define SVM_FEATURE_AVIC          13 /* AVIC support */
 
 #define cpu_has_svm_feature(f) test_bit(f, &svm_feature_flags)
 #define cpu_has_svm_npt       cpu_has_svm_feature(SVM_FEATURE_NPT)
@@ -91,6 +92,7 @@ extern u32 svm_feature_flags;
 #define cpu_has_svm_decode    cpu_has_svm_feature(SVM_FEATURE_DECODEASSISTS)
 #define cpu_has_pause_filter  cpu_has_svm_feature(SVM_FEATURE_PAUSEFILTER)
 #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 SVM_PAUSEFILTER_INIT    3000
 
diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h
index 768e9fb..a42c034 100644
--- a/xen/include/asm-x86/hvm/svm/vmcb.h
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h
@@ -496,6 +496,12 @@ struct __packed vmcb_struct {
 };
 
 struct svm_domain {
+    u32 avic_max_vcpu_id;
+    bool_t avic_access_page_done;
+    paddr_t avic_log_ait_mfn;
+    paddr_t avic_phy_ait_mfn;
+    u32 ldr_reg;
+    u32 ldr_mode;
 };
 
 struct arch_svm_struct {
@@ -529,6 +535,10 @@ struct arch_svm_struct {
         u64 length;
         u64 status;
     } osvw;
+
+    /* AVIC APIC backing page */
+    struct page_info *avic_bk_pg;
+    struct svm_avic_phy_ait_entry *avic_phy_id_cache;
 };
 
 struct vmcb_struct *alloc_vmcb(void);
-- 
1.9.1


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

  parent reply	other threads:[~2016-09-19  5:52 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-19  5:52 [RFC PATCH 0/9] Introduce AMD SVM AVIC Suravee Suthikulpanit
2016-09-19  5:52 ` [RFC PATCH 1/9] x86/HVM: Introduce struct hvm_pi_ops Suravee Suthikulpanit
2016-10-12 17:01   ` Konrad Rzeszutek Wilk
2016-09-19  5:52 ` [RFC PATCH 2/9] x86/vLAPIC: Declare vlapic_read_aligned() and vlapic_reg_write() as non-static Suravee Suthikulpanit
2016-10-12 19:00   ` Konrad Rzeszutek Wilk
2016-09-19  5:52 ` [RFC PATCH 3/9] x86/HVM: Call vlapic_destroy after vcpu_destroy Suravee Suthikulpanit
2016-10-12 19:02   ` Konrad Rzeszutek Wilk
2016-12-22 11:09   ` Jan Beulich
2016-09-19  5:52 ` [RFC PATCH 4/9] x86/SVM: Modify VMCB fields to add AVIC support Suravee Suthikulpanit
2016-10-12 19:07   ` Konrad Rzeszutek Wilk
2016-12-22 11:11   ` Jan Beulich
2016-12-26  5:55     ` Suravee Suthikulpanit
2016-09-19  5:52 ` Suravee Suthikulpanit [this message]
2016-10-12 20:02   ` [RFC PATCH 5/9] x86/HVM/SVM: Add AVIC initialization code Konrad Rzeszutek Wilk
2016-11-17 16:05     ` Suravee Suthikulpanit
2016-11-17 17:18       ` Konrad Rzeszutek Wilk
2016-11-17 18:32         ` Suravee Suthikulpanit
2016-11-17 16:55     ` Suravee Suthikulpanit
2016-11-17 17:19       ` Konrad Rzeszutek Wilk
2016-10-14 14:03   ` Konrad Rzeszutek Wilk
2016-12-22 11:16   ` Jan Beulich
2016-12-28  3:36     ` Suravee Suthikulpanit
2016-09-19  5:52 ` [RFC PATCH 6/9] x86/SVM: Add AVIC vmexit handlers Suravee Suthikulpanit
2016-10-14 15:20   ` Konrad Rzeszutek Wilk
2016-12-12 10:34     ` Suravee Suthikulpanit
2017-01-07  1:24       ` Konrad Rzeszutek Wilk
2016-12-22 11:25   ` Jan Beulich
2016-09-19  5:52 ` [RFC PATCH 7/9] x86/SVM: Add vcpu scheduling support for AVIC Suravee Suthikulpanit
2016-10-14 15:31   ` Konrad Rzeszutek Wilk
2016-10-24 11:19     ` Jan Beulich
2016-12-22 11:32   ` Jan Beulich
2016-09-19  5:52 ` [RFC PATCH 8/9] x86/SVM: Add interrupt management code via AVIC Suravee Suthikulpanit
2016-10-14 15:44   ` Konrad Rzeszutek Wilk
2016-12-22 11:36   ` Jan Beulich
2016-09-19  5:52 ` [RFC PATCH 9/9] x86/SVM: Hook up miscellaneous AVIC functions Suravee Suthikulpanit
2016-10-14 15:46   ` Konrad Rzeszutek Wilk
2016-12-22 11:38   ` Jan Beulich
2016-09-19 13:09 ` [RFC PATCH 0/9] Introduce AMD SVM AVIC Konrad Rzeszutek Wilk
2016-09-19 16:21   ` Suravee Suthikulpanit
2016-09-20 14:34 ` Boris Ostrovsky
2016-12-04  7:40   ` Suravee Suthikulpanit
2016-12-22 11:38 ` Jan Beulich
2016-12-28  6:30   ` Suravee Suthikulpanit

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=1474264368-4104-6-git-send-email-suravee.suthikulpanit@amd.com \
    --to=suravee.suthikulpanit@amd.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=jbeulich@suse.com \
    --cc=sherry.hurwitz@amd.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.