]> xenbits.xensource.com Git - people/andrewcoop/xen-test-framework.git/commitdiff
Introduce some basic APIC infrastructure
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 1 Jun 2017 14:04:15 +0000 (14:04 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 26 Jun 2017 14:34:26 +0000 (15:34 +0100)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/apic.c [new file with mode: 0644]
arch/x86/include/arch/apic.h [new file with mode: 0644]
arch/x86/include/arch/cpuid.h
arch/x86/include/arch/msr-index.h
build/files.mk

diff --git a/arch/x86/apic.c b/arch/x86/apic.c
new file mode 100644 (file)
index 0000000..4e7b5b6
--- /dev/null
@@ -0,0 +1,102 @@
+/**
+ * @file arch/x86/apic.c
+ *
+ * Basic x86 APIC driver.
+ */
+#include <xtf/lib.h>
+
+#include <arch/apic.h>
+#include <arch/cpuid.h>
+#include <arch/lib.h>
+#include <arch/page.h>
+
+enum apic_mode cur_apic_mode;
+
+static enum apic_mode apicbase_to_mode(uint64_t apicbase)
+{
+    switch ( apicbase & (MSR_APICBASE_EXTD | MSR_APICBASE_ENABLE) )
+    {
+    case 0:
+        return APIC_MODE_DISABLED;
+
+    case MSR_APICBASE_ENABLE:
+        return APIC_MODE_XAPIC;
+
+    case MSR_APICBASE_EXTD | MSR_APICBASE_ENABLE:
+        return APIC_MODE_X2APIC;
+
+    default:
+        return APIC_MODE_NONE;
+    }
+}
+
+int apic_init(enum apic_mode mode)
+{
+    uint64_t msrval;
+
+    ASSERT(mode > APIC_MODE_NONE);
+
+    /*
+     * First pass through this function.  Try to calculate what is available
+     * (if anything).
+     */
+    if ( cur_apic_mode == APIC_MODE_UNKNOWN )
+    {
+        if ( rdmsr_safe(MSR_APICBASE, &msrval) )
+            cur_apic_mode = APIC_MODE_NONE;
+        else
+        {
+            cur_apic_mode = apicbase_to_mode(msrval);
+
+            /* Set the MMIO base back to default if necessary. */
+            if ( (msrval & PAGE_MASK) != APIC_DEFAULT_BASE )
+            {
+                msrval &= ~PAGE_MASK;
+                msrval |= APIC_DEFAULT_BASE;
+
+                wrmsr(MSR_APICBASE, msrval);
+            }
+        }
+    }
+
+    /*
+     * Bail if there is no APIC, or X2APIC was requested and hardware doesn't
+     * support it.
+     */
+    if ( (cur_apic_mode == APIC_MODE_NONE) ||
+         (mode == APIC_MODE_X2APIC && !cpu_has_x2apic) )
+        return -ENODEV;
+
+    /*
+     * Attempt to switch to the requested mode.  For simplicity, this always
+     * starts by disabling, then cycling through XAPIC and X2APIC if
+     * applicable.
+     */
+    if ( mode != cur_apic_mode )
+    {
+        msrval = rdmsr(MSR_APICBASE) &
+            ~(MSR_APICBASE_EXTD | MSR_APICBASE_ENABLE);
+
+        wrmsr(MSR_APICBASE, msrval);
+
+        if ( mode == APIC_MODE_XAPIC || mode == APIC_MODE_X2APIC )
+            wrmsr(MSR_APICBASE, msrval | MSR_APICBASE_ENABLE);
+
+        if ( mode == APIC_MODE_X2APIC )
+            wrmsr(MSR_APICBASE, msrval | MSR_APICBASE_ENABLE | MSR_APICBASE_EXTD);
+
+        cur_apic_mode = mode;
+    }
+
+    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/arch/x86/include/arch/apic.h b/arch/x86/include/arch/apic.h
new file mode 100644 (file)
index 0000000..3cb8877
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * @file arch/x86/include/arch/apic.h
+ *
+ * %x86 Local APIC register definitions and utility functions.
+ *
+ * The xAPIC MMIO window is expected to be in its default location for the
+ * benefit of unpaged environments.
+ */
+
+#ifndef XTF_X86_APIC_H
+#define XTF_X86_APIC_H
+
+#include <xtf/types.h>
+#include <xen/errno.h>
+
+#include <arch/msr-index.h>
+
+/* Local APIC register definitions. */
+#define APIC_ID         0x020
+#define APIC_LVR        0x030
+#define APIC_ICR        0x300
+#define   APIC_DM_NMI             0x00400
+#define   APIC_ICR_BUSY           0x01000
+#define   APIC_DEST_SELF          0x40000
+
+#define APIC_ICR2       0x310
+
+#define APIC_DEFAULT_BASE 0xfee00000ul
+
+/* Utilities. */
+
+enum apic_mode {
+    APIC_MODE_UNKNOWN,
+    APIC_MODE_NONE,
+    APIC_MODE_DISABLED,
+    APIC_MODE_XAPIC,
+    APIC_MODE_X2APIC,
+};
+
+/**
+ * Discover and initialise the local APIC to the requested mode.  May fail if
+ * there is no APIC, or the requested mode is not available.
+ */
+int apic_init(enum apic_mode mode);
+
+static inline uint32_t apic_mmio_read(unsigned int reg)
+{
+    return *(volatile uint32_t *)(_p(APIC_DEFAULT_BASE) + reg);
+}
+
+static inline void apic_mmio_write(unsigned int reg, uint32_t val)
+{
+    *(volatile uint32_t *)(_p(APIC_DEFAULT_BASE) + reg) = val;
+}
+
+static inline uint32_t apic_msr_read(unsigned int reg)
+{
+    unsigned long val;
+
+    asm volatile ("rdmsr" : "=a" (val)
+                  : "c" (MSR_X2APIC_REGS + (reg >> 4)) : "edx");
+
+    return val;
+}
+
+static inline void apic_msr_write(unsigned int reg, uint32_t val)
+{
+    asm volatile ("wrmsr" : "=a" (val)
+                  : "c" (MSR_X2APIC_REGS + (reg >> 4)), "d" (0));
+}
+
+extern enum apic_mode cur_apic_mode;
+
+static inline uint32_t apic_read(unsigned int reg)
+{
+    if ( cur_apic_mode == APIC_MODE_XAPIC )
+        return apic_mmio_read(reg);
+    else
+        return apic_msr_read(reg);
+}
+
+static inline void apic_write(unsigned int reg, uint32_t val)
+{
+    if ( cur_apic_mode == APIC_MODE_XAPIC )
+        return apic_mmio_write(reg, val);
+    else
+        return apic_msr_write(reg, val);
+}
+
+#endif /* XTF_X86_APIC_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index bff55d46be35c3e04d3d87e4f7b02da1f92d2162..a51a8291e7a7649fde5283cce4cf337233e3f1ed 100644 (file)
@@ -76,6 +76,7 @@ static inline bool cpu_has(unsigned int feature)
 #define cpu_has_vmx             cpu_has(X86_FEATURE_VMX)
 #define cpu_has_smx             cpu_has(X86_FEATURE_SMX)
 #define cpu_has_pcid            cpu_has(X86_FEATURE_PCID)
+#define cpu_has_x2apic          cpu_has(X86_FEATURE_X2APIC)
 #define cpu_has_xsave           cpu_has(X86_FEATURE_XSAVE)
 #define cpu_has_avx             cpu_has(X86_FEATURE_AVX)
 
index f6e26577ad325f09722a9016b97c94101ee789a8..cc5f5a4f34f4473cc9e0b177af742b0cb05e3fca 100644 (file)
@@ -3,6 +3,11 @@
 
 #include <xtf/numbers.h>
 
+#define MSR_APICBASE                    0x0000001b
+#define MSR_APICBASE_BSP                (_AC(1, L) << 8)
+#define MSR_APICBASE_EXTD               (_AC(1, L) << 10)
+#define MSR_APICBASE_ENABLE             (_AC(1, L) << 11)
+
 #define MSR_PMC(n)                     (0x000000c1 + (n))
 
 #define MSR_INTEL_PLATFORM_INFO         0x000000ce
@@ -27,6 +32,8 @@
 #define MSR_PERF_GLOBAL_OVF_CTRL        0x00000390
 #define MSR_A_PMC(n)                   (0x000004c1 + (n))
 
+#define MSR_X2APIC_REGS                 0x00000800
+
 #define MSR_EFER                        0xc0000080 /* Extended Feature register. */
 #define _EFER_SCE                       0  /* SYSCALL Enable. */
 #define EFER_SCE                        (_AC(1, L) << _EFER_SCE)
index 8ffd6e7d709709514042abe0c14ee61368580b25..3454aa38554f5f84a0b99e5ac397b4e86e57069d 100644 (file)
@@ -24,6 +24,7 @@ obj-perenv += $(ROOT)/arch/x86/traps.o
 
 
 # HVM specific objects
+obj-hvm += $(ROOT)/arch/x86/apic.o
 obj-hvm += $(ROOT)/arch/x86/hvm/pagetables.o
 obj-hvm += $(ROOT)/arch/x86/hvm/traps.o