xref: /freebsd/sys/x86/xen/xen_apic.c (revision ad7dd514)
124f7e474SRoger Pau Monné /*
224f7e474SRoger Pau Monné  * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com>
324f7e474SRoger Pau Monné  * All rights reserved.
424f7e474SRoger Pau Monné  *
524f7e474SRoger Pau Monné  * Redistribution and use in source and binary forms, with or without
624f7e474SRoger Pau Monné  * modification, are permitted provided that the following conditions
724f7e474SRoger Pau Monné  * are met:
824f7e474SRoger Pau Monné  * 1. Redistributions of source code must retain the above copyright
924f7e474SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer.
1024f7e474SRoger Pau Monné  * 2. Redistributions in binary form must reproduce the above copyright
1124f7e474SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer in the
1224f7e474SRoger Pau Monné  *    documentation and/or other materials provided with the distribution.
1324f7e474SRoger Pau Monné  *
1424f7e474SRoger Pau Monné  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
1524f7e474SRoger Pau Monné  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1624f7e474SRoger Pau Monné  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1724f7e474SRoger Pau Monné  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1824f7e474SRoger Pau Monné  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1924f7e474SRoger Pau Monné  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2024f7e474SRoger Pau Monné  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2124f7e474SRoger Pau Monné  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2224f7e474SRoger Pau Monné  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2324f7e474SRoger Pau Monné  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2424f7e474SRoger Pau Monné  * SUCH DAMAGE.
2524f7e474SRoger Pau Monné  */
2624f7e474SRoger Pau Monné 
2724f7e474SRoger Pau Monné #include <sys/cdefs.h>
2824f7e474SRoger Pau Monné __FBSDID("$FreeBSD$");
2924f7e474SRoger Pau Monné 
3024f7e474SRoger Pau Monné #include <sys/param.h>
3124f7e474SRoger Pau Monné #include <sys/bus.h>
3224f7e474SRoger Pau Monné #include <sys/kernel.h>
3324f7e474SRoger Pau Monné #include <sys/malloc.h>
3424f7e474SRoger Pau Monné #include <sys/proc.h>
3524f7e474SRoger Pau Monné #include <sys/smp.h>
3624f7e474SRoger Pau Monné #include <sys/systm.h>
3724f7e474SRoger Pau Monné 
3824f7e474SRoger Pau Monné #include <vm/vm.h>
3924f7e474SRoger Pau Monné #include <vm/pmap.h>
4024f7e474SRoger Pau Monné 
4124f7e474SRoger Pau Monné #include <machine/cpufunc.h>
4224f7e474SRoger Pau Monné #include <machine/cpu.h>
43fae92773SJohn Baldwin #include <machine/intr_machdep.h>
4445c228ccSKonstantin Belousov #include <machine/md_var.h>
4524f7e474SRoger Pau Monné #include <machine/smp.h>
4624f7e474SRoger Pau Monné 
4724f7e474SRoger Pau Monné #include <x86/apicreg.h>
48fae92773SJohn Baldwin #include <x86/apicvar.h>
4924f7e474SRoger Pau Monné 
5024f7e474SRoger Pau Monné #include <xen/xen-os.h>
5124f7e474SRoger Pau Monné #include <xen/features.h>
5224f7e474SRoger Pau Monné #include <xen/gnttab.h>
5324f7e474SRoger Pau Monné #include <xen/hypervisor.h>
5424f7e474SRoger Pau Monné #include <xen/hvm.h>
5524f7e474SRoger Pau Monné #include <xen/xen_intr.h>
5624f7e474SRoger Pau Monné 
57ad7dd514SElliott Mitchell #include <contrib/xen/arch-x86/cpuid.h>
58ad7dd514SElliott Mitchell #include <contrib/xen/vcpu.h>
5924f7e474SRoger Pau Monné 
6024f7e474SRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/
6124f7e474SRoger Pau Monné static driver_filter_t xen_smp_rendezvous_action;
62dc43978aSKonstantin Belousov #ifdef __amd64__
63dc43978aSKonstantin Belousov static driver_filter_t xen_invlop;
64dc43978aSKonstantin Belousov #else
6524f7e474SRoger Pau Monné static driver_filter_t xen_invltlb;
6624f7e474SRoger Pau Monné static driver_filter_t xen_invlpg;
6724f7e474SRoger Pau Monné static driver_filter_t xen_invlrng;
6824f7e474SRoger Pau Monné static driver_filter_t xen_invlcache;
69dc43978aSKonstantin Belousov #endif
7024f7e474SRoger Pau Monné static driver_filter_t xen_ipi_bitmap_handler;
7124f7e474SRoger Pau Monné static driver_filter_t xen_cpustop_handler;
7224f7e474SRoger Pau Monné static driver_filter_t xen_cpususpend_handler;
73aba10e13SAlexander Motin static driver_filter_t xen_ipi_swi_handler;
7424f7e474SRoger Pau Monné 
7524f7e474SRoger Pau Monné /*---------------------------------- Macros ----------------------------------*/
7624f7e474SRoger Pau Monné #define	IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
7724f7e474SRoger Pau Monné 
7824f7e474SRoger Pau Monné /*--------------------------------- Xen IPIs ---------------------------------*/
7924f7e474SRoger Pau Monné struct xen_ipi_handler
8024f7e474SRoger Pau Monné {
8124f7e474SRoger Pau Monné 	driver_filter_t	*filter;
8224f7e474SRoger Pau Monné 	const char	*description;
8324f7e474SRoger Pau Monné };
8424f7e474SRoger Pau Monné 
8524f7e474SRoger Pau Monné static struct xen_ipi_handler xen_ipis[] =
8624f7e474SRoger Pau Monné {
8724f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_RENDEZVOUS)]	= { xen_smp_rendezvous_action,	"r"   },
88dc43978aSKonstantin Belousov #ifdef __amd64__
89dc43978aSKonstantin Belousov 	[IPI_TO_IDX(IPI_INVLOP)]	= { xen_invlop,			"itlb"},
90dc43978aSKonstantin Belousov #else
9124f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_INVLTLB)]	= { xen_invltlb,		"itlb"},
9224f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_INVLPG)]	= { xen_invlpg,			"ipg" },
9324f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_INVLRNG)]	= { xen_invlrng,		"irg" },
9424f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_INVLCACHE)]	= { xen_invlcache,		"ic"  },
95dc43978aSKonstantin Belousov #endif
9624f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler,	"b"   },
9724f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_STOP)]		= { xen_cpustop_handler,	"st"  },
9824f7e474SRoger Pau Monné 	[IPI_TO_IDX(IPI_SUSPEND)]	= { xen_cpususpend_handler,	"sp"  },
99aba10e13SAlexander Motin 	[IPI_TO_IDX(IPI_SWI)]		= { xen_ipi_swi_handler,	"sw"  },
10024f7e474SRoger Pau Monné };
10124f7e474SRoger Pau Monné 
102ad15eeeaSRoger Pau Monné /*
103ad15eeeaSRoger Pau Monné  * Save previous (native) handler as a fallback. Xen < 4.7 doesn't support
104ad15eeeaSRoger Pau Monné  * VCPUOP_send_nmi for HVM guests, and thus we need a fallback in that case:
105ad15eeeaSRoger Pau Monné  *
106ad15eeeaSRoger Pau Monné  * https://lists.freebsd.org/archives/freebsd-xen/2022-January/000032.html
107ad15eeeaSRoger Pau Monné  */
108ad15eeeaSRoger Pau Monné void (*native_ipi_vectored)(u_int, int);
109ad15eeeaSRoger Pau Monné 
11024f7e474SRoger Pau Monné /*------------------------------- Per-CPU Data -------------------------------*/
11124f7e474SRoger Pau Monné DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
11224f7e474SRoger Pau Monné 
11324f7e474SRoger Pau Monné /*------------------------------- Xen PV APIC --------------------------------*/
11424f7e474SRoger Pau Monné 
115b2802351SRoger Pau Monné #define PCPU_ID_GET(id, field) (pcpu_find(id)->pc_##field)
116ad15eeeaSRoger Pau Monné static int
117b2802351SRoger Pau Monné send_nmi(int dest)
118b2802351SRoger Pau Monné {
119b2802351SRoger Pau Monné 	unsigned int cpu;
120ad15eeeaSRoger Pau Monné 	int rc = 0;
121b2802351SRoger Pau Monné 
122b2802351SRoger Pau Monné 	/*
123b2802351SRoger Pau Monné 	 * NMIs are not routed over event channels, and instead delivered as on
124b2802351SRoger Pau Monné 	 * native using the exception vector (#2). Triggering them can be done
125b2802351SRoger Pau Monné 	 * using the local APIC, or an hypercall as a shortcut like it's done
126b2802351SRoger Pau Monné 	 * below.
127b2802351SRoger Pau Monné 	 */
128b2802351SRoger Pau Monné 	switch(dest) {
129b2802351SRoger Pau Monné 	case APIC_IPI_DEST_SELF:
130ad15eeeaSRoger Pau Monné 		rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi, PCPU_GET(vcpu_id), NULL);
131b2802351SRoger Pau Monné 		break;
132b2802351SRoger Pau Monné 	case APIC_IPI_DEST_ALL:
133ad15eeeaSRoger Pau Monné 		CPU_FOREACH(cpu) {
134ad15eeeaSRoger Pau Monné 			rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
135b2802351SRoger Pau Monné 			    PCPU_ID_GET(cpu, vcpu_id), NULL);
136ad15eeeaSRoger Pau Monné 			if (rc != 0)
137ad15eeeaSRoger Pau Monné 				break;
138ad15eeeaSRoger Pau Monné 		}
139b2802351SRoger Pau Monné 		break;
140b2802351SRoger Pau Monné 	case APIC_IPI_DEST_OTHERS:
141ad15eeeaSRoger Pau Monné 		CPU_FOREACH(cpu) {
142ad15eeeaSRoger Pau Monné 			if (cpu != PCPU_GET(cpuid)) {
143ad15eeeaSRoger Pau Monné 				rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
144b2802351SRoger Pau Monné 				    PCPU_ID_GET(cpu, vcpu_id), NULL);
145ad15eeeaSRoger Pau Monné 				if (rc != 0)
146ad15eeeaSRoger Pau Monné 					break;
147ad15eeeaSRoger Pau Monné 			}
148ad15eeeaSRoger Pau Monné 		}
149b2802351SRoger Pau Monné 		break;
150b2802351SRoger Pau Monné 	default:
151ad15eeeaSRoger Pau Monné 		rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
152b2802351SRoger Pau Monné 		    PCPU_ID_GET(apic_cpuid(dest), vcpu_id), NULL);
153b2802351SRoger Pau Monné 		break;
154b2802351SRoger Pau Monné 	}
155ad15eeeaSRoger Pau Monné 
156ad15eeeaSRoger Pau Monné 	return rc;
157b2802351SRoger Pau Monné }
158b2802351SRoger Pau Monné #undef PCPU_ID_GET
159b2802351SRoger Pau Monné 
16024f7e474SRoger Pau Monné static void
16124f7e474SRoger Pau Monné xen_pv_lapic_ipi_vectored(u_int vector, int dest)
16224f7e474SRoger Pau Monné {
16324f7e474SRoger Pau Monné 	xen_intr_handle_t *ipi_handle;
16424f7e474SRoger Pau Monné 	int ipi_idx, to_cpu, self;
165ad15eeeaSRoger Pau Monné 	static bool pvnmi = true;
16624f7e474SRoger Pau Monné 
167b2802351SRoger Pau Monné 	if (vector >= IPI_NMI_FIRST) {
168ad15eeeaSRoger Pau Monné 		if (pvnmi) {
169ad15eeeaSRoger Pau Monné 			int rc = send_nmi(dest);
170ad15eeeaSRoger Pau Monné 
171ad15eeeaSRoger Pau Monné 			if (rc != 0) {
172ad15eeeaSRoger Pau Monné 				printf(
173ad15eeeaSRoger Pau Monné     "Sending NMI using hypercall failed (%d) switching to APIC\n", rc);
174ad15eeeaSRoger Pau Monné 				pvnmi = false;
175ad15eeeaSRoger Pau Monné 				native_ipi_vectored(vector, dest);
176ad15eeeaSRoger Pau Monné 			}
177ad15eeeaSRoger Pau Monné 		} else
178ad15eeeaSRoger Pau Monné 			native_ipi_vectored(vector, dest);
179ad15eeeaSRoger Pau Monné 
180b2802351SRoger Pau Monné 		return;
181b2802351SRoger Pau Monné 	}
182b2802351SRoger Pau Monné 
18324f7e474SRoger Pau Monné 	ipi_idx = IPI_TO_IDX(vector);
1848114c8e1SRoger Pau Monné 	if (ipi_idx >= nitems(xen_ipis))
18524f7e474SRoger Pau Monné 		panic("IPI out of range");
18624f7e474SRoger Pau Monné 
18724f7e474SRoger Pau Monné 	switch(dest) {
18824f7e474SRoger Pau Monné 	case APIC_IPI_DEST_SELF:
18924f7e474SRoger Pau Monné 		ipi_handle = DPCPU_GET(ipi_handle);
19024f7e474SRoger Pau Monné 		xen_intr_signal(ipi_handle[ipi_idx]);
19124f7e474SRoger Pau Monné 		break;
19224f7e474SRoger Pau Monné 	case APIC_IPI_DEST_ALL:
19324f7e474SRoger Pau Monné 		CPU_FOREACH(to_cpu) {
19424f7e474SRoger Pau Monné 			ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
19524f7e474SRoger Pau Monné 			xen_intr_signal(ipi_handle[ipi_idx]);
19624f7e474SRoger Pau Monné 		}
19724f7e474SRoger Pau Monné 		break;
19824f7e474SRoger Pau Monné 	case APIC_IPI_DEST_OTHERS:
19924f7e474SRoger Pau Monné 		self = PCPU_GET(cpuid);
20024f7e474SRoger Pau Monné 		CPU_FOREACH(to_cpu) {
20124f7e474SRoger Pau Monné 			if (to_cpu != self) {
20224f7e474SRoger Pau Monné 				ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
20324f7e474SRoger Pau Monné 				xen_intr_signal(ipi_handle[ipi_idx]);
20424f7e474SRoger Pau Monné 			}
20524f7e474SRoger Pau Monné 		}
20624f7e474SRoger Pau Monné 		break;
20724f7e474SRoger Pau Monné 	default:
20824f7e474SRoger Pau Monné 		to_cpu = apic_cpuid(dest);
20924f7e474SRoger Pau Monné 		ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
21024f7e474SRoger Pau Monné 		xen_intr_signal(ipi_handle[ipi_idx]);
21124f7e474SRoger Pau Monné 		break;
21224f7e474SRoger Pau Monné 	}
21324f7e474SRoger Pau Monné }
21424f7e474SRoger Pau Monné 
21524f7e474SRoger Pau Monné /*---------------------------- XEN PV IPI Handlers ---------------------------*/
21624f7e474SRoger Pau Monné /*
21724f7e474SRoger Pau Monné  * These are C clones of the ASM functions found in apic_vector.
21824f7e474SRoger Pau Monné  */
21924f7e474SRoger Pau Monné static int
22024f7e474SRoger Pau Monné xen_ipi_bitmap_handler(void *arg)
22124f7e474SRoger Pau Monné {
22224f7e474SRoger Pau Monné 	struct trapframe *frame;
22324f7e474SRoger Pau Monné 
22424f7e474SRoger Pau Monné 	frame = arg;
22524f7e474SRoger Pau Monné 	ipi_bitmap_handler(*frame);
22624f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
22724f7e474SRoger Pau Monné }
22824f7e474SRoger Pau Monné 
22924f7e474SRoger Pau Monné static int
23024f7e474SRoger Pau Monné xen_smp_rendezvous_action(void *arg)
23124f7e474SRoger Pau Monné {
23224f7e474SRoger Pau Monné #ifdef COUNT_IPIS
23324f7e474SRoger Pau Monné 	(*ipi_rendezvous_counts[PCPU_GET(cpuid)])++;
23424f7e474SRoger Pau Monné #endif /* COUNT_IPIS */
23524f7e474SRoger Pau Monné 
23624f7e474SRoger Pau Monné 	smp_rendezvous_action();
23724f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
23824f7e474SRoger Pau Monné }
23924f7e474SRoger Pau Monné 
240dc43978aSKonstantin Belousov #ifdef __amd64__
241dc43978aSKonstantin Belousov static int
242dc43978aSKonstantin Belousov xen_invlop(void *arg)
243dc43978aSKonstantin Belousov {
244dc43978aSKonstantin Belousov 
245dc43978aSKonstantin Belousov 	invlop_handler();
246dc43978aSKonstantin Belousov 	return (FILTER_HANDLED);
247dc43978aSKonstantin Belousov }
248dc43978aSKonstantin Belousov 
249dc43978aSKonstantin Belousov #else /* __i386__ */
250dc43978aSKonstantin Belousov 
25124f7e474SRoger Pau Monné static int
25224f7e474SRoger Pau Monné xen_invltlb(void *arg)
25324f7e474SRoger Pau Monné {
25424f7e474SRoger Pau Monné 
25524f7e474SRoger Pau Monné 	invltlb_handler();
25624f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
25724f7e474SRoger Pau Monné }
25824f7e474SRoger Pau Monné 
25924f7e474SRoger Pau Monné static int
26024f7e474SRoger Pau Monné xen_invlpg(void *arg)
26124f7e474SRoger Pau Monné {
26224f7e474SRoger Pau Monné 
26324f7e474SRoger Pau Monné 	invlpg_handler();
26424f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
26524f7e474SRoger Pau Monné }
26624f7e474SRoger Pau Monné 
26724f7e474SRoger Pau Monné static int
26824f7e474SRoger Pau Monné xen_invlrng(void *arg)
26924f7e474SRoger Pau Monné {
27024f7e474SRoger Pau Monné 
27124f7e474SRoger Pau Monné 	invlrng_handler();
27224f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
27324f7e474SRoger Pau Monné }
27424f7e474SRoger Pau Monné 
27524f7e474SRoger Pau Monné static int
27624f7e474SRoger Pau Monné xen_invlcache(void *arg)
27724f7e474SRoger Pau Monné {
27824f7e474SRoger Pau Monné 
27924f7e474SRoger Pau Monné 	invlcache_handler();
28024f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
28124f7e474SRoger Pau Monné }
282dc43978aSKonstantin Belousov #endif /* __amd64__ */
28324f7e474SRoger Pau Monné 
28424f7e474SRoger Pau Monné static int
28524f7e474SRoger Pau Monné xen_cpustop_handler(void *arg)
28624f7e474SRoger Pau Monné {
28724f7e474SRoger Pau Monné 
28824f7e474SRoger Pau Monné 	cpustop_handler();
28924f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
29024f7e474SRoger Pau Monné }
29124f7e474SRoger Pau Monné 
29224f7e474SRoger Pau Monné static int
29324f7e474SRoger Pau Monné xen_cpususpend_handler(void *arg)
29424f7e474SRoger Pau Monné {
29524f7e474SRoger Pau Monné 
29624f7e474SRoger Pau Monné 	cpususpend_handler();
29724f7e474SRoger Pau Monné 	return (FILTER_HANDLED);
29824f7e474SRoger Pau Monné }
29924f7e474SRoger Pau Monné 
300aba10e13SAlexander Motin static int
301aba10e13SAlexander Motin xen_ipi_swi_handler(void *arg)
302aba10e13SAlexander Motin {
303aba10e13SAlexander Motin 	struct trapframe *frame = arg;
304aba10e13SAlexander Motin 
305aba10e13SAlexander Motin 	ipi_swi_handler(*frame);
306aba10e13SAlexander Motin 	return (FILTER_HANDLED);
307aba10e13SAlexander Motin }
308aba10e13SAlexander Motin 
30924f7e474SRoger Pau Monné /*----------------------------- XEN PV IPI setup -----------------------------*/
31024f7e474SRoger Pau Monné /*
31124f7e474SRoger Pau Monné  * Those functions are provided outside of the Xen PV APIC implementation
31224f7e474SRoger Pau Monné  * so PVHVM guests can also use PV IPIs without having an actual Xen PV APIC,
31324f7e474SRoger Pau Monné  * because on PVHVM there's an emulated LAPIC provided by Xen.
31424f7e474SRoger Pau Monné  */
31524f7e474SRoger Pau Monné static void
31624f7e474SRoger Pau Monné xen_cpu_ipi_init(int cpu)
31724f7e474SRoger Pau Monné {
31824f7e474SRoger Pau Monné 	xen_intr_handle_t *ipi_handle;
31924f7e474SRoger Pau Monné 	const struct xen_ipi_handler *ipi;
32024f7e474SRoger Pau Monné 	int idx, rc;
32124f7e474SRoger Pau Monné 
32224f7e474SRoger Pau Monné 	ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
32324f7e474SRoger Pau Monné 
32424f7e474SRoger Pau Monné 	for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
32524f7e474SRoger Pau Monné 		if (ipi->filter == NULL) {
32624f7e474SRoger Pau Monné 			ipi_handle[idx] = NULL;
32724f7e474SRoger Pau Monné 			continue;
32824f7e474SRoger Pau Monné 		}
32924f7e474SRoger Pau Monné 
330ca7af67aSRoger Pau Monné 		rc = xen_intr_alloc_and_bind_ipi(cpu, ipi->filter,
33124f7e474SRoger Pau Monné 		    INTR_TYPE_TTY, &ipi_handle[idx]);
33224f7e474SRoger Pau Monné 		if (rc != 0)
33324f7e474SRoger Pau Monné 			panic("Unable to allocate a XEN IPI port");
33424f7e474SRoger Pau Monné 		xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
33524f7e474SRoger Pau Monné 	}
33624f7e474SRoger Pau Monné }
33724f7e474SRoger Pau Monné 
33824f7e474SRoger Pau Monné static void
33924f7e474SRoger Pau Monné xen_setup_cpus(void)
34024f7e474SRoger Pau Monné {
3412450da67SRoger Pau Monné 	uint32_t regs[4];
34224f7e474SRoger Pau Monné 	int i;
34324f7e474SRoger Pau Monné 
34424f7e474SRoger Pau Monné 	if (!xen_vector_callback_enabled)
34524f7e474SRoger Pau Monné 		return;
34624f7e474SRoger Pau Monné 
3472450da67SRoger Pau Monné 	/*
3482450da67SRoger Pau Monné 	 * Check whether the APIC virtualization is hardware assisted, as
3492450da67SRoger Pau Monné 	 * that's faster than using event channels because it avoids the VM
3502450da67SRoger Pau Monné 	 * exit.
3512450da67SRoger Pau Monné 	 */
3522450da67SRoger Pau Monné 	KASSERT(xen_cpuid_base != 0, ("Invalid base Xen CPUID leaf"));
3532450da67SRoger Pau Monné 	cpuid_count(xen_cpuid_base + 4, 0, regs);
3542450da67SRoger Pau Monné 	if ((x2apic_mode && (regs[0] & XEN_HVM_CPUID_X2APIC_VIRT)) ||
3552450da67SRoger Pau Monné 	    (!x2apic_mode && (regs[0] & XEN_HVM_CPUID_APIC_ACCESS_VIRT)))
3562450da67SRoger Pau Monné 		return;
3572450da67SRoger Pau Monné 
35824f7e474SRoger Pau Monné 	CPU_FOREACH(i)
35924f7e474SRoger Pau Monné 		xen_cpu_ipi_init(i);
36024f7e474SRoger Pau Monné 
36124f7e474SRoger Pau Monné 	/* Set the xen pv ipi ops to replace the native ones */
362e0516c75SRoger Pau Monné 	ipi_vectored = xen_pv_lapic_ipi_vectored;
363e0516c75SRoger Pau Monné 	native_ipi_vectored = ipi_vectored;
36424f7e474SRoger Pau Monné }
36524f7e474SRoger Pau Monné 
366fae9a0cbSRoger Pau Monné /* Switch to using PV IPIs as soon as the vcpu_id is set. */
367fae9a0cbSRoger Pau Monné SYSINIT(xen_setup_cpus, SI_SUB_SMP, SI_ORDER_SECOND, xen_setup_cpus, NULL);
368