Index: arm64/cpu.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/arm64/cpu.c,v diff -u -p -r1.141 cpu.c --- arm64/cpu.c 16 May 2025 01:29:27 -0000 1.141 +++ arm64/cpu.c 1 Jul 2025 05:16:49 -0000 @@ -1098,6 +1098,13 @@ cpu_identify(struct cpu_info *ci) sep = ","; } + if (ID_AA64PFR0_AMU(id) >= ID_AA64PFR0_AMU_IMPL) { + printf("%sAMU", sep); + if (ID_AA64PFR0_AMU(id) >= ID_AA64PFR0_AMU_IMPL_V1P1) + printf("v1p1"); + sep = ","; + } + if (ID_AA64PFR0_RAS(id) >= ID_AA64PFR0_RAS_IMPL) { printf("%sRAS", sep); if (ID_AA64PFR0_RAS(id) >= ID_AA64PFR0_RAS_IMPL_V1P1) Index: arm64/intr.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/arm64/intr.c,v diff -u -p -r1.32 intr.c --- arm64/intr.c 25 Apr 2025 12:48:48 -0000 1.32 +++ arm64/intr.c 1 Jul 2025 05:16:49 -0000 @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include @@ -937,3 +939,62 @@ arm_no_send_ipi(struct cpu_info *ci, int { panic("arm_send_ipi() called: no ipi function"); } + +/* + * cpu_xcall() implementation + */ + +void +#ifdef MULTIPROCESSOR +cpu_xcall_self(struct task *t) +#else +cpu_xcall(struct cpu_info *ci, struct task *t) +#endif +{ + int s = splsoftclock(); + (*t->t_func)(t->t_arg); + splx(s); +} + +#ifdef MULTIPROCESSOR +void +cpu_xcall(struct cpu_info *ci, struct task *t) +{ + size_t i; + + if (ci == curcpu()) { + /* execute the task immediately on the local cpu */ + cpu_xcall_self(t); + return; + } + + for (;;) { + for (i = 0; i < nitems(ci->ci_xcalls); i++) { + if (atomic_cas_ptr(&ci->ci_xcalls[i], NULL, t) != NULL) + continue; + + /* membar_producer(); */ + arm_send_ipi(ci, ARM_IPI_XCALL); + return; + } + + CPU_BUSY_CYCLE(); + } +} + +void +cpu_xcall_dispatch(void *arg) +{ + struct cpu_info *ci = arg; + struct task *t; + size_t i; + + for (i = 0; i < nitems(ci->ci_xcalls); i++) { + t = ci->ci_xcalls[i]; + if (t != NULL) { + ci->ci_xcalls[i] = NULL; + (*t->t_func)(t->t_arg); + } + } +} +#endif /* MULTIPROCESSOR */ Index: conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/GENERIC,v diff -u -p -r1.296 GENERIC --- conf/GENERIC 23 Jun 2025 18:42:52 -0000 1.296 +++ conf/GENERIC 1 Jul 2025 05:16:49 -0000 @@ -36,6 +36,7 @@ config bsd swap generic mainbus0 at root cpu0 at mainbus? apm0 at mainbus? +amu0 at mainbus? efi0 at mainbus? smbios0 at efi? acpi0 at mainbus? Index: conf/GENERIC.MP =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/GENERIC.MP,v diff -u -p -r1.5 GENERIC.MP --- conf/GENERIC.MP 1 Jul 2018 21:05:07 -0000 1.5 +++ conf/GENERIC.MP 1 Jul 2025 05:16:49 -0000 @@ -3,7 +3,7 @@ include "arch/arm64/conf/GENERIC" option MULTIPROCESSOR -#option MP_LOCKDEBUG +option MP_LOCKDEBUG #option WITNESS cpu* at mainbus? Index: conf/files.arm64 =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/files.arm64,v diff -u -p -r1.74 files.arm64 --- conf/files.arm64 7 Jun 2025 15:11:12 -0000 1.74 +++ conf/files.arm64 1 Jul 2025 05:16:49 -0000 @@ -290,3 +290,7 @@ device apm attach apm at mainbus file arch/arm64/dev/apm.c apm needs-flag file arch/arm64/arm64/acpiapm.c apm + +device amu +attach amu at mainbus +file arch/arm64/dev/amu.c amu needs-flag Index: dev/agintc.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/agintc.c,v diff -u -p -r1.62 agintc.c --- dev/agintc.c 24 Jan 2025 20:17:28 -0000 1.62 +++ dev/agintc.c 1 Jul 2025 05:16:49 -0000 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -182,9 +183,9 @@ struct agintc_softc { struct agintc_dmamem *sc_prop; struct agintc_dmamem *sc_pend; struct interrupt_controller sc_ic; - int sc_ipi_num[3]; /* id for each ipi */ + int sc_ipi_num; /* id for ipi */ int sc_ipi_reason[MAXCPUS]; /* cause of ipi */ - void *sc_ipi_irq[3]; /* irqhandle for each ipi */ + void *sc_ipi_irq; /* ipi irqhandle */ }; struct agintc_softc *agintc_sc; @@ -317,7 +318,7 @@ agintc_attach(struct device *parent, str int i, nbits, nintr; int idx, offset, nredist; #ifdef MULTIPROCESSOR - int nipi, ipiirq[3]; + int ipiirq; #endif psw = intr_disable(); @@ -600,13 +601,7 @@ agintc_attach(struct device *parent, str #ifdef MULTIPROCESSOR /* setup IPI interrupts */ - /* - * Ideally we want three IPI interrupts, one for NOP, one for - * DDB and one for HALT. However we can survive if only one - * is available; it is possible that most are not available to - * the non-secure OS. - */ - nipi = 0; + ipiirq = -1; for (i = 0; i < 16; i++) { int hwcpu = sc->sc_cpuremap[cpu_number()]; int reg, oldreg; @@ -625,56 +620,19 @@ agintc_attach(struct device *parent, str /* return to original value, will be set when used */ bus_space_write_1(sc->sc_iot, sc->sc_r_ioh[hwcpu], GICR_IPRIORITYR(i), oldreg); - - if (nipi == 0) - printf(" ipi: %d", i); - else - printf(", %d", i); - ipiirq[nipi++] = i; - if (nipi == 3) - break; + ipiirq = i; + break; } - if (nipi == 0) + if (ipiirq == -1) panic("no irq available for IPI"); - switch (nipi) { - case 1: - sc->sc_ipi_irq[0] = agintc_intr_establish(ipiirq[0], - IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL, - agintc_ipi_combined, sc, "ipi"); - sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0]; - sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[0]; - sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[0]; - break; - case 2: - sc->sc_ipi_irq[0] = agintc_intr_establish(ipiirq[0], - IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL, - agintc_ipi_nop, sc, "ipinop"); - sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0]; - sc->sc_ipi_irq[1] = agintc_intr_establish(ipiirq[1], - IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL, - agintc_ipi_combined, sc, "ipi"); - sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1]; - sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[1]; - break; - case 3: - sc->sc_ipi_irq[0] = agintc_intr_establish(ipiirq[0], - IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL, - agintc_ipi_nop, sc, "ipinop"); - sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0]; - sc->sc_ipi_irq[1] = agintc_intr_establish(ipiirq[1], - IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL, - agintc_ipi_ddb, sc, "ipiddb"); - sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1]; - sc->sc_ipi_irq[2] = agintc_intr_establish(ipiirq[2], - IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL, - agintc_ipi_halt, sc, "ipihalt"); - sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[2]; - break; - default: - panic("nipi unexpected number %d", nipi); - } + printf(" ipi: %d", ipiirq); + + sc->sc_ipi_irq = agintc_intr_establish(ipiirq, + IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL, + agintc_ipi_combined, sc, "ipi"); + sc->sc_ipi_num = ipiirq; intr_send_ipi_func = agintc_send_ipi; #endif @@ -764,12 +722,18 @@ void agintc_cpuinit(void) { struct agintc_softc *sc = agintc_sc; + struct cpu_info *ci = curcpu(); uint32_t waker; int timeout = 100000; int hwcpu; int i; - hwcpu = sc->sc_cpuremap[cpu_number()]; +#ifdef MULTIPROCESSOR + ci->ci_xcall_si = softintr_establish(IPL_SOFTCLOCK | IPL_MPSAFE, + cpu_xcall_dispatch, ci); +#endif + + hwcpu = sc->sc_cpuremap[ci->ci_cpuid]; waker = bus_space_read_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], GICR_WAKER); waker &= ~(GICR_WAKER_PROCESSORSLEEP); @@ -798,12 +762,8 @@ agintc_cpuinit(void) bus_space_write_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], GICR_IGRPMODR0, 0); - if (sc->sc_ipi_irq[0] != NULL) - agintc_route_irq(sc->sc_ipi_irq[0], IRQ_ENABLE, curcpu()); - if (sc->sc_ipi_irq[1] != NULL) - agintc_route_irq(sc->sc_ipi_irq[1], IRQ_ENABLE, curcpu()); - if (sc->sc_ipi_irq[2] != NULL) - agintc_route_irq(sc->sc_ipi_irq[2], IRQ_ENABLE, curcpu()); + if (sc->sc_ipi_irq != NULL) + agintc_route_irq(sc->sc_ipi_irq, IRQ_ENABLE, curcpu()); __asm volatile("msr "STR(ICC_PMR)", %x0" :: "r"(0xff)); __asm volatile("msr "STR(ICC_BPR1)", %x0" :: "r"(0)); @@ -1451,7 +1411,7 @@ agintc_ipi_halt(void *v) int old = curcpu()->ci_cpl; intr_disable(); - agintc_eoi(sc->sc_ipi_num[ARM_IPI_HALT]); + agintc_eoi(sc->sc_ipi_num); agintc_setipl(IPL_NONE); cpu_halt(); @@ -1472,37 +1432,42 @@ int agintc_ipi_combined(void *v) { struct agintc_softc *sc = v; + struct cpu_info *ci = curcpu(); + u_int reasons; - if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_DDB) { - sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP; - return agintc_ipi_ddb(v); - } else if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_HALT) { - sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP; - return agintc_ipi_halt(v); - } else { - return agintc_ipi_nop(v); + reasons = atomic_swap_uint(&sc->sc_ipi_reason[ci->ci_cpuid], 0); + if (reasons) { + if (ISSET(reasons, 1 << ARM_IPI_DDB)) + agintc_ipi_ddb(v); + if (ISSET(reasons, 1 << ARM_IPI_HALT)) + agintc_ipi_halt(v); + if (ISSET(reasons, 1 << ARM_IPI_XCALL)) + softintr_schedule(ci->ci_xcall_si); } + + return (1); } void -agintc_send_ipi(struct cpu_info *ci, int id) +agintc_send_ipi(struct cpu_info *ci, int reason) { struct agintc_softc *sc = agintc_sc; uint64_t sendmask; - if (ci == curcpu() && id == ARM_IPI_NOP) - return; - - /* never overwrite IPI_DDB or IPI_HALT with IPI_NOP */ - if (id == ARM_IPI_DDB || id == ARM_IPI_HALT) - sc->sc_ipi_reason[ci->ci_cpuid] = id; + if (reason == ARM_IPI_NOP) { + if (ci == curcpu()) + return; + } else { + atomic_setbits_int(&sc->sc_ipi_reason[ci->ci_cpuid], + 1 << reason); + } /* will only send 1 cpu */ sendmask = (ci->ci_mpidr & MPIDR_AFF3) << 16; sendmask |= (ci->ci_mpidr & MPIDR_AFF2) << 16; sendmask |= (ci->ci_mpidr & MPIDR_AFF1) << 8; sendmask |= 1 << (ci->ci_mpidr & 0x0f); - sendmask |= (sc->sc_ipi_num[id] << 24); + sendmask |= (sc->sc_ipi_num << 24); __asm volatile ("msr " STR(ICC_SGI1R)", %x0" ::"r"(sendmask)); } Index: dev/amu.c =================================================================== RCS file: dev/amu.c diff -N dev/amu.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/amu.c 1 Jul 2025 05:16:49 -0000 @@ -0,0 +1,193 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2025 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * ARM Activity Monitor Unit + */ + +#include "kstat.h" +#if NKSTAT == 0 +#error amu(4) requires kstat(4) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* CPU Identification */ +#define CPU_IMPL_ARM 0x41 +#define CPU_PART_ARM_NEOVERSE_N1 0xd0c + +#define CPU_IMPL(midr) (((midr) >> 24) & 0xff) +#define CPU_PART(midr) (((midr) >> 4) & 0xfff) +#define CPU_VAR(midr) (((midr) >> 20) & 0xf) +#define CPU_REV(midr) (((midr) >> 0) & 0xf) + +struct amu_softc { + struct device sc_dev; +}; + +#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) + +static int amu_match(struct device *, void *, void *); +static void amu_attach(struct device *, struct device *, void *); + +const struct cfattach amu_ca = { + sizeof(struct amu_softc), amu_match, amu_attach +}; + +struct cfdriver amu_cd = { + NULL, "amu", DV_DULL +}; + +static void amu_v0_attach(struct amu_softc *sc, + struct cpu_info *); + +static int +amu_match(struct device *parent, void *match, void *aux) +{ +// struct fdt_attach_args *faa = aux; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + CPU_INFO_FOREACH(cii, ci) { + if (CPU_IMPL(ci->ci_midr) == CPU_IMPL_ARM && + CPU_PART(ci->ci_midr) == CPU_PART_ARM_NEOVERSE_N1) + return (1); + } + + return (0); +} + +static void +amu_attach(struct device *parent, struct device *self, void *aux) +{ + struct amu_softc *sc = (struct amu_softc *)self; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + printf("\n"); + + CPU_INFO_FOREACH(cii, ci) { + if (CPU_IMPL(ci->ci_midr) == CPU_IMPL_ARM && + CPU_PART(ci->ci_midr) == CPU_PART_ARM_NEOVERSE_N1) { + sched_peg_curproc(ci); + amu_v0_attach(sc, ci); + } + } + + atomic_clearbits_int(&curproc->p_flag, P_CPUPEG); +} + +static const char *amu_v0_events[] = { + "core-cycles", + "constant-cycles", + "instr-retired", + "first-miss", + "high-activity", +}; + +struct amu_xcall { + struct kstat *ax_ks; + struct cond ax_c; +}; + +static void +amu_v0_read_xcall(void *arg) +{ + struct amu_xcall *ax = arg; + struct kstat *ks = ax->ax_ks; + struct kstat_kv *kvs = ks->ks_data; + unsigned long s; + + s = intr_disable(); + /* AMEVCNTR0_EL0 */ + kstat_kv_u64(&kvs[0]) = READ_SPECIALREG(s3_3_c15_c9_0); + /* AMEVCNTR1_EL0 */ + kstat_kv_u64(&kvs[1]) = READ_SPECIALREG(s3_3_c15_c9_1); + /* AMEVCNTR2_EL0 */ + kstat_kv_u64(&kvs[2]) = READ_SPECIALREG(s3_3_c15_c9_2); + /* AMEVCNTR3_EL0 */ + kstat_kv_u64(&kvs[3]) = READ_SPECIALREG(s3_3_c15_c9_3); + /* AMEVCNTR4_EL0 */ + kstat_kv_u64(&kvs[4]) = READ_SPECIALREG(s3_3_c15_c9_4); + nanouptime(&ks->ks_updated); + intr_restore(s); + + cond_signal(&ax->ax_c); +} + +static int +amu_v0_read(struct kstat *ks) +{ + struct timespec now, diff; + + getnanouptime(&now); + timespecsub(&now, &ks->ks_updated, &diff); + if (diff.tv_sec > 0 || diff.tv_nsec > 500000000) { + struct amu_xcall ax = { ks, COND_INITIALIZER() }; + struct task t = TASK_INITIALIZER(amu_v0_read_xcall, &ax); + + cpu_xcall(ks->ks_ptr, &t); + + cond_wait(&ax.ax_c, "amurd"); + } + + return (0); +} + +static void +amu_v0_attach(struct amu_softc *sc, struct cpu_info *ci) +{ + struct kstat *ks; + struct kstat_kv *kvs; + size_t i; + + ks = kstat_create(ci->ci_dev->dv_xname, 0, "amu", 0, KSTAT_T_KV, 0); + if (ks == NULL) { + printf("%s: unable to create %s amu kstats\n", DEVNAME(sc), + ci->ci_dev->dv_xname); + return; + } + + kvs = mallocarray(nitems(amu_v0_events), sizeof(*kvs), + M_DEVBUF, M_WAITOK|M_ZERO); + for (i = 0; i < nitems(amu_v0_events); i++) { + kstat_kv_init(&kvs[i], amu_v0_events[i], + KSTAT_KV_T_COUNTER64); + } + + ks->ks_data = kvs; + ks->ks_datalen = nitems(amu_v0_events) * sizeof(*kvs); + ks->ks_softc = sc; + ks->ks_ptr = ci; + ks->ks_read = amu_v0_read; + + kstat_install(ks); +} Index: dev/mainbus.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/mainbus.c,v diff -u -p -r1.32 mainbus.c --- dev/mainbus.c 18 Nov 2024 05:32:39 -0000 1.32 +++ dev/mainbus.c 1 Jul 2025 05:16:49 -0000 @@ -38,7 +38,8 @@ int mainbus_match_primary(struct device int mainbus_match_secondary(struct device *, void *, void *); void mainbus_attach_psci(struct device *); void mainbus_attach_efi(struct device *); -void mainbus_attach_apm(struct device *); +void mainbus_attach_subsystem(struct device *, const char *); +void mainbus_attach_late(struct device *); void mainbus_attach_framebuffer(struct device *); void mainbus_attach_firmware(struct device *); void mainbus_attach_resvmem(struct device *); @@ -147,7 +148,7 @@ mainbus_attach(struct device *parent, st sc->sc_rangeslen); } - mainbus_attach_apm(self); + mainbus_attach_subsystem(self, "apm"); /* Scan the whole tree. */ for (sc->sc_early = 2; sc->sc_early >= 0; sc->sc_early--) { @@ -156,13 +157,21 @@ mainbus_attach(struct device *parent, st } sc->sc_early = 0; + config_mountroot(self, mainbus_attach_late); + + thermal_init(); +} + +void +mainbus_attach_late(struct device *self) +{ /* * Delay attaching the framebuffer to give other drivers a * chance to claim it. */ - config_mountroot(self, mainbus_attach_framebuffer); + mainbus_attach_framebuffer(self); - thermal_init(); + mainbus_attach_subsystem(self, "amu"); } int @@ -399,15 +408,27 @@ mainbus_attach_efi(struct device *self) config_found(self, &fa, NULL); } -void -mainbus_attach_apm(struct device *self) +static int +mainbus_match_subsystem(struct device *parent, void *match, void *aux) { - struct fdt_attach_args fa; + struct cfdata *cf = match; + struct fdt_attach_args *fa = aux; - memset(&fa, 0, sizeof(fa)); - fa.fa_name = "apm"; + if (strcmp(cf->cf_driver->cd_name, fa->fa_name) == 0) + return cf->cf_attach->ca_match(parent, match, aux); - config_found(self, &fa, NULL); + return (0); +} + +void +mainbus_attach_subsystem(struct device *self, const char *name) +{ + struct fdt_attach_args fa = { .fa_name = name }; + void *match; + + match = config_search(mainbus_match_subsystem, self, &fa); + if (match != NULL) + config_attach(self, match, &fa, mainbus_print); } void Index: include/armreg.h =================================================================== RCS file: /cvs/src/sys/arch/arm64/include/armreg.h,v diff -u -p -r1.42 armreg.h --- include/armreg.h 11 Feb 2025 22:27:09 -0000 1.42 +++ include/armreg.h 1 Jul 2025 05:16:49 -0000 @@ -706,6 +706,7 @@ #define ID_AA64PFR0_AMU(x) ((x) & ID_AA64PFR0_AMU_MASK) #define ID_AA64PFR0_AMU_NONE (0x0ULL << ID_AA64PFR0_AMU_SHIFT) #define ID_AA64PFR0_AMU_IMPL (0x1ULL << ID_AA64PFR0_AMU_SHIFT) +#define ID_AA64PFR0_AMU_IMPL_V1P1 (0x2ULL << ID_AA64PFR0_AMU_SHIFT) #define ID_AA64PFR0_DIT_SHIFT 48 #define ID_AA64PFR0_DIT_MASK (0xfULL << ID_AA64PFR0_DIT_SHIFT) #define ID_AA64PFR0_DIT(x) ((x) & ID_AA64PFR0_DIT_MASK) Index: include/cpu.h =================================================================== RCS file: /cvs/src/sys/arch/arm64/include/cpu.h,v diff -u -p -r1.51 cpu.h --- include/cpu.h 11 Feb 2025 22:27:09 -0000 1.51 +++ include/cpu.h 1 Jul 2025 05:16:49 -0000 @@ -113,6 +113,8 @@ void cpu_identify_cleanup(void); #include #include +struct task; /* for xcalls */ + struct cpu_info { struct device *ci_dev; /* Device corresponding to this CPU */ struct cpu_info *ci_next; @@ -167,6 +169,8 @@ struct cpu_info { #ifdef MULTIPROCESSOR struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; + struct task *ci_xcalls[4]; + void *ci_xcall_si; #define __HAVE_UVM_PERCPU struct uvm_pmr_cache ci_uvm; volatile int ci_flags; Index: include/intr.h =================================================================== RCS file: /cvs/src/sys/arch/arm64/include/intr.h,v diff -u -p -r1.24 intr.h --- include/intr.h 25 Apr 2025 12:48:48 -0000 1.24 +++ include/intr.h 1 Jul 2025 05:16:49 -0000 @@ -201,6 +201,11 @@ extern void (*intr_send_ipi_func)(struct #define ARM_IPI_NOP 0 #define ARM_IPI_DDB 1 #define ARM_IPI_HALT 2 +#define ARM_IPI_XCALL 3 + +struct task; +void cpu_xcall(struct cpu_info *, struct task *); +void cpu_xcall_dispatch(void *); #ifdef DIAGNOSTIC /*