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/param.h>
2824f7e474SRoger Pau Monné #include <sys/bus.h>
2924f7e474SRoger Pau Monné #include <sys/kernel.h>
3024f7e474SRoger Pau Monné #include <sys/malloc.h>
3124f7e474SRoger Pau Monné #include <sys/proc.h>
3224f7e474SRoger Pau Monné #include <sys/smp.h>
3324f7e474SRoger Pau Monné #include <sys/systm.h>
3424f7e474SRoger Pau Monné
3524f7e474SRoger Pau Monné #include <vm/vm.h>
3624f7e474SRoger Pau Monné #include <vm/pmap.h>
3724f7e474SRoger Pau Monné
3824f7e474SRoger Pau Monné #include <machine/cpufunc.h>
3924f7e474SRoger Pau Monné #include <machine/cpu.h>
40fae92773SJohn Baldwin #include <machine/intr_machdep.h>
4145c228ccSKonstantin Belousov #include <machine/md_var.h>
4224f7e474SRoger Pau Monné #include <machine/smp.h>
4324f7e474SRoger Pau Monné
4424f7e474SRoger Pau Monné #include <x86/apicreg.h>
45fae92773SJohn Baldwin #include <x86/apicvar.h>
4624f7e474SRoger Pau Monné
4724f7e474SRoger Pau Monné #include <xen/xen-os.h>
4824f7e474SRoger Pau Monné #include <xen/features.h>
4924f7e474SRoger Pau Monné #include <xen/gnttab.h>
5024f7e474SRoger Pau Monné #include <xen/hypervisor.h>
5124f7e474SRoger Pau Monné #include <xen/hvm.h>
5224f7e474SRoger Pau Monné #include <xen/xen_intr.h>
5324f7e474SRoger Pau Monné
54ad7dd514SElliott Mitchell #include <contrib/xen/arch-x86/cpuid.h>
55ad7dd514SElliott Mitchell #include <contrib/xen/vcpu.h>
5624f7e474SRoger Pau Monné
5724f7e474SRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/
5824f7e474SRoger Pau Monné static driver_filter_t xen_smp_rendezvous_action;
59dc43978aSKonstantin Belousov #ifdef __amd64__
60dc43978aSKonstantin Belousov static driver_filter_t xen_invlop;
61dc43978aSKonstantin Belousov #else
6224f7e474SRoger Pau Monné static driver_filter_t xen_invltlb;
6324f7e474SRoger Pau Monné static driver_filter_t xen_invlpg;
6424f7e474SRoger Pau Monné static driver_filter_t xen_invlrng;
6524f7e474SRoger Pau Monné static driver_filter_t xen_invlcache;
66dc43978aSKonstantin Belousov #endif
6724f7e474SRoger Pau Monné static driver_filter_t xen_ipi_bitmap_handler;
6824f7e474SRoger Pau Monné static driver_filter_t xen_cpustop_handler;
6924f7e474SRoger Pau Monné static driver_filter_t xen_cpususpend_handler;
70aba10e13SAlexander Motin static driver_filter_t xen_ipi_swi_handler;
7124f7e474SRoger Pau Monné
7224f7e474SRoger Pau Monné /*---------------------------------- Macros ----------------------------------*/
7324f7e474SRoger Pau Monné #define IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
7424f7e474SRoger Pau Monné
7524f7e474SRoger Pau Monné /*--------------------------------- Xen IPIs ---------------------------------*/
7624f7e474SRoger Pau Monné struct xen_ipi_handler
7724f7e474SRoger Pau Monné {
7824f7e474SRoger Pau Monné driver_filter_t *filter;
7924f7e474SRoger Pau Monné const char *description;
8024f7e474SRoger Pau Monné };
8124f7e474SRoger Pau Monné
8224f7e474SRoger Pau Monné static struct xen_ipi_handler xen_ipis[] =
8324f7e474SRoger Pau Monné {
8424f7e474SRoger Pau Monné [IPI_TO_IDX(IPI_RENDEZVOUS)] = { xen_smp_rendezvous_action, "r" },
85dc43978aSKonstantin Belousov #ifdef __amd64__
86dc43978aSKonstantin Belousov [IPI_TO_IDX(IPI_INVLOP)] = { xen_invlop, "itlb"},
87dc43978aSKonstantin Belousov #else
8824f7e474SRoger Pau Monné [IPI_TO_IDX(IPI_INVLTLB)] = { xen_invltlb, "itlb"},
8924f7e474SRoger Pau Monné [IPI_TO_IDX(IPI_INVLPG)] = { xen_invlpg, "ipg" },
9024f7e474SRoger Pau Monné [IPI_TO_IDX(IPI_INVLRNG)] = { xen_invlrng, "irg" },
9124f7e474SRoger Pau Monné [IPI_TO_IDX(IPI_INVLCACHE)] = { xen_invlcache, "ic" },
92dc43978aSKonstantin Belousov #endif
9324f7e474SRoger Pau Monné [IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler, "b" },
9424f7e474SRoger Pau Monné [IPI_TO_IDX(IPI_STOP)] = { xen_cpustop_handler, "st" },
9524f7e474SRoger Pau Monné [IPI_TO_IDX(IPI_SUSPEND)] = { xen_cpususpend_handler, "sp" },
96aba10e13SAlexander Motin [IPI_TO_IDX(IPI_SWI)] = { xen_ipi_swi_handler, "sw" },
9724f7e474SRoger Pau Monné };
9824f7e474SRoger Pau Monné
99ad15eeeaSRoger Pau Monné /*
100ad15eeeaSRoger Pau Monné * Save previous (native) handler as a fallback. Xen < 4.7 doesn't support
101ad15eeeaSRoger Pau Monné * VCPUOP_send_nmi for HVM guests, and thus we need a fallback in that case:
102ad15eeeaSRoger Pau Monné *
103ad15eeeaSRoger Pau Monné * https://lists.freebsd.org/archives/freebsd-xen/2022-January/000032.html
104ad15eeeaSRoger Pau Monné */
105ad15eeeaSRoger Pau Monné void (*native_ipi_vectored)(u_int, int);
106ad15eeeaSRoger Pau Monné
10724f7e474SRoger Pau Monné /*------------------------------- Per-CPU Data -------------------------------*/
10824f7e474SRoger Pau Monné DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
10924f7e474SRoger Pau Monné
11024f7e474SRoger Pau Monné /*------------------------------- Xen PV APIC --------------------------------*/
11124f7e474SRoger Pau Monné
112b2802351SRoger Pau Monné #define PCPU_ID_GET(id, field) (pcpu_find(id)->pc_##field)
113ad15eeeaSRoger Pau Monné static int
send_nmi(int dest)114b2802351SRoger Pau Monné send_nmi(int dest)
115b2802351SRoger Pau Monné {
116b2802351SRoger Pau Monné unsigned int cpu;
117ad15eeeaSRoger Pau Monné int rc = 0;
118b2802351SRoger Pau Monné
119b2802351SRoger Pau Monné /*
120b2802351SRoger Pau Monné * NMIs are not routed over event channels, and instead delivered as on
121b2802351SRoger Pau Monné * native using the exception vector (#2). Triggering them can be done
122b2802351SRoger Pau Monné * using the local APIC, or an hypercall as a shortcut like it's done
123b2802351SRoger Pau Monné * below.
124b2802351SRoger Pau Monné */
125b2802351SRoger Pau Monné switch(dest) {
126b2802351SRoger Pau Monné case APIC_IPI_DEST_SELF:
127ad15eeeaSRoger Pau Monné rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi, PCPU_GET(vcpu_id), NULL);
128b2802351SRoger Pau Monné break;
129b2802351SRoger Pau Monné case APIC_IPI_DEST_ALL:
130ad15eeeaSRoger Pau Monné CPU_FOREACH(cpu) {
131ad15eeeaSRoger Pau Monné rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
132b2802351SRoger Pau Monné PCPU_ID_GET(cpu, vcpu_id), NULL);
133ad15eeeaSRoger Pau Monné if (rc != 0)
134ad15eeeaSRoger Pau Monné break;
135ad15eeeaSRoger Pau Monné }
136b2802351SRoger Pau Monné break;
137b2802351SRoger Pau Monné case APIC_IPI_DEST_OTHERS:
138ad15eeeaSRoger Pau Monné CPU_FOREACH(cpu) {
139ad15eeeaSRoger Pau Monné if (cpu != PCPU_GET(cpuid)) {
140ad15eeeaSRoger Pau Monné rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
141b2802351SRoger Pau Monné PCPU_ID_GET(cpu, vcpu_id), NULL);
142ad15eeeaSRoger Pau Monné if (rc != 0)
143ad15eeeaSRoger Pau Monné break;
144ad15eeeaSRoger Pau Monné }
145ad15eeeaSRoger Pau Monné }
146b2802351SRoger Pau Monné break;
147b2802351SRoger Pau Monné default:
148ad15eeeaSRoger Pau Monné rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi,
149b2802351SRoger Pau Monné PCPU_ID_GET(apic_cpuid(dest), vcpu_id), NULL);
150b2802351SRoger Pau Monné break;
151b2802351SRoger Pau Monné }
152ad15eeeaSRoger Pau Monné
153ad15eeeaSRoger Pau Monné return rc;
154b2802351SRoger Pau Monné }
155b2802351SRoger Pau Monné #undef PCPU_ID_GET
156b2802351SRoger Pau Monné
15724f7e474SRoger Pau Monné static void
xen_pv_lapic_ipi_vectored(u_int vector,int dest)15824f7e474SRoger Pau Monné xen_pv_lapic_ipi_vectored(u_int vector, int dest)
15924f7e474SRoger Pau Monné {
16024f7e474SRoger Pau Monné xen_intr_handle_t *ipi_handle;
16124f7e474SRoger Pau Monné int ipi_idx, to_cpu, self;
162ad15eeeaSRoger Pau Monné static bool pvnmi = true;
16324f7e474SRoger Pau Monné
164b2802351SRoger Pau Monné if (vector >= IPI_NMI_FIRST) {
165ad15eeeaSRoger Pau Monné if (pvnmi) {
166ad15eeeaSRoger Pau Monné int rc = send_nmi(dest);
167ad15eeeaSRoger Pau Monné
168ad15eeeaSRoger Pau Monné if (rc != 0) {
169ad15eeeaSRoger Pau Monné printf(
170ad15eeeaSRoger Pau Monné "Sending NMI using hypercall failed (%d) switching to APIC\n", rc);
171ad15eeeaSRoger Pau Monné pvnmi = false;
172ad15eeeaSRoger Pau Monné native_ipi_vectored(vector, dest);
173ad15eeeaSRoger Pau Monné }
174ad15eeeaSRoger Pau Monné } else
175ad15eeeaSRoger Pau Monné native_ipi_vectored(vector, dest);
176ad15eeeaSRoger Pau Monné
177b2802351SRoger Pau Monné return;
178b2802351SRoger Pau Monné }
179b2802351SRoger Pau Monné
18024f7e474SRoger Pau Monné ipi_idx = IPI_TO_IDX(vector);
1818114c8e1SRoger Pau Monné if (ipi_idx >= nitems(xen_ipis))
18224f7e474SRoger Pau Monné panic("IPI out of range");
18324f7e474SRoger Pau Monné
18424f7e474SRoger Pau Monné switch(dest) {
18524f7e474SRoger Pau Monné case APIC_IPI_DEST_SELF:
18624f7e474SRoger Pau Monné ipi_handle = DPCPU_GET(ipi_handle);
18724f7e474SRoger Pau Monné xen_intr_signal(ipi_handle[ipi_idx]);
18824f7e474SRoger Pau Monné break;
18924f7e474SRoger Pau Monné case APIC_IPI_DEST_ALL:
19024f7e474SRoger Pau Monné CPU_FOREACH(to_cpu) {
19124f7e474SRoger Pau Monné ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
19224f7e474SRoger Pau Monné xen_intr_signal(ipi_handle[ipi_idx]);
19324f7e474SRoger Pau Monné }
19424f7e474SRoger Pau Monné break;
19524f7e474SRoger Pau Monné case APIC_IPI_DEST_OTHERS:
19624f7e474SRoger Pau Monné self = PCPU_GET(cpuid);
19724f7e474SRoger Pau Monné CPU_FOREACH(to_cpu) {
19824f7e474SRoger Pau Monné if (to_cpu != self) {
19924f7e474SRoger Pau Monné ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
20024f7e474SRoger Pau Monné xen_intr_signal(ipi_handle[ipi_idx]);
20124f7e474SRoger Pau Monné }
20224f7e474SRoger Pau Monné }
20324f7e474SRoger Pau Monné break;
20424f7e474SRoger Pau Monné default:
20524f7e474SRoger Pau Monné to_cpu = apic_cpuid(dest);
20624f7e474SRoger Pau Monné ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
20724f7e474SRoger Pau Monné xen_intr_signal(ipi_handle[ipi_idx]);
20824f7e474SRoger Pau Monné break;
20924f7e474SRoger Pau Monné }
21024f7e474SRoger Pau Monné }
21124f7e474SRoger Pau Monné
21224f7e474SRoger Pau Monné /*---------------------------- XEN PV IPI Handlers ---------------------------*/
21324f7e474SRoger Pau Monné /*
21424f7e474SRoger Pau Monné * These are C clones of the ASM functions found in apic_vector.
21524f7e474SRoger Pau Monné */
21624f7e474SRoger Pau Monné static int
xen_ipi_bitmap_handler(void * arg)21724f7e474SRoger Pau Monné xen_ipi_bitmap_handler(void *arg)
21824f7e474SRoger Pau Monné {
21924f7e474SRoger Pau Monné
22054a0b720SElliott Mitchell ipi_bitmap_handler(*curthread->td_intr_frame);
22124f7e474SRoger Pau Monné return (FILTER_HANDLED);
22224f7e474SRoger Pau Monné }
22324f7e474SRoger Pau Monné
22424f7e474SRoger Pau Monné static int
xen_smp_rendezvous_action(void * arg)22524f7e474SRoger Pau Monné xen_smp_rendezvous_action(void *arg)
22624f7e474SRoger Pau Monné {
22724f7e474SRoger Pau Monné #ifdef COUNT_IPIS
22824f7e474SRoger Pau Monné (*ipi_rendezvous_counts[PCPU_GET(cpuid)])++;
22924f7e474SRoger Pau Monné #endif /* COUNT_IPIS */
23024f7e474SRoger Pau Monné
23124f7e474SRoger Pau Monné smp_rendezvous_action();
23224f7e474SRoger Pau Monné return (FILTER_HANDLED);
23324f7e474SRoger Pau Monné }
23424f7e474SRoger Pau Monné
235dc43978aSKonstantin Belousov #ifdef __amd64__
236dc43978aSKonstantin Belousov static int
xen_invlop(void * arg)237dc43978aSKonstantin Belousov xen_invlop(void *arg)
238dc43978aSKonstantin Belousov {
239dc43978aSKonstantin Belousov
240dc43978aSKonstantin Belousov invlop_handler();
241dc43978aSKonstantin Belousov return (FILTER_HANDLED);
242dc43978aSKonstantin Belousov }
243dc43978aSKonstantin Belousov
244dc43978aSKonstantin Belousov #else /* __i386__ */
245dc43978aSKonstantin Belousov
24624f7e474SRoger Pau Monné static int
xen_invltlb(void * arg)24724f7e474SRoger Pau Monné xen_invltlb(void *arg)
24824f7e474SRoger Pau Monné {
24924f7e474SRoger Pau Monné
25024f7e474SRoger Pau Monné invltlb_handler();
25124f7e474SRoger Pau Monné return (FILTER_HANDLED);
25224f7e474SRoger Pau Monné }
25324f7e474SRoger Pau Monné
25424f7e474SRoger Pau Monné static int
xen_invlpg(void * arg)25524f7e474SRoger Pau Monné xen_invlpg(void *arg)
25624f7e474SRoger Pau Monné {
25724f7e474SRoger Pau Monné
25824f7e474SRoger Pau Monné invlpg_handler();
25924f7e474SRoger Pau Monné return (FILTER_HANDLED);
26024f7e474SRoger Pau Monné }
26124f7e474SRoger Pau Monné
26224f7e474SRoger Pau Monné static int
xen_invlrng(void * arg)26324f7e474SRoger Pau Monné xen_invlrng(void *arg)
26424f7e474SRoger Pau Monné {
26524f7e474SRoger Pau Monné
26624f7e474SRoger Pau Monné invlrng_handler();
26724f7e474SRoger Pau Monné return (FILTER_HANDLED);
26824f7e474SRoger Pau Monné }
26924f7e474SRoger Pau Monné
27024f7e474SRoger Pau Monné static int
xen_invlcache(void * arg)27124f7e474SRoger Pau Monné xen_invlcache(void *arg)
27224f7e474SRoger Pau Monné {
27324f7e474SRoger Pau Monné
27424f7e474SRoger Pau Monné invlcache_handler();
27524f7e474SRoger Pau Monné return (FILTER_HANDLED);
27624f7e474SRoger Pau Monné }
277dc43978aSKonstantin Belousov #endif /* __amd64__ */
27824f7e474SRoger Pau Monné
27924f7e474SRoger Pau Monné static int
xen_cpustop_handler(void * arg)28024f7e474SRoger Pau Monné xen_cpustop_handler(void *arg)
28124f7e474SRoger Pau Monné {
28224f7e474SRoger Pau Monné
28324f7e474SRoger Pau Monné cpustop_handler();
28424f7e474SRoger Pau Monné return (FILTER_HANDLED);
28524f7e474SRoger Pau Monné }
28624f7e474SRoger Pau Monné
28724f7e474SRoger Pau Monné static int
xen_cpususpend_handler(void * arg)28824f7e474SRoger Pau Monné xen_cpususpend_handler(void *arg)
28924f7e474SRoger Pau Monné {
29024f7e474SRoger Pau Monné
29124f7e474SRoger Pau Monné cpususpend_handler();
29224f7e474SRoger Pau Monné return (FILTER_HANDLED);
29324f7e474SRoger Pau Monné }
29424f7e474SRoger Pau Monné
295aba10e13SAlexander Motin static int
xen_ipi_swi_handler(void * arg)296aba10e13SAlexander Motin xen_ipi_swi_handler(void *arg)
297aba10e13SAlexander Motin {
298aba10e13SAlexander Motin
29954a0b720SElliott Mitchell ipi_swi_handler(*curthread->td_intr_frame);
300aba10e13SAlexander Motin return (FILTER_HANDLED);
301aba10e13SAlexander Motin }
302aba10e13SAlexander Motin
30324f7e474SRoger Pau Monné /*----------------------------- XEN PV IPI setup -----------------------------*/
30424f7e474SRoger Pau Monné /*
30524f7e474SRoger Pau Monné * Those functions are provided outside of the Xen PV APIC implementation
30624f7e474SRoger Pau Monné * so PVHVM guests can also use PV IPIs without having an actual Xen PV APIC,
30724f7e474SRoger Pau Monné * because on PVHVM there's an emulated LAPIC provided by Xen.
30824f7e474SRoger Pau Monné */
30924f7e474SRoger Pau Monné static void
xen_cpu_ipi_init(int cpu)31024f7e474SRoger Pau Monné xen_cpu_ipi_init(int cpu)
31124f7e474SRoger Pau Monné {
31224f7e474SRoger Pau Monné xen_intr_handle_t *ipi_handle;
31324f7e474SRoger Pau Monné const struct xen_ipi_handler *ipi;
31424f7e474SRoger Pau Monné int idx, rc;
31524f7e474SRoger Pau Monné
31624f7e474SRoger Pau Monné ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
31724f7e474SRoger Pau Monné
31824f7e474SRoger Pau Monné for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
31924f7e474SRoger Pau Monné if (ipi->filter == NULL) {
32024f7e474SRoger Pau Monné ipi_handle[idx] = NULL;
32124f7e474SRoger Pau Monné continue;
32224f7e474SRoger Pau Monné }
32324f7e474SRoger Pau Monné
324ca7af67aSRoger Pau Monné rc = xen_intr_alloc_and_bind_ipi(cpu, ipi->filter,
32524f7e474SRoger Pau Monné INTR_TYPE_TTY, &ipi_handle[idx]);
32624f7e474SRoger Pau Monné if (rc != 0)
32724f7e474SRoger Pau Monné panic("Unable to allocate a XEN IPI port");
32824f7e474SRoger Pau Monné xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
32924f7e474SRoger Pau Monné }
33024f7e474SRoger Pau Monné }
33124f7e474SRoger Pau Monné
33224f7e474SRoger Pau Monné static void
xen_setup_cpus(void)33324f7e474SRoger Pau Monné xen_setup_cpus(void)
33424f7e474SRoger Pau Monné {
3352450da67SRoger Pau Monné uint32_t regs[4];
33624f7e474SRoger Pau Monné int i;
33724f7e474SRoger Pau Monné
33824f7e474SRoger Pau Monné if (!xen_vector_callback_enabled)
33924f7e474SRoger Pau Monné return;
34024f7e474SRoger Pau Monné
3412450da67SRoger Pau Monné /*
3422450da67SRoger Pau Monné * Check whether the APIC virtualization is hardware assisted, as
3432450da67SRoger Pau Monné * that's faster than using event channels because it avoids the VM
3442450da67SRoger Pau Monné * exit.
3452450da67SRoger Pau Monné */
346*f0cf86c0SRoger Pau Monné KASSERT(hv_base != 0, ("Invalid base Xen CPUID leaf"));
347*f0cf86c0SRoger Pau Monné cpuid_count(hv_base + 4, 0, regs);
3482450da67SRoger Pau Monné if ((x2apic_mode && (regs[0] & XEN_HVM_CPUID_X2APIC_VIRT)) ||
3492450da67SRoger Pau Monné (!x2apic_mode && (regs[0] & XEN_HVM_CPUID_APIC_ACCESS_VIRT)))
3502450da67SRoger Pau Monné return;
3512450da67SRoger Pau Monné
35224f7e474SRoger Pau Monné CPU_FOREACH(i)
35324f7e474SRoger Pau Monné xen_cpu_ipi_init(i);
35424f7e474SRoger Pau Monné
35524f7e474SRoger Pau Monné /* Set the xen pv ipi ops to replace the native ones */
356e0516c75SRoger Pau Monné ipi_vectored = xen_pv_lapic_ipi_vectored;
357e0516c75SRoger Pau Monné native_ipi_vectored = ipi_vectored;
35824f7e474SRoger Pau Monné }
35924f7e474SRoger Pau Monné
360fae9a0cbSRoger Pau Monné /* Switch to using PV IPIs as soon as the vcpu_id is set. */
361fae9a0cbSRoger Pau Monné SYSINIT(xen_setup_cpus, SI_SUB_SMP, SI_ORDER_SECOND, xen_setup_cpus, NULL);
362