From db5806c24a727a0505f1850b79a6f6c11ee4201c Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Fri, 7 Feb 2014 12:20:43 +0100
Subject: [PATCH 2/9] xen: add hooks for Xen PV APIC

Create the necessary hooks in order to provide a Xen PV APIC
implementation that can be used on PVH. Most of the lapic ops
shouldn't be called on Xen, since we trap those operations at a higher
layer.

Sponsored by: Citrix Systems R&D

x86/xen/hvm.c:
x86/xen/xen_apic.c:
 - Move IPI related code to xen_apic.c

x86/xen/xen_apic.c:
 - Introduce Xen PV APIC implementation, most of the functions of the
   lapic interface should never be called when running as PV(H) guest,
   so make sure FreeBSD panics when trying to use one of those.

xen/xen_apic.h:
 - Prototypes for the Xen APIC methods.

x86/xen/pv.c:
 - Define the Xen APIC implementation in xen_apic_ops by using the
   functions from xen_apic.c.

conf/files.amd64:
conf/files.i386:
 - Include the xen_apic.c file in the build of i386/amd64 kernels
   using XENHVM.
---
 sys/conf/files.amd64   |    1 +
 sys/conf/files.i386    |    1 +
 sys/x86/xen/hvm.c      |  256 ------------------------
 sys/x86/xen/pv.c       |   32 +++
 sys/x86/xen/xen_apic.c |  517 ++++++++++++++++++++++++++++++++++++++++++++++++
 sys/xen/xen_apic.h     |   63 ++++++
 6 files changed, 614 insertions(+), 256 deletions(-)
 create mode 100644 sys/x86/xen/xen_apic.c
 create mode 100644 sys/xen/xen_apic.h

diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index c493a31..65d9bb7 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -559,3 +559,4 @@ x86/xen/hvm.c			optional	xenhvm
 x86/xen/xen_intr.c		optional	xen | xenhvm
 x86/xen/pv.c			optional	xenhvm
 x86/xen/pvcpu_enum.c		optional	xenhvm
+x86/xen/xen_apic.c		optional	xenhvm
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index 8d724ca..8f5ca47 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -596,3 +596,4 @@ x86/x86/tsc.c			standard
 x86/x86/delay.c			standard
 x86/xen/hvm.c			optional xenhvm
 x86/xen/xen_intr.c		optional xen | xenhvm
+x86/xen/xen_apic.c		optional xenhvm
diff --git a/sys/x86/xen/hvm.c b/sys/x86/xen/hvm.c
index a6f07a4..651bdd0 100644
--- a/sys/x86/xen/hvm.c
+++ b/sys/x86/xen/hvm.c
@@ -58,38 +58,13 @@ __FBSDID("$FreeBSD$");
 #include <xen/interface/vcpu.h>
 
 /*--------------------------- Forward Declarations ---------------------------*/
-#ifdef SMP
-static driver_filter_t xen_smp_rendezvous_action;
-static driver_filter_t xen_invltlb;
-static driver_filter_t xen_invlpg;
-static driver_filter_t xen_invlrng;
-static driver_filter_t xen_invlcache;
-#ifdef __i386__
-static driver_filter_t xen_lazypmap;
-#endif
-static driver_filter_t xen_ipi_bitmap_handler;
-static driver_filter_t xen_cpustop_handler;
-static driver_filter_t xen_cpususpend_handler;
-static driver_filter_t xen_cpustophard_handler;
-#endif
-static void xen_ipi_vectored(u_int vector, int dest);
 static void xen_hvm_cpu_resume(void);
 static void xen_hvm_cpu_init(void);
 
 /*---------------------------- Extern Declarations ---------------------------*/
-#ifdef __i386__
-extern void pmap_lazyfix_action(void);
-#endif
-#ifdef __amd64__
-extern int pmap_pcid_enabled;
-#endif
-
 /* Variables used by mp_machdep to perform the bitmap IPI */
 extern volatile u_int cpu_ipi_pending[MAXCPU];
 
-/*---------------------------------- Macros ----------------------------------*/
-#define	IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
-
 /*-------------------------------- Local Types -------------------------------*/
 enum xen_hvm_init_type {
 	XEN_HVM_INIT_COLD,
@@ -97,12 +72,6 @@ enum xen_hvm_init_type {
 	XEN_HVM_INIT_RESUME
 };
 
-struct xen_ipi_handler
-{
-	driver_filter_t	*filter;
-	const char	*description;
-};
-
 /*-------------------------------- Global Data -------------------------------*/
 enum xen_domain_type xen_domain_type = XEN_NATIVE;
 
@@ -113,24 +82,6 @@ struct cpu_ops xen_hvm_cpu_ops = {
 
 static MALLOC_DEFINE(M_XENHVM, "xen_hvm", "Xen HVM PV Support");
 
-#ifdef SMP
-static struct xen_ipi_handler xen_ipis[] = 
-{
-	[IPI_TO_IDX(IPI_RENDEZVOUS)]	= { xen_smp_rendezvous_action,	"r"   },
-	[IPI_TO_IDX(IPI_INVLTLB)]	= { xen_invltlb,		"itlb"},
-	[IPI_TO_IDX(IPI_INVLPG)]	= { xen_invlpg,			"ipg" },
-	[IPI_TO_IDX(IPI_INVLRNG)]	= { xen_invlrng,		"irg" },
-	[IPI_TO_IDX(IPI_INVLCACHE)]	= { xen_invlcache,		"ic"  },
-#ifdef __i386__
-	[IPI_TO_IDX(IPI_LAZYPMAP)]	= { xen_lazypmap,		"lp"  },
-#endif
-	[IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler,	"b"   },
-	[IPI_TO_IDX(IPI_STOP)]		= { xen_cpustop_handler,	"st"  },
-	[IPI_TO_IDX(IPI_SUSPEND)]	= { xen_cpususpend_handler,	"sp"  },
-	[IPI_TO_IDX(IPI_STOP_HARD)]	= { xen_cpustophard_handler,	"sth" },
-};
-#endif
-
 /**
  * If non-zero, the hypervisor has been configured to use a direct
  * IDT event callback for interrupt injection.
@@ -140,9 +91,6 @@ int xen_vector_callback_enabled;
 /*------------------------------- Per-CPU Data -------------------------------*/
 DPCPU_DEFINE(struct vcpu_info, vcpu_local_info);
 DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
-#ifdef SMP
-DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
-#endif
 
 /*------------------ Hypervisor Access Shared Memory Regions -----------------*/
 /** Hypercall table accessed via HYPERVISOR_*_op() methods. */
@@ -150,157 +98,6 @@ extern char *hypercall_page;
 shared_info_t *HYPERVISOR_shared_info;
 start_info_t *HYPERVISOR_start_info;
 
-#ifdef SMP
-/*---------------------------- XEN PV IPI Handlers ---------------------------*/
-/*
- * This are C clones of the ASM functions found in apic_vector.s
- */
-static int
-xen_ipi_bitmap_handler(void *arg)
-{
-	struct trapframe *frame;
-
-	frame = arg;
-	ipi_bitmap_handler(*frame);
-	return (FILTER_HANDLED);
-}
-
-static int
-xen_smp_rendezvous_action(void *arg)
-{
-#ifdef COUNT_IPIS
-	(*ipi_rendezvous_counts[PCPU_GET(cpuid)])++;
-#endif /* COUNT_IPIS */
-
-	smp_rendezvous_action();
-	return (FILTER_HANDLED);
-}
-
-static int
-xen_invltlb(void *arg)
-{
-
-	invltlb_handler();
-	return (FILTER_HANDLED);
-}
-
-#ifdef __amd64__
-static int
-xen_invltlb_pcid(void *arg)
-{
-
-	invltlb_pcid_handler();
-	return (FILTER_HANDLED);
-}
-#endif
-
-static int
-xen_invlpg(void *arg)
-{
-
-	invlpg_handler();
-	return (FILTER_HANDLED);
-}
-
-#ifdef __amd64__
-static int
-xen_invlpg_pcid(void *arg)
-{
-
-	invlpg_pcid_handler();
-	return (FILTER_HANDLED);
-}
-#endif
-
-static int
-xen_invlrng(void *arg)
-{
-
-	invlrng_handler();
-	return (FILTER_HANDLED);
-}
-
-static int
-xen_invlcache(void *arg)
-{
-
-	invlcache_handler();
-	return (FILTER_HANDLED);
-}
-
-#ifdef __i386__
-static int
-xen_lazypmap(void *arg)
-{
-
-	pmap_lazyfix_action();
-	return (FILTER_HANDLED);
-}
-#endif
-
-static int
-xen_cpustop_handler(void *arg)
-{
-
-	cpustop_handler();
-	return (FILTER_HANDLED);
-}
-
-static int
-xen_cpususpend_handler(void *arg)
-{
-
-	cpususpend_handler();
-	return (FILTER_HANDLED);
-}
-
-static int
-xen_cpustophard_handler(void *arg)
-{
-
-	ipi_nmi_handler();
-	return (FILTER_HANDLED);
-}
-
-/* Xen PV IPI sender */
-static void
-xen_ipi_vectored(u_int vector, int dest)
-{
-	xen_intr_handle_t *ipi_handle;
-	int ipi_idx, to_cpu, self;
-
-	ipi_idx = IPI_TO_IDX(vector);
-	if (ipi_idx > nitems(xen_ipis))
-		panic("IPI out of range");
-
-	switch(dest) {
-	case APIC_IPI_DEST_SELF:
-		ipi_handle = DPCPU_GET(ipi_handle);
-		xen_intr_signal(ipi_handle[ipi_idx]);
-		break;
-	case APIC_IPI_DEST_ALL:
-		CPU_FOREACH(to_cpu) {
-			ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
-			xen_intr_signal(ipi_handle[ipi_idx]);
-		}
-		break;
-	case APIC_IPI_DEST_OTHERS:
-		self = PCPU_GET(cpuid);
-		CPU_FOREACH(to_cpu) {
-			if (to_cpu != self) {
-				ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
-				xen_intr_signal(ipi_handle[ipi_idx]);
-			}
-		}
-		break;
-	default:
-		to_cpu = apic_cpuid(dest);
-		ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
-		xen_intr_signal(ipi_handle[ipi_idx]);
-		break;
-	}
-}
-
 /* XEN diverged cpu operations */
 static void
 xen_hvm_cpu_resume(void)
@@ -317,55 +114,6 @@ xen_hvm_cpu_resume(void)
 	xen_hvm_cpu_init();
 }
 
-static void
-xen_cpu_ipi_init(int cpu)
-{
-	xen_intr_handle_t *ipi_handle;
-	const struct xen_ipi_handler *ipi;
-	device_t dev;
-	int idx, rc;
-
-	ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
-	dev = pcpu_find(cpu)->pc_device;
-	KASSERT((dev != NULL), ("NULL pcpu device_t"));
-
-	for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
-
-		if (ipi->filter == NULL) {
-			ipi_handle[idx] = NULL;
-			continue;
-		}
-
-		rc = xen_intr_alloc_and_bind_ipi(dev, cpu, ipi->filter,
-		    INTR_TYPE_TTY, &ipi_handle[idx]);
-		if (rc != 0)
-			panic("Unable to allocate a XEN IPI port");
-		xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
-	}
-}
-
-static void
-xen_setup_cpus(void)
-{
-	int i;
-
-	if (!xen_vector_callback_enabled)
-		return;
-
-#ifdef __amd64__
-	if (pmap_pcid_enabled) {
-		xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = xen_invltlb_pcid;
-		xen_ipis[IPI_TO_IDX(IPI_INVLPG)].filter = xen_invlpg_pcid;
-	}
-#endif
-	CPU_FOREACH(i)
-		xen_cpu_ipi_init(i);
-
-	/* Set the xen pv ipi ops to replace the native ones */
-	apic_ops.ipi_vectored = xen_ipi_vectored;
-}
-#endif
-
 /*---------------------- XEN Hypervisor Probe and Setup ----------------------*/
 static uint32_t
 xen_hvm_cpuid_base(void)
@@ -650,9 +398,5 @@ xen_hvm_cpu_init(void)
 }
 
 SYSINIT(xen_hvm_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, xen_hvm_sysinit, NULL);
-#ifdef SMP
-/* We need to setup IPIs before APs are started */
-SYSINIT(xen_setup_cpus, SI_SUB_SMP-1, SI_ORDER_FIRST, xen_setup_cpus, NULL);
-#endif
 SYSINIT(xen_hvm_cpu_init, SI_SUB_INTR, SI_ORDER_FIRST, xen_hvm_cpu_init, NULL);
 SYSINIT(xen_set_vcpu_id, SI_SUB_CPU, SI_ORDER_ANY, xen_set_vcpu_id, NULL);
diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c
index 96420e3..69c859d 100644
--- a/sys/x86/xen/pv.c
+++ b/sys/x86/xen/pv.c
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
 
 #include <xen/xen-os.h>
 #include <xen/hypervisor.h>
+#include <xen/xen_apic.h>
 
 #include <xen/interface/vcpu.h>
 
@@ -101,6 +102,36 @@ struct init_ops xen_init_ops = {
 #endif
 };
 
+/* Xen apic_ops implementation */
+struct apic_ops xen_apic_ops = {
+	.create = xen_pv_lapic_create,
+	.init = xen_pv_lapic_init,
+	.setup = xen_pv_lapic_setup,
+	.dump = xen_pv_lapic_dump,
+	.disable = xen_pv_lapic_disable,
+	.eoi = xen_pv_lapic_eoi,
+	.id = xen_pv_lapic_id,
+	.intr_pending = xen_pv_lapic_intr_pending,
+	.set_logical_id = xen_pv_lapic_set_logical_id,
+	.cpuid = xen_pv_apic_cpuid,
+	.alloc_vector = xen_pv_apic_alloc_vector,
+	.alloc_vectors = xen_pv_apic_alloc_vectors,
+	.enable_vector = xen_pv_apic_enable_vector,
+	.disable_vector = xen_pv_apic_disable_vector,
+	.free_vector = xen_pv_apic_free_vector,
+	.enable_pmc = xen_pv_lapic_enable_pmc,
+	.disable_pmc = xen_pv_lapic_disable_pmc,
+	.reenable_pmc = xen_pv_lapic_reenable_pmc,
+	.enable_cmc = xen_pv_lapic_enable_cmc,
+	.ipi_raw = xen_pv_lapic_ipi_raw,
+	.ipi_vectored = xen_pv_lapic_ipi_vectored,
+	.ipi_wait = xen_pv_lapic_ipi_wait,
+	.set_lvt_mask = xen_pv_lapic_set_lvt_mask,
+	.set_lvt_mode = xen_pv_lapic_set_lvt_mode,
+	.set_lvt_polarity = xen_pv_lapic_set_lvt_polarity,
+	.set_lvt_triggermode = xen_pv_lapic_set_lvt_triggermode,
+};
+
 static struct bios_smap xen_smap[MAX_E820_ENTRIES];
 
 /*-------------------------------- Xen PV init -------------------------------*/
@@ -170,6 +201,7 @@ hammer_time_xen(start_info_t *si, uint64_t xenstack)
 
 	/* Set the hooks for early functions that diverge from bare metal */
 	init_ops = xen_init_ops;
+	apic_ops = xen_apic_ops;
 
 	/* Now we can jump into the native init function */
 	return (hammer_time(0, physfree));
diff --git a/sys/x86/xen/xen_apic.c b/sys/x86/xen/xen_apic.c
new file mode 100644
index 0000000..0ada7b1
--- /dev/null
+++ b/sys/x86/xen/xen_apic.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2013 Roger Pau Monné <roger.pau@citrix.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/cpufunc.h>
+#include <machine/cpu.h>
+#include <machine/smp.h>
+
+#include <x86/apicreg.h>
+
+#include <xen/xen-os.h>
+#include <xen/features.h>
+#include <xen/gnttab.h>
+#include <xen/hypervisor.h>
+#include <xen/hvm.h>
+#include <xen/xen_intr.h>
+#include <xen/xen_apic.h>
+
+#include <xen/interface/vcpu.h>
+
+/*--------------------------------- Macros -----------------------------------*/
+
+#define XEN_APIC_UNSUPPORTED \
+	panic("%s: not available in Xen PV port.", __func__)
+
+
+/*--------------------------- Forward Declarations ---------------------------*/
+#ifdef SMP
+static driver_filter_t xen_smp_rendezvous_action;
+static driver_filter_t xen_invltlb;
+static driver_filter_t xen_invlpg;
+static driver_filter_t xen_invlrng;
+static driver_filter_t xen_invlcache;
+#ifdef __i386__
+static driver_filter_t xen_lazypmap;
+#endif
+static driver_filter_t xen_ipi_bitmap_handler;
+static driver_filter_t xen_cpustop_handler;
+static driver_filter_t xen_cpususpend_handler;
+static driver_filter_t xen_cpustophard_handler;
+#endif
+
+/*---------------------------- Extern Declarations ---------------------------*/
+/* Variables used by mp_machdep to perform the MMU related IPIs */
+#ifdef __i386__
+extern void pmap_lazyfix_action(void);
+#endif
+#ifdef __amd64__
+extern int pmap_pcid_enabled;
+#endif
+
+extern int xen_vector_callback_enabled;
+
+/*---------------------------------- Macros ----------------------------------*/
+#define	IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
+
+/*--------------------------------- Xen IPIs ---------------------------------*/
+#ifdef SMP
+struct xen_ipi_handler
+{
+	driver_filter_t	*filter;
+	const char	*description;
+};
+
+static struct xen_ipi_handler xen_ipis[] = 
+{
+	[IPI_TO_IDX(IPI_RENDEZVOUS)]	= { xen_smp_rendezvous_action,	"r"   },
+	[IPI_TO_IDX(IPI_INVLTLB)]	= { xen_invltlb,		"itlb"},
+	[IPI_TO_IDX(IPI_INVLPG)]	= { xen_invlpg,			"ipg" },
+	[IPI_TO_IDX(IPI_INVLRNG)]	= { xen_invlrng,		"irg" },
+	[IPI_TO_IDX(IPI_INVLCACHE)]	= { xen_invlcache,		"ic"  },
+#ifdef __i386__
+	[IPI_TO_IDX(IPI_LAZYPMAP)]	= { xen_lazypmap,		"lp"  },
+#endif
+	[IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler,	"b"   },
+	[IPI_TO_IDX(IPI_STOP)]		= { xen_cpustop_handler,	"st"  },
+	[IPI_TO_IDX(IPI_SUSPEND)]	= { xen_cpususpend_handler,	"sp"  },
+	[IPI_TO_IDX(IPI_STOP_HARD)]	= { xen_cpustophard_handler,	"sth" },
+};
+#endif
+
+/*------------------------------- Per-CPU Data -------------------------------*/
+#ifdef SMP
+DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
+#endif
+
+#ifdef SMP
+/*---------------------------- XEN PV IPI Handlers ---------------------------*/
+/*
+ * This are C clones of the ASM functions found in apic_vector.s
+ */
+static int
+xen_ipi_bitmap_handler(void *arg)
+{
+	struct trapframe *frame;
+
+	frame = arg;
+	ipi_bitmap_handler(*frame);
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_smp_rendezvous_action(void *arg)
+{
+#ifdef COUNT_IPIS
+	(*ipi_rendezvous_counts[PCPU_GET(cpuid)])++;
+#endif /* COUNT_IPIS */
+
+	smp_rendezvous_action();
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_invltlb(void *arg)
+{
+
+	invltlb_handler();
+	return (FILTER_HANDLED);
+}
+
+#ifdef __amd64__
+static int
+xen_invltlb_pcid(void *arg)
+{
+
+	invltlb_pcid_handler();
+	return (FILTER_HANDLED);
+}
+#endif
+
+static int
+xen_invlpg(void *arg)
+{
+
+	invlpg_handler();
+	return (FILTER_HANDLED);
+}
+
+#ifdef __amd64__
+static int
+xen_invlpg_pcid(void *arg)
+{
+
+	invlpg_pcid_handler();
+	return (FILTER_HANDLED);
+}
+#endif
+
+static int
+xen_invlrng(void *arg)
+{
+
+	invlrng_handler();
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_invlcache(void *arg)
+{
+
+	invlcache_handler();
+	return (FILTER_HANDLED);
+}
+
+#ifdef __i386__
+static int
+xen_lazypmap(void *arg)
+{
+
+	pmap_lazyfix_action();
+	return (FILTER_HANDLED);
+}
+#endif
+
+static int
+xen_cpustop_handler(void *arg)
+{
+
+	cpustop_handler();
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_cpususpend_handler(void *arg)
+{
+
+	cpususpend_handler();
+	return (FILTER_HANDLED);
+}
+
+static int
+xen_cpustophard_handler(void *arg)
+{
+
+	ipi_nmi_handler();
+	return (FILTER_HANDLED);
+}
+
+/*----------------------------- XEN PV IPI setup -----------------------------*/
+/*
+ * Those functions are provided outside of the Xen PV APIC implementation
+ * so PVHVM guests can also use PV IPIs without having an actual Xen PV APIC,
+ * because on PVHVM there's an emulated LAPIC provided by Xen.
+ */
+static void
+xen_cpu_ipi_init(int cpu)
+{
+	xen_intr_handle_t *ipi_handle;
+	const struct xen_ipi_handler *ipi;
+	device_t dev;
+	int idx, rc;
+
+	ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
+	dev = pcpu_find(cpu)->pc_device;
+	KASSERT((dev != NULL), ("NULL pcpu device_t"));
+
+	for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
+
+		if (ipi->filter == NULL) {
+			ipi_handle[idx] = NULL;
+			continue;
+		}
+
+		rc = xen_intr_alloc_and_bind_ipi(dev, cpu, ipi->filter,
+		    INTR_TYPE_TTY, &ipi_handle[idx]);
+		if (rc != 0)
+			panic("Unable to allocate a XEN IPI port");
+		xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
+	}
+}
+
+static void
+xen_setup_cpus(void)
+{
+	int i;
+
+	if (!xen_vector_callback_enabled)
+		return;
+
+#ifdef __amd64__
+	if (pmap_pcid_enabled) {
+		xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = xen_invltlb_pcid;
+		xen_ipis[IPI_TO_IDX(IPI_INVLPG)].filter = xen_invlpg_pcid;
+	}
+#endif
+	CPU_FOREACH(i)
+		xen_cpu_ipi_init(i);
+
+	/* Set the xen pv ipi ops to replace the native ones */
+	if (xen_hvm_domain())
+		apic_ops.ipi_vectored = xen_pv_lapic_ipi_vectored;
+}
+
+/* We need to setup IPIs before APs are started */
+SYSINIT(xen_setup_cpus, SI_SUB_SMP-1, SI_ORDER_FIRST, xen_setup_cpus, NULL);
+#endif /* SMP */
+
+/*------------------------------- Xen PV APIC --------------------------------*/
+
+void
+xen_pv_lapic_create(u_int apic_id, int boot_cpu)
+{
+#ifdef SMP
+	cpu_add(apic_id, boot_cpu);
+#endif
+}
+
+void
+xen_pv_lapic_init(vm_paddr_t addr)
+{
+
+}
+
+void
+xen_pv_lapic_setup(int boot)
+{
+
+}
+
+void
+xen_pv_lapic_dump(const char *str)
+{
+
+	printf("cpu%d %s XEN PV LAPIC\n", PCPU_GET(cpuid), str);
+}
+
+void
+xen_pv_lapic_disable(void)
+{
+
+}
+
+void
+xen_pv_lapic_eoi(void)
+{
+
+	XEN_APIC_UNSUPPORTED;
+}
+
+int
+xen_pv_lapic_id(void)
+{
+
+	return (PCPU_GET(apic_id));
+}
+
+int
+xen_pv_lapic_intr_pending(u_int vector)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
+
+u_int
+xen_pv_apic_cpuid(u_int apic_id)
+{
+#ifdef SMP
+	return (apic_cpuids[apic_id]);
+#else
+	return (0);
+#endif
+}
+
+u_int
+xen_pv_apic_alloc_vector(u_int apic_id, u_int irq)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
+
+u_int
+xen_pv_apic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count, u_int align)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
+
+void
+xen_pv_apic_disable_vector(u_int apic_id, u_int vector)
+{
+
+	XEN_APIC_UNSUPPORTED;
+}
+
+void
+xen_pv_apic_enable_vector(u_int apic_id, u_int vector)
+{
+
+	XEN_APIC_UNSUPPORTED;
+}
+
+void
+xen_pv_apic_free_vector(u_int apic_id, u_int vector, u_int irq)
+{
+
+	XEN_APIC_UNSUPPORTED;
+}
+
+void
+xen_pv_lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id)
+{
+
+	XEN_APIC_UNSUPPORTED;
+}
+
+int
+xen_pv_lapic_enable_pmc(void)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
+
+void
+xen_pv_lapic_disable_pmc(void)
+{
+
+	XEN_APIC_UNSUPPORTED;
+}
+
+void
+xen_pv_lapic_reenable_pmc(void)
+{
+
+	XEN_APIC_UNSUPPORTED;
+}
+
+void
+xen_pv_lapic_enable_cmc(void)
+{
+
+}
+
+void
+xen_pv_lapic_ipi_raw(register_t icrlo, u_int dest)
+{
+
+	XEN_APIC_UNSUPPORTED;
+}
+
+void
+xen_pv_lapic_ipi_vectored(u_int vector, int dest)
+{
+	xen_intr_handle_t *ipi_handle;
+	int ipi_idx, to_cpu, self;
+
+	ipi_idx = IPI_TO_IDX(vector);
+	if (ipi_idx > nitems(xen_ipis))
+		panic("IPI out of range");
+
+	switch(dest) {
+	case APIC_IPI_DEST_SELF:
+		ipi_handle = DPCPU_GET(ipi_handle);
+		xen_intr_signal(ipi_handle[ipi_idx]);
+		break;
+	case APIC_IPI_DEST_ALL:
+		CPU_FOREACH(to_cpu) {
+			ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+			xen_intr_signal(ipi_handle[ipi_idx]);
+		}
+		break;
+	case APIC_IPI_DEST_OTHERS:
+		self = PCPU_GET(cpuid);
+		CPU_FOREACH(to_cpu) {
+			if (to_cpu != self) {
+				ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+				xen_intr_signal(ipi_handle[ipi_idx]);
+			}
+		}
+		break;
+	default:
+		to_cpu = apic_cpuid(dest);
+		ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
+		xen_intr_signal(ipi_handle[ipi_idx]);
+		break;
+	}
+}
+
+int
+xen_pv_lapic_ipi_wait(int delay)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
+
+int
+xen_pv_lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
+
+int
+xen_pv_lapic_set_lvt_mode(u_int apic_id, u_int lvt, uint32_t mode)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
+
+int
+xen_pv_lapic_set_lvt_polarity(u_int apic_id, u_int lvt, enum intr_polarity pol)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
+
+int
+xen_pv_lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
+    enum intr_trigger trigger)
+{
+
+	XEN_APIC_UNSUPPORTED;
+	return (0);
+}
diff --git a/sys/xen/xen_apic.h b/sys/xen/xen_apic.h
new file mode 100644
index 0000000..8d91127
--- /dev/null
+++ b/sys/xen/xen_apic.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2013 Roger Pau Monné <roger.pau@citrix.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __XEN_APIC_H__
+#define __XEN_APIC_H__
+
+void xen_pv_lapic_create(u_int apic_id, int boot_cpu);
+void xen_pv_lapic_init(vm_paddr_t addr);
+void xen_pv_lapic_setup(int boot);
+void xen_pv_lapic_dump(const char *str);
+void xen_pv_lapic_disable(void);
+void xen_pv_lapic_eoi(void);
+int xen_pv_lapic_id(void);
+int xen_pv_lapic_intr_pending(u_int vector);
+u_int xen_pv_apic_cpuid(u_int apic_id);
+u_int xen_pv_apic_alloc_vector(u_int apic_id, u_int irq);
+u_int xen_pv_apic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count,
+    u_int align);
+void xen_pv_apic_disable_vector(u_int apic_id, u_int vector);
+void xen_pv_apic_enable_vector(u_int apic_id, u_int vector);
+void xen_pv_apic_free_vector(u_int apic_id, u_int vector, u_int irq);
+void xen_pv_lapic_set_logical_id(u_int apic_id, u_int cluster,
+     u_int cluster_id);
+int xen_pv_lapic_enable_pmc(void);
+void xen_pv_lapic_disable_pmc(void);
+void xen_pv_lapic_reenable_pmc(void);
+void xen_pv_lapic_enable_cmc(void);
+void xen_pv_lapic_ipi_raw(register_t icrlo, u_int dest);
+void xen_pv_lapic_ipi_vectored(u_int vector, int dest);
+int xen_pv_lapic_ipi_wait(int delay);
+int xen_pv_lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked);
+int xen_pv_lapic_set_lvt_mode(u_int apic_id, u_int lvt, uint32_t mode);
+int xen_pv_lapic_set_lvt_polarity(u_int apic_id, u_int lvt,
+     enum intr_polarity pol);
+int xen_pv_lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
+     enum intr_trigger trigger);
+
+#endif /* __XEN_APIC_H__ */
-- 
1.7.7.5 (Apple Git-26)

