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