--- /dev/null
+/**
+ * @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:
+ */
--- /dev/null
+/**
+ * @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:
+ */
#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)
#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
#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)
# 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