diff --git a/RELNOTES b/RELNOTES index 71dea5561ed6b6..a67ff596c62910 100644 --- a/RELNOTES +++ b/RELNOTES @@ -10,6 +10,21 @@ newline. Entries should be separated by a newline. Changes to this file should not be MFCed. +????????????: + Support for operation in Xen/ARM64 VMs was introduced. FreeBSD + has worked in x86 Xen VMs for more than a decade, but now FreeBSD + works in Xen's ARM64 VMs. Effort was made to keep the patches + architecture-independent, so support for Xen/RISC-V should appear + once Xen/RISC-V becomes viable. + + Tianocore/EDK2 for Xen/ARM is the presently known to work initial boot + stage. Build the ArmVirtXen.dsc configuration and configure XEN_EFI.fd + as the kernel to boot. + + Presently DomU operation has been implemented. Dom0 operation could + be implemented in the future. A sponsor could aid this, or CheriBSD + may get there first. + f57efe95cc25: New mididump(1) utility which dumps MIDI 1.0 events in real time. diff --git a/share/man/man4/xen.4 b/share/man/man4/xen.4 index 284b09bc87b705..34981d93be5453 100644 --- a/share/man/man4/xen.4 +++ b/share/man/man4/xen.4 @@ -26,7 +26,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 8, 2024 +.Dd January 23, 2024 .Dt XEN 4 .Os .Sh NAME @@ -136,3 +136,9 @@ This manual page was written by .An Robert Watson Aq Mt rwatson@FreeBSD.org , and .An Roger Pau Monné Aq Mt royger@FreeBSD.org . +A great deal of work since 2015 has been done by +.An Roger Pau Monné Aq Mt royger@FreeBSD.org . +Initial work on adding support for DomU support on ARM64 was done by +.An Julien Grall Aq Mt julien@xen.org . +ARM64 DomU support was completed in 2022 by +.An Elliott Mitchell . diff --git a/sys/amd64/include/xen/hypercall.h b/sys/amd64/include/xen/hypercall.h index 48d60e345983ea..09197b38f98108 100644 --- a/sys/amd64/include/xen/hypercall.h +++ b/sys/amd64/include/xen/hypercall.h @@ -39,8 +39,6 @@ #ifndef __MACHINE_XEN_HYPERCALL_H__ #define __MACHINE_XEN_HYPERCALL_H__ -#include - #ifndef __XEN_HYPERVISOR_H__ # error "please don't include this file directly" #endif @@ -164,227 +162,8 @@ HYPERVISOR_set_trap_table( return _hypercall1(int, set_trap_table, table); } -static inline int __must_check -HYPERVISOR_mmu_update( - mmu_update_t *req, unsigned int count, unsigned int *success_count, - domid_t domid) -{ - return _hypercall4(int, mmu_update, req, count, success_count, domid); -} - -static inline int __must_check -HYPERVISOR_mmuext_op( - struct mmuext_op *op, unsigned int count, unsigned int *success_count, - domid_t domid) -{ - return _hypercall4(int, mmuext_op, op, count, success_count, domid); -} - -static inline int __must_check -HYPERVISOR_set_gdt( - unsigned long *frame_list, unsigned int entries) -{ - return _hypercall2(int, set_gdt, frame_list, entries); -} - -static inline int __must_check -HYPERVISOR_stack_switch( - unsigned long ss, unsigned long esp) -{ - return _hypercall2(int, stack_switch, ss, esp); -} - -static inline int __must_check -HYPERVISOR_set_callbacks( - unsigned long event_address, unsigned long failsafe_address, - unsigned long syscall_address) -{ - return _hypercall3(int, set_callbacks, - event_address, failsafe_address, syscall_address); -} - -static inline int -HYPERVISOR_fpu_taskswitch( - int set) -{ - return _hypercall1(int, fpu_taskswitch, set); -} - -static inline int __must_check -HYPERVISOR_sched_op( - int cmd, void *arg) -{ - return _hypercall2(int, sched_op, cmd, arg); -} - -static inline long __must_check -HYPERVISOR_set_timer_op( - uint64_t timeout) -{ - return _hypercall1(long, set_timer_op, timeout); -} - -static inline int __must_check -HYPERVISOR_platform_op( - struct xen_platform_op *platform_op) -{ - platform_op->interface_version = XENPF_INTERFACE_VERSION; - return _hypercall1(int, platform_op, platform_op); -} - -static inline int __must_check -HYPERVISOR_set_debugreg( - unsigned int reg, unsigned long value) -{ - return _hypercall2(int, set_debugreg, reg, value); -} - -static inline unsigned long __must_check -HYPERVISOR_get_debugreg( - unsigned int reg) -{ - return _hypercall1(unsigned long, get_debugreg, reg); -} - -static inline int __must_check -HYPERVISOR_update_descriptor( - unsigned long ma, unsigned long word) -{ - return _hypercall2(int, update_descriptor, ma, word); -} - -static inline int __must_check -HYPERVISOR_memory_op( - unsigned int cmd, void *arg) -{ - return _hypercall2(int, memory_op, cmd, arg); -} - -static inline int __must_check -HYPERVISOR_multicall( - multicall_entry_t *call_list, unsigned int nr_calls) -{ - return _hypercall2(int, multicall, call_list, nr_calls); -} - -static inline int __must_check -HYPERVISOR_update_va_mapping( - unsigned long va, uint64_t new_val, unsigned long flags) -{ - return _hypercall3(int, update_va_mapping, va, new_val, flags); -} - -static inline int __must_check -HYPERVISOR_event_channel_op( - int cmd, void *arg) -{ - return _hypercall2(int, event_channel_op, cmd, arg); -} - -static inline int __must_check -HYPERVISOR_xen_version( - int cmd, void *arg) -{ - return _hypercall2(int, xen_version, cmd, arg); -} - -static inline int __must_check -HYPERVISOR_console_io( - int cmd, unsigned int count, const char *str) -{ - return _hypercall3(int, console_io, cmd, count, str); -} - -static inline int __must_check -HYPERVISOR_physdev_op( - int cmd, void *arg) -{ - return _hypercall2(int, physdev_op, cmd, arg); -} - -static inline int __must_check -HYPERVISOR_grant_table_op( - unsigned int cmd, void *uop, unsigned int count) -{ - return _hypercall3(int, grant_table_op, cmd, uop, count); -} - -static inline int __must_check -HYPERVISOR_update_va_mapping_otherdomain( - unsigned long va, uint64_t new_val, unsigned long flags, domid_t domid) -{ - return _hypercall4(int, update_va_mapping_otherdomain, va, - new_val, flags, domid); -} - -static inline int __must_check -HYPERVISOR_vm_assist( - unsigned int cmd, unsigned int type) -{ - return _hypercall2(int, vm_assist, cmd, type); -} - -static inline int __must_check -HYPERVISOR_vcpu_op( - int cmd, unsigned int vcpuid, void *extra_args) -{ - return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); -} - -static inline int __must_check -HYPERVISOR_set_segment_base( - int reg, unsigned long value) -{ - return _hypercall2(int, set_segment_base, reg, value); -} - -static inline int __must_check -HYPERVISOR_suspend( - unsigned long srec) -{ - struct sched_shutdown sched_shutdown = { - .reason = SHUTDOWN_suspend - }; - - return _hypercall3(int, sched_op, SCHEDOP_shutdown, - &sched_shutdown, srec); -} - -static inline unsigned long __must_check -HYPERVISOR_hvm_op( - int op, void *arg) -{ - return _hypercall2(unsigned long, hvm_op, op, arg); -} - -static inline int __must_check -HYPERVISOR_callback_op( - int cmd, const void *arg) -{ - return _hypercall2(int, callback_op, cmd, arg); -} - -static inline int __must_check -HYPERVISOR_xenoprof_op( - int op, void *arg) -{ - return _hypercall2(int, xenoprof_op, op, arg); -} - -static inline int __must_check -HYPERVISOR_kexec_op( - unsigned long op, void *args) -{ - return _hypercall2(int, kexec_op, op, args); -} - -static inline int __must_check -HYPERVISOR_dm_op( - domid_t domid, unsigned int nr_bufs, const void *bufs) -{ - return _hypercall3(int, dm_op, domid, nr_bufs, bufs); -} - #undef __must_check +#include + #endif /* __MACHINE_XEN_HYPERCALL_H__ */ diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c index b1b7aacd63abb2..887d99b79f98bc 100644 --- a/sys/arm/arm/gic.c +++ b/sys/arm/arm/gic.c @@ -205,6 +205,13 @@ arm_gic_init_secondary(device_t dev, uint32_t rootnum) struct arm_gic_softc *sc = device_get_softc(dev); u_int irq, cpu; + if (root_type >= INTR_ROOT_COUNT) { + /* + * Per-processor setup for devices with PPI interrupts? + */ + return; + } + /* Set the mask so we can find this CPU to send it IPIs */ cpu = PCPU_GET(cpuid); MPASS(cpu < GIC_MAXCPU); diff --git a/sys/arm/broadcom/bcm2835/bcm2836.c b/sys/arm/broadcom/bcm2835/bcm2836.c index 7ed9dedaa77ebb..57d79921d459d2 100644 --- a/sys/arm/broadcom/bcm2835/bcm2836.c +++ b/sys/arm/broadcom/bcm2835/bcm2836.c @@ -543,6 +543,13 @@ bcm_lintc_init_secondary(device_t dev, uint32_t rootnum) u_int cpu; struct bcm_lintc_softc *sc; + if (root_type >= INTR_ROOT_COUNT) { + /* + * Per-processor setup for devices with PPI interrupts? + */ + return; + } + cpu = PCPU_GET(cpuid); sc = device_get_softc(dev); diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c index 964a129111e274..bb63d8aef8186d 100644 --- a/sys/arm64/arm64/gic_v3.c +++ b/sys/arm64/arm64/gic_v3.c @@ -1103,6 +1103,13 @@ gic_v3_init_secondary(device_t dev, uint32_t rootnum) u_int cpu, irq; int err, i; + if (root_type >= INTR_ROOT_COUNT) { + /* + * Per-processor setup for devices with PPI interrupts? + */ + return; + } + sc = device_get_softc(dev); cpu = PCPU_GET(cpuid); diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c index 5ecd9b8c0e9496..e121d4cec56df1 100644 --- a/sys/arm64/arm64/gicv3_its.c +++ b/sys/arm64/arm64/gicv3_its.c @@ -1297,6 +1297,13 @@ gicv3_its_init_secondary(device_t dev, uint32_t rootnum) { struct gicv3_its_softc *sc; + if (root_type >= INTR_ROOT_COUNT) { + /* + * Per-processor setup for devices with PPI interrupts? + */ + return; + } + sc = device_get_softc(dev); /* diff --git a/sys/arm64/conf/LINT-ACPI b/sys/arm64/conf/LINT-ACPI index 306b7c4f0d4203..ea4662c617cb22 100644 --- a/sys/arm64/conf/LINT-ACPI +++ b/sys/arm64/conf/LINT-ACPI @@ -2,3 +2,9 @@ include "../../conf/NOTES" include NOTES nooptions FDT + +##################################################################### +# Items broken without FDT that are generally available elsewhere + +# Only presently available probe method uses device-trees +nooptions XENHVM diff --git a/sys/arm64/conf/LINT-FDT b/sys/arm64/conf/LINT-FDT index a6440ed76b6ca2..0c50f206c30ed7 100644 --- a/sys/arm64/conf/LINT-FDT +++ b/sys/arm64/conf/LINT-FDT @@ -2,3 +2,6 @@ include "../../conf/NOTES" include NOTES nodevice acpi + +##################################################################### +# Items broken without ACPI that are generally available elsewhere diff --git a/sys/arm64/conf/NOTES b/sys/arm64/conf/NOTES index b3bf2fedd5f7ca..de8a159c7f6a7b 100644 --- a/sys/arm64/conf/NOTES +++ b/sys/arm64/conf/NOTES @@ -66,6 +66,9 @@ device gve # Google Virtual NIC (gVNIC) driver # Microsoft Hyper-V device hyperv +# Xen HVM Guest support +options XENHVM # Xen HVM kernel infrastructure + # CPU frequency control device cpufreq diff --git a/sys/arm64/conf/std.virt b/sys/arm64/conf/std.virt index 8e64ce44f89b52..f3cb37021d5b44 100644 --- a/sys/arm64/conf/std.virt +++ b/sys/arm64/conf/std.virt @@ -2,6 +2,9 @@ # Virt SoC support # +# Xen HVM Guest support +options XENHVM # Xen HVM kernel infrastructure + # Block devices device pvscsi # VMware PVSCSI diff --git a/sys/arm64/include/xen/arch-intr.h b/sys/arm64/include/xen/arch-intr.h new file mode 120000 index 00000000000000..f42ad7eac3cb57 --- /dev/null +++ b/sys/arm64/include/xen/arch-intr.h @@ -0,0 +1 @@ +../../../dev/xen/intrng/arch-intr.h \ No newline at end of file diff --git a/sys/arm64/include/xen/hypercall.h b/sys/arm64/include/xen/hypercall.h new file mode 100644 index 00000000000000..9484ec15f7ed3e --- /dev/null +++ b/sys/arm64/include/xen/hypercall.h @@ -0,0 +1,166 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2022 Elliott Mitchell + * + * 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. + */ + +#ifndef __MACHINE_XEN_HYPERCALL_H__ +#define __MACHINE_XEN_HYPERCALL_H__ + +#ifndef __XEN_HYPERVISOR_H__ +# error "please don't include this file directly" +#endif + +/* + * See the Xen contrib header: xen/arch-arm.h for details on Xen's + * hypercall calling conventions. + * + * The hypercall number is passed in r12/x16. + * + * Input parameters are in r0-r4/x0-x4 as appropriate to the number of + * arguments. Input registers are clobbered. + * + * Return is in r0/x0. + * + * The hypercall tag for Xen is 0x0EA1. + */ + +#define hypercallf(NUM, ARGS, REGVAR, REGASM) \ + static inline register_t \ + ___xen_hypercall_##NUM(ARGS register_t op) \ + { \ + register register_t _op __asm__(OPREG) = op; \ + REGVAR \ + __asm__ volatile ( \ + "hvc #0x0EA1;\n" \ + : "+r" (_op)REGASM \ + : /* clobbered inputs, are outputs, really */ \ + : "memory" \ + ); \ + return (_arg0); \ + } + +#ifndef __ILP32__ +#define OPREG "x16" +#define REGPRE "x" +#else +#define OPREG "r12" +#define REGPRE "r" +#endif + +#define COMMAS(...) __VA_ARGS__ +#define ARG(n) register_t arg##n, +#define VAR(n) register register_t _arg##n __asm__(REGPRE __STRING(n)) = arg##n; +#define REG(n) , "+r" (_arg##n) + + +#define hypercall0(NUM, ARGS, REGVAR, REGASM) \ + hypercallf(NUM,, register register_t _arg0 __asm__(REGPRE"0");, \ + COMMAS(, "=r" (_arg0))) + +#define hypercall1(NUM, ARGS, REGVAR, REGASM) \ + hypercallf(NUM, COMMAS(ARG(0)ARGS), VAR(0)REGVAR, COMMAS(REG(0)REGASM)) + +#define hypercall2(NUM, ARGS, REGVAR, REGASM) \ + hypercall1(NUM, COMMAS(ARG(1)ARGS), VAR(1)REGVAR, COMMAS(REG(1)REGASM)) + +#define hypercall3(NUM, ARGS, REGVAR, REGASM) \ + hypercall2(NUM, COMMAS(ARG(2)ARGS), VAR(2)REGVAR, COMMAS(REG(2)REGASM)) + +#define hypercall4(NUM, ARGS, REGVAR, REGASM) \ + hypercall3(NUM, COMMAS(ARG(3)ARGS), VAR(3)REGVAR, COMMAS(REG(3)REGASM)) + +#define hypercall5(NUM, ARGS, REGVAR, REGASM) \ + hypercall4(NUM, COMMAS(ARG(4)ARGS), VAR(4)REGVAR, COMMAS(REG(4)REGASM)) + +#define hypercall(NUM) hypercall##NUM(NUM,,,) + +/* the actual inline function definitions */ + +hypercall(0) +hypercall(1) +hypercall(2) +hypercall(3) +hypercall(4) +hypercall(5) + +/* cleanup */ + +#undef hypercallf +#undef OPREG +#undef REGPRE +#undef COMMAS +#undef ARG +#undef VAR +#undef REG + +#undef hypercall0 +#undef hypercall1 +#undef hypercall2 +#undef hypercall3 +#undef hypercall4 +#undef hypercall + +/* the wrappers expected by hypercall.h */ + +/* + * The reasoning behind this is Xen/ARM wants the first argument in the first + * argument passing register, and the op code in a later register. As such the + * preprocessor is used to swap arguments with the goal of reducing argument + * shuffling in the resultant binary. + */ + +#define __xen_hypercall_0(op) ___xen_hypercall_0(op) +#define __xen_hypercall_1(op,a0) ___xen_hypercall_1(a0,op) +#define __xen_hypercall_2(op,a0,a1) ___xen_hypercall_2(a0,a1,op) +#define __xen_hypercall_3(op,a0,a1,a2) ___xen_hypercall_3(a0,a1,a2,op) +#define __xen_hypercall_4(op,a0,a1,a2,a3) ___xen_hypercall_4(a0,a1,a2,a3,op) +#define __xen_hypercall_5(op,a0,a1,a2,a3,a4) ___xen_hypercall_5(a0,a1,a2,a3,a4,op) + +/* the wrappers presently expected by hypercall.h */ + +#define _hypercall0(type, name) \ + (type)__xen_hypercall_0(__HYPERVISOR_##name) +#define _hypercall1(type, name, arg0) \ + (type)__xen_hypercall_1(__HYPERVISOR_##name, (register_t)(arg0)) +#define _hypercall2(type, name, arg0, arg1) \ + (type)__xen_hypercall_2(__HYPERVISOR_##name, (register_t)(arg0), \ + (register_t)(arg1)) +#define _hypercall3(type, name, arg0, arg1, arg2) \ + (type)__xen_hypercall_3(__HYPERVISOR_##name, (register_t)(arg0), \ + (register_t)(arg1), (register_t)(arg2)) +#define _hypercall4(type, name, arg0, arg1, arg2, arg3) \ + (type)__xen_hypercall_4(__HYPERVISOR_##name, (register_t)(arg0), \ + (register_t)(arg1), (register_t)(arg2), (register_t)(arg3)) +#define _hypercall5(type, name, arg0, arg1, arg2, arg3, arg4) \ + (type)__xen_hypercall_5(__HYPERVISOR_##name, (register_t)(arg0), \ + (register_t)(arg1), (register_t)(arg2), (register_t)(arg3), \ + (register_t)(arg4)) + +#define privcmd_hypercall(op, arg0, arg1, arg2, arg3, arg4) \ + (int)__xen_hypercall_5((op), (arg0), (arg1), (arg2), (arg3), (arg4)) + +#include + +#endif /* __MACHINE_XEN_HYPERCALL_H__ */ diff --git a/sys/arm64/include/xen/xen-os.h b/sys/arm64/include/xen/xen-os.h new file mode 120000 index 00000000000000..248b24b533e3e8 --- /dev/null +++ b/sys/arm64/include/xen/xen-os.h @@ -0,0 +1 @@ +../../../dev/xen/intrng/xen-os.h \ No newline at end of file diff --git a/sys/conf/files b/sys/conf/files index 7bf2cffe8b0979..89f0d09661b86e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3534,6 +3534,7 @@ dev/xen/control/control.c optional xenhvm dev/xen/cpu/xen_acpi_cpu.c optional xenhvm acpi dev/xen/efi/pvefi.c optional xenhvm xenefi efirt dev/xen/grant_table/grant_table.c optional xenhvm +dev/xen/intrng/xen_arch_intr.c optional xenhvm intrng fdt dev/xen/netback/netback.c optional xenhvm dev/xen/netfront/netfront.c optional xenhvm dev/xen/timer/xen_timer.c optional xenhvm xentimer diff --git a/sys/conf/options.arm64 b/sys/conf/options.arm64 index e36f856ecb04ad..d7e9ed825a28c5 100644 --- a/sys/conf/options.arm64 +++ b/sys/conf/options.arm64 @@ -4,6 +4,7 @@ INTRNG opt_global.h SOCDEV_PA opt_global.h THUNDERX_PASS_1_1_ERRATA opt_global.h VFP opt_global.h +XENHVM opt_global.h LINUX_BOOT_ABI opt_global.h LSE_ATOMICS opt_global.h diff --git a/sys/dev/xen/console/xen_console.c b/sys/dev/xen/console/xen_console.c index f1a298a2aefae6..f86492fad0c8fa 100644 --- a/sys/dev/xen/console/xen_console.c +++ b/sys/dev/xen/console/xen_console.c @@ -590,7 +590,8 @@ static void xencons_cnprobe(struct consdev *cp) { - if (!xen_domain()) + /* on some architectures Xen may not have been probed yet */ + if (!xen_domain_early()) return; cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; diff --git a/sys/dev/xen/intrng/arch-intr.h b/sys/dev/xen/intrng/arch-intr.h new file mode 100644 index 00000000000000..6890daa2ec396e --- /dev/null +++ b/sys/dev/xen/intrng/arch-intr.h @@ -0,0 +1,92 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2015 Julien Grall + * Copyright © 2021 Elliott Mitchell + * + * 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. + */ + +#ifndef _MACHINE__XEN_ARCH_INTR_H_ +#define _MACHINE__XEN_ARCH_INTR_H_ + +#include + +typedef struct intr_irqsrc xen_arch_isrc_t; + +#include + +/****************************** ARCH wrappers ********************************/ + +static inline void +xen_arch_intr_init(void) +{ + + /* Nothing to do */ +} + +extern struct xenisrc *_Nullable xen_arch_intr_alloc(void); +extern void xen_arch_intr_release(struct xenisrc *_Nonnull isrc); + +static inline u_int +xen_arch_intr_next_cpu(struct xenisrc *_Nonnull isrc) +{ + static u_int current = 0; + + return (current = intr_irq_next_cpu(current, &all_cpus)); +} + +u_long xen_arch_intr_execute_handlers(struct xenisrc *_Nonnull isrc, + struct trapframe *_Nullable frame); +int xen_arch_intr_add_handler(const char *_Nonnull name, + driver_filter_t filter, driver_intr_t handler, void *_Nullable arg, + enum intr_type flags, struct xenisrc *_Nonnull isrc, + void *_Nullable *_Nonnull cookiep); + +static inline int +xen_arch_intr_describe(struct xenisrc *_Nonnull isrc, void *_Nonnull cookie, + const char *_Nonnull descr) +{ + + return (intr_describe(&isrc->xi_arch, cookie, descr)); +} + +static inline int +xen_arch_intr_remove_handler(struct xenisrc *_Nonnull isrc, + void *_Nonnull cookie) +{ + int rc = intr_event_remove_handler(cookie); + + if (rc == 0) + --isrc->xi_arch.isrc_handlers; + return (rc); +} + +static inline int +xen_arch_intr_event_bind(struct xenisrc *_Nonnull isrc, u_int cpu) +{ + + MPASS(isrc->xi_arch.isrc_event != NULL); + return (intr_event_bind(isrc->xi_arch.isrc_event, cpu)); +} + +#endif /* _MACHINE__XEN_ARCH_INTR_H_ */ diff --git a/sys/dev/xen/intrng/xen-os.h b/sys/dev/xen/intrng/xen-os.h new file mode 100644 index 00000000000000..330a36fc8b0624 --- /dev/null +++ b/sys/dev/xen/intrng/xen-os.h @@ -0,0 +1,103 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2014 Julien Grall + * + * 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. + */ + +#ifndef __MACHINE_ARM64_XEN_XEN_OS_H__ +#define __MACHINE_ARM64_XEN_XEN_OS_H__ + +#ifndef _XEN_XEN_OS_H_ +#error "do not #include machine/xen/xen-os.h, #include xen/xen-os.h instead" +#endif + +/* Xen/ARM *requires* write-back/cached, so this is the correct setting */ +#define VM_MEMATTR_XEN VM_MEMATTR_WRITE_BACK + +#ifndef __ASSEMBLY__ + +/* Right now the device-tree is the only implemented detection method */ +#define xen_domain_early() xen_dt_probe() + +/* Early initializer, returns success/failure identical to xen_domain() */ +extern int xen_dt_probe(void); + +/* compatibility for accessing xen_ulong_t with atomics */ + +#define atomic_clear_xen_ulong atomic_clear_64 +#define atomic_set_xen_ulong atomic_set_64 +#define atomic_testandset_xen_ulong atomic_testandset_64 +#define atomic_readandclear_xen_ulong atomic_readandclear_64 +#define atomic_load_acq_xen_ulong atomic_load_acq_64 +#define atomic_store_rel_xen_ulong atomic_store_rel_64 +#define atomic_set_xen_ulong atomic_set_64 +#define atomic_clear_xen_ulong atomic_clear_64 + +#define XEN_CPUID_TO_VCPUID(cpu) (cpu) + +#define XEN_VCPUID() PCPU_GET(cpuid) + +static inline bool +xen_pv_shutdown_handler(void) +{ + + /* PV shutdown handler are always supported on ARM */ + return (true); +} + +static inline bool +xen_has_percpu_evtchn(void) +{ + + /* It's always possible to rebind event channel on ARM */ + return (true); +} + +static inline bool +xen_pv_disks_disabled(void) +{ + + /* It's not possible to disable PV disks on ARM */ + return (false); +} + +static inline bool +xen_pv_nics_disabled(void) +{ + + /* It's not possible to disable PV nics on ARM */ + return (false); +} + +static inline bool +xen_has_iommu_maps(void) +{ + + /* the Xen bug predates ARM support */ + return (true); +} + +#endif + +#endif /* __MACHINE_ARM64_XEN_XEN_OS__ */ diff --git a/sys/dev/xen/intrng/xen_arch_intr.c b/sys/dev/xen/intrng/xen_arch_intr.c new file mode 100644 index 00000000000000..1f08cf134c2fa2 --- /dev/null +++ b/sys/dev/xen/intrng/xen_arch_intr.c @@ -0,0 +1,397 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2014,2015 Julien Grall + * Copyright © 2021,2022 Elliott Mitchell + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "pic_if.h" + +int +xen_dt_probe(void) +{ + /* + * Short-circuit extra attempts at looking for Xen + */ + if (xen_domain()) + return (1); + + /* + * The device tree contains the node /hypervisor with the compatible + * string "xen,xen" when the OS will run on top of Xen. + */ + if (ofw_bus_node_is_compatible(OF_finddevice("/hypervisor"), "xen,xen") == 0) + return (0); + + vm_guest = VM_GUEST_XEN; + setup_xen_features(); + + if (xen_feature(XENFEAT_dom0)) + hvm_start_flags |= SIF_INITDOMAIN | SIF_PRIVILEGED; + + return (1); +} + +/* in case of console being disabled, probe again as a fallback */ +C_SYSINIT(xen_probe_fdt, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, (sysinit_cfunc_t)xen_dt_probe, NULL); + +static void +xen_map_shared_info(void) +{ + int rc; + struct xen_add_to_physmap xatp; + vm_page_t shared_info; + vm_paddr_t shared_paddr; + + if (!xen_domain()) + return; + + shared_info = vm_page_alloc_noobj(VM_ALLOC_ZERO | VM_ALLOC_WIRED | + VM_ALLOC_WAITFAIL); + KASSERT(shared_info != NULL, ("Unable to allocate shared page\n")); + shared_paddr = VM_PAGE_TO_PHYS(shared_info); + HYPERVISOR_shared_info = pmap_mapdev_attr(shared_paddr, PAGE_SIZE, + VM_MEMATTR_XEN); + + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = shared_paddr >> PAGE_SHIFT; + rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); + if (rc != 0) + panic("Unable to map shared info error=%d\n", rc); +} + +/* xen_map_shared_info() won't work during console probe, thus this */ +C_SYSINIT(xen_shared_info, SI_SUB_HYPERVISOR, SI_ORDER_SECOND, + (sysinit_cfunc_t)xen_map_shared_info, NULL); + +struct xen_softc { + struct resource *intr; + void *cookie; + int rid; + device_t dev; + struct intr_pic *pic; + struct { + int rid; + struct resource *res; + } regions[8]; +}; + +struct xen_softc *xen_sc = NULL; + +static int +xen_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "xen,xen")) + return (ENXIO); + + device_set_desc(dev, "Xen ARM device-tree"); + + return (BUS_PROBE_DEFAULT); +} + +static int +xen_attach(device_t dev) +{ + struct xen_softc *sc; + u_int i; + + if (xen_sc != NULL) + return (ENXIO); + + sc = device_get_softc(dev); + + sc->dev = dev; + + sc->pic = intr_pic_register(dev, + OF_xref_from_node(ofw_bus_get_node(dev))); + if (sc->pic == NULL) + return (ENXIO); + + /* setup vCPU #0 so events work on first processor */ + xen_setup_vcpu_info(); + + + /* Resources */ + sc->rid = 0; + sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid, RF_ACTIVE); + if (sc->intr == NULL) { + panic("Unable to retrieve Xen event channel interrupt"); + return (ENXIO); + } + + xen_sc = sc; + + /* Setup and enable the event channel interrupt */ + if (bus_setup_intr(dev, sc->intr, INTR_TYPE_MISC|INTR_MPSAFE, + xen_intr_handle_upcall, NULL, sc, &sc->cookie)) { + panic("Could not setup event channel interrupt"); + return (ENXIO); + } + + /* Allocate memory regions for grant-table/foreign mappings */ + for (i = 0; i < nitems(sc->regions); ++i) { + sc->regions[i].rid = i; + sc->regions[i].res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->regions[i].rid, RF_ACTIVE | RF_UNMAPPED); + if (sc->regions[i].res == NULL) + break; + } + + if (sc->regions[nitems(sc->regions) - 1].res != NULL) + device_printf(dev, "NOTICE: memory region list exhausted!\n"); + + return (0); +} + +int +xen_arch_init_physmem(device_t dev, struct rman *mem) +{ + u_int i; + int error; + + for (i = 0; i < nitems(xen_sc->regions) && + xen_sc->regions[i].res != NULL; ++i) { + + if (bootverbose != 0) + device_printf(dev, + "scratch mapping region @ [%#lx, %#lx]\n", + rman_get_start(xen_sc->regions[i].res), + rman_get_end(xen_sc->regions[i].res)); + + error = rman_manage_region(mem, + rman_get_start(xen_sc->regions[i].res), + rman_get_end(xen_sc->regions[i].res)); + if (error != 0) + device_printf(dev, + "unable to add scratch region [%#lx, %#lx]: %d\n", + rman_get_start(xen_sc->regions[i].res), + rman_get_end(xen_sc->regions[i].res), error); + } + + return (0); +} + +static void +xen_intrng_intr_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + + xen_intr_disable_intr((struct xenisrc *)isrc); +} + +static void +xen_intrng_intr_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + + xen_intr_enable_intr((struct xenisrc *)isrc); +} + +static void +xen_intrng_intr_post_filter(device_t dev, struct intr_irqsrc *isrc) +{ + + /* should only clear the port now, but oh well for the moment */ +} + +static void +xen_intrng_intr_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + xen_intr_disable_source((struct xenisrc *)isrc); +} + +static void +xen_intrng_intr_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + xen_intr_enable_source((struct xenisrc *)isrc); +} + +static int +xen_intrng_intr_bind(device_t dev, struct intr_irqsrc *isrc) +{ + struct xenisrc *xsrc = (struct xenisrc *)isrc; + u_int cpu; + + /* distinctly inspired by sys/arm64/arm64/gic_v3.c:gic_v3_bind_intr() */ + if (CPU_EMPTY(&isrc->isrc_cpu)) { + cpu = xen_arch_intr_next_cpu(xsrc); + CPU_SETOF(cpu, &isrc->isrc_cpu); + } else + /* INTRNG wants the PIC to choose the processor?! */ + cpu = xen_arch_intr_next_cpu(xsrc); + + return (xen_intr_assign_cpu(xsrc, cpu)); +} + +static device_method_t xen_methods[] = { + DEVMETHOD(device_probe, xen_probe), + DEVMETHOD(device_attach, xen_attach), + + /* Interrupt controller interface */ + DEVMETHOD(pic_init_secondary, (pic_init_secondary_t *)xen_setup_vcpu_info), + DEVMETHOD(pic_disable_intr, xen_intrng_intr_disable_intr), + DEVMETHOD(pic_enable_intr, xen_intrng_intr_enable_intr), + DEVMETHOD(pic_post_filter, xen_intrng_intr_post_filter), + DEVMETHOD(pic_pre_ithread, xen_intrng_intr_pre_ithread), + DEVMETHOD(pic_post_ithread, xen_intrng_intr_post_ithread), + DEVMETHOD(pic_bind_intr, xen_intrng_intr_bind), + + DEVMETHOD_END +}; + +static driver_t xen_driver = { + "xen", + xen_methods, + sizeof(struct xen_softc), +}; + +DRIVER_MODULE(xen, ofwbus, xen_driver, 0, 0); + + + + + + + + +static MALLOC_DEFINE(M_XENINTR, "xen_intr", "Xen Interrupt Services"); + +struct xenisrc * +xen_arch_intr_alloc(void) +{ + static u_int counter = 0; + struct xenisrc *isrc; + int error; + + if (!(isrc = malloc(sizeof(struct xenisrc), M_XENINTR, M_WAITOK | M_ZERO))) + return (NULL); + + error = intr_isrc_register(&isrc->xi_arch, xen_sc->dev, 0, "xen%u", + ++counter); + + if (error) { + free(isrc, M_XENINTR); + isrc = NULL; + } + + return (isrc); +} + +void +xen_arch_intr_release(struct xenisrc *isrc) +{ + int error; + + KASSERT(isrc->xi_arch.isrc_event == NULL || + CK_SLIST_EMPTY(&isrc->xi_arch.isrc_event->ie_handlers), + ("Release called, but xenisrc still in use")); + + if ((error = intr_isrc_deregister(&isrc->xi_arch)) != 0) + printf("%s(): leaking isrc due to failure during release: %d", + __func__, error); + else + free(isrc, M_XENINTR); +} + +u_long +xen_arch_intr_execute_handlers(struct xenisrc *isrc, struct trapframe *frame) +{ + u_long strays; + + strays = intr_isrc_dispatch(&isrc->xi_arch, frame); + if (strays != 0) { + xen_intr_disable_source(isrc); + if (strays < INTR_STRAY_LOG_MAX) + log(LOG_ERR, "stray evtchn %u: (%lu seen)\n", + isrc->xi_port, strays); + else if (strays == INTR_STRAY_LOG_MAX) + log(LOG_CRIT, + "too many stray evtchn %u: not logging anymore\n", + isrc->xi_port); + } + return (strays); +} + +int +xen_arch_intr_add_handler(const char *name, driver_filter_t filter, + driver_intr_t handler, void *arg, enum intr_type flags, + struct xenisrc *isrc, void **cookiep) +{ + int error; + + error = intr_add_handler(&isrc->xi_arch, name, filter, handler, arg, + flags, cookiep); + if (error != 0) + return (error); + + ++isrc->xi_arch.isrc_handlers; + + /* Enable the event channel */ + xen_intr_enable_intr(isrc); + xen_intr_enable_source(isrc); + + return (0); +} diff --git a/sys/i386/include/xen/hypercall.h b/sys/i386/include/xen/hypercall.h index 2a8b36f0f7cd14..f39e66c26262d4 100644 --- a/sys/i386/include/xen/hypercall.h +++ b/sys/i386/include/xen/hypercall.h @@ -29,12 +29,12 @@ * IN THE SOFTWARE. */ -#ifndef __HYPERCALL_H__ -#define __HYPERCALL_H__ +#ifndef __MACHINE_XEN_HYPERCALL_H__ +#define __MACHINE_XEN_HYPERCALL_H__ -#include -#include -#include +#ifndef __XEN_HYPERVISOR_H__ +# error "please don't include this file directly" +#endif extern char *hypercall_page; @@ -145,239 +145,6 @@ HYPERVISOR_set_trap_table( return _hypercall1(int, set_trap_table, table); } -static inline int -HYPERVISOR_mmu_update( - mmu_update_t *req, int count, int *success_count, domid_t domid) -{ - return _hypercall4(int, mmu_update, req, count, success_count, domid); -} - -static inline int -HYPERVISOR_mmuext_op( - mmuext_op_t *op, int count, int *success_count, domid_t domid) -{ - return _hypercall4(int, mmuext_op, op, count, success_count, domid); -} - -static inline int -HYPERVISOR_set_gdt( - unsigned long *frame_list, int entries) -{ - return _hypercall2(int, set_gdt, frame_list, entries); -} - -static inline int -HYPERVISOR_stack_switch( - unsigned long ss, unsigned long esp) -{ - return _hypercall2(int, stack_switch, ss, esp); -} - -static inline int -HYPERVISOR_set_callbacks( - unsigned long event_selector, unsigned long event_address, - unsigned long failsafe_selector, unsigned long failsafe_address) -{ - return _hypercall4(int, set_callbacks, - event_selector, event_address, - failsafe_selector, failsafe_address); -} - -static inline int -HYPERVISOR_fpu_taskswitch( - int set) -{ - return _hypercall1(int, fpu_taskswitch, set); -} - -static inline int -HYPERVISOR_sched_op( - int cmd, void *arg) -{ - return _hypercall2(int, sched_op, cmd, arg); -} - -static inline long -HYPERVISOR_set_timer_op( - uint64_t timeout) -{ - unsigned long timeout_hi = (unsigned long)(timeout>>32); - unsigned long timeout_lo = (unsigned long)timeout; - return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); -} - -static inline int -HYPERVISOR_platform_op( - struct xen_platform_op *platform_op) -{ - platform_op->interface_version = XENPF_INTERFACE_VERSION; - return _hypercall1(int, platform_op, platform_op); -} - -static inline int -HYPERVISOR_set_debugreg( - int reg, unsigned long value) -{ - return _hypercall2(int, set_debugreg, reg, value); -} - -static inline unsigned long -HYPERVISOR_get_debugreg( - int reg) -{ - return _hypercall1(unsigned long, get_debugreg, reg); -} - -static inline int -HYPERVISOR_update_descriptor( - uint64_t ma, uint64_t desc) -{ - return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32); -} - -static inline int -HYPERVISOR_memory_op( - unsigned int cmd, void *arg) -{ - return _hypercall2(int, memory_op, cmd, arg); -} - -static inline int -HYPERVISOR_multicall( - void *call_list, int nr_calls) -{ - return _hypercall2(int, multicall, call_list, nr_calls); -} - -static inline int -HYPERVISOR_update_va_mapping( - unsigned long va, uint64_t new_val, unsigned long flags) -{ - uint32_t hi, lo; - - lo = (uint32_t)(new_val & 0xffffffff); - hi = (uint32_t)(new_val >> 32); - - return _hypercall4(int, update_va_mapping, va, - lo, hi, flags); -} +#include -static inline int -HYPERVISOR_event_channel_op( - int cmd, void *arg) -{ - return _hypercall2(int, event_channel_op, cmd, arg); -} - -static inline int -HYPERVISOR_xen_version( - int cmd, void *arg) -{ - return _hypercall2(int, xen_version, cmd, arg); -} - -static inline int -HYPERVISOR_console_io( - int cmd, int count, const char *str) -{ - return _hypercall3(int, console_io, cmd, count, str); -} - -static inline int -HYPERVISOR_physdev_op( - int cmd, void *arg) -{ - return _hypercall2(int, physdev_op, cmd, arg); -} - -static inline int -HYPERVISOR_grant_table_op( - unsigned int cmd, void *uop, unsigned int count) -{ - return _hypercall3(int, grant_table_op, cmd, uop, count); -} - -static inline int -HYPERVISOR_update_va_mapping_otherdomain( - unsigned long va, uint64_t new_val, unsigned long flags, domid_t domid) -{ - uint32_t hi, lo; - - lo = (uint32_t)(new_val & 0xffffffff); - hi = (uint32_t)(new_val >> 32); - - return _hypercall5(int, update_va_mapping_otherdomain, va, - lo, hi, flags, domid); -} - -static inline int -HYPERVISOR_vm_assist( - unsigned int cmd, unsigned int type) -{ - return _hypercall2(int, vm_assist, cmd, type); -} - -static inline int -HYPERVISOR_vcpu_op( - int cmd, int vcpuid, void *extra_args) -{ - return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); -} - -static inline int -HYPERVISOR_suspend( - unsigned long srec) -{ - struct sched_shutdown sched_shutdown = { - .reason = SHUTDOWN_suspend - }; - - return _hypercall3(int, sched_op, SCHEDOP_shutdown, - &sched_shutdown, srec); -} - -static inline int -HYPERVISOR_callback_op( - int cmd, void *arg) -{ - return _hypercall2(int, callback_op, cmd, arg); -} - -static inline unsigned long -HYPERVISOR_hvm_op( - int op, void *arg) -{ - return _hypercall2(unsigned long, hvm_op, op, arg); -} - -static inline int -HYPERVISOR_xenoprof_op( - int op, void *arg) -{ - return _hypercall2(int, xenoprof_op, op, arg); -} - -static inline int -HYPERVISOR_kexec_op( - unsigned long op, void *args) -{ - return _hypercall2(int, kexec_op, op, args); -} - -static inline int -HYPERVISOR_dm_op( - domid_t domid, unsigned int nr_bufs, const void *bufs) -{ - return _hypercall3(int, dm_op, domid, nr_bufs, bufs); -} -#endif /* __HYPERCALL_H__ */ - -/* - * Local variables: - * c-file-style: "linux" - * indent-tabs-mode: t - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ +#endif /* __MACHINE_XEN_HYPERCALL_H__ */ diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c index b8d85bf20f289b..37d240e7677f42 100644 --- a/sys/kern/subr_intr.c +++ b/sys/kern/subr_intr.c @@ -413,16 +413,120 @@ intr_isrc_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf) return (0); } else #endif - if (isrc->isrc_event != NULL) { - if (intr_event_handle(isrc->isrc_event, tf) == 0) - return (0); - } + if (intr_event_handle(isrc->isrc_event, tf) == 0) + return (0); if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0) isrc_increment_straycount(isrc); return (EINVAL); } +/* + * Interrupt source pre_ithread method for MI interrupt framework. + */ +static void +intr_isrc_pre_ithread(void *arg) +{ + struct intr_irqsrc *isrc = arg; + + PIC_PRE_ITHREAD(isrc->isrc_dev, isrc); +} + +/* + * Interrupt source post_ithread method for MI interrupt framework. + */ +static void +intr_isrc_post_ithread(void *arg) +{ + struct intr_irqsrc *isrc = arg; + + PIC_POST_ITHREAD(isrc->isrc_dev, isrc); +} + +/* + * Interrupt source post_filter method for MI interrupt framework. + */ +static void +intr_isrc_post_filter(void *arg) +{ + struct intr_irqsrc *isrc = arg; + + PIC_POST_FILTER(isrc->isrc_dev, isrc); +} + +/* + * Interrupt source assign_cpu method for MI interrupt framework. + */ +static int +intr_isrc_assign_cpu(void *arg, int cpu) +{ +#ifdef SMP + struct intr_irqsrc *isrc = arg; + int error; + + mtx_lock(&isrc_table_lock); + if (cpu == NOCPU) { + CPU_ZERO(&isrc->isrc_cpu); + isrc->isrc_flags &= ~INTR_ISRCF_BOUND; + } else { + CPU_SETOF(cpu, &isrc->isrc_cpu); + isrc->isrc_flags |= INTR_ISRCF_BOUND; + } + + /* + * In NOCPU case, it's up to PIC to either leave ISRC on same CPU or + * re-balance it to another CPU or enable it on more CPUs. However, + * PIC is expected to change isrc_cpu appropriately to keep us well + * informed if the call is successful. + */ + if (irq_assign_cpu) { + error = PIC_BIND_INTR(isrc->isrc_dev, isrc); + if (error) { + CPU_ZERO(&isrc->isrc_cpu); + mtx_unlock(&isrc_table_lock); + return (error); + } + } + mtx_unlock(&isrc_table_lock); + return (0); +#else + return (EOPNOTSUPP); +#endif +} + +/* + * Create interrupt event for interrupt source. + */ +static int +isrc_event_create(struct intr_irqsrc *isrc) +{ + int error; + + error = intr_event_create(&isrc->isrc_event, isrc, 0, INTR_IRQ_INVALID, + intr_isrc_pre_ithread, intr_isrc_post_ithread, intr_isrc_post_filter, + intr_isrc_assign_cpu, "%s:", isrc->isrc_name); + + return (error); +} + +/* + * Destroy interrupt event for interrupt source. + */ +static int +isrc_event_destroy(struct intr_irqsrc *isrc) +{ + int rc; + + MPASS(isrc->isrc_event != NULL); + MPASS(isrc->isrc_event->ie_irq >= intr_nirq); + + rc = intr_event_destroy(isrc->isrc_event); + if (rc == 0) + isrc->isrc_event = NULL; + + return (rc); +} + /* * Alloc unique interrupt number (resource handle) for interrupt source. * @@ -456,6 +560,7 @@ isrc_alloc_irq(struct intr_irqsrc *isrc) return (ENOSPC); found: + isrc->isrc_event->ie_irq = irq; isrc->isrc_irq = irq; irq_sources[irq] = isrc; @@ -473,6 +578,7 @@ isrc_free_irq(struct intr_irqsrc *isrc) { mtx_assert(&isrc_table_lock, MA_OWNED); + MPASS(isrc->isrc_event != NULL); if (isrc->isrc_irq >= intr_nirq) return (EINVAL); @@ -521,10 +627,18 @@ intr_isrc_register(struct intr_irqsrc *isrc, device_t dev, u_int flags, vsnprintf(isrc->isrc_name, INTR_ISRC_NAMELEN, fmt, ap); va_end(ap); + error = isrc_event_create(isrc); + if (error) + return (error); + mtx_lock(&isrc_table_lock); error = isrc_alloc_irq(isrc); if (error != 0) { + int rc; mtx_unlock(&isrc_table_lock); + if ((rc = intr_event_destroy(isrc->isrc_event)) != 0) + printf("ERROR: %s(): intr_event_destroy() rc = %d!\n", + __func__, rc); return (error); } /* @@ -551,7 +665,11 @@ intr_isrc_deregister(struct intr_irqsrc *isrc) isrc_release_counters(isrc); error = isrc_free_irq(isrc); mtx_unlock(&isrc_table_lock); - return (error); + + if (error != 0) + return (error); + + return (isrc_event_destroy(isrc)); } #ifdef SMP @@ -611,147 +729,16 @@ iscr_setup_filter(struct intr_irqsrc *isrc, const char *name, } #endif -/* - * Interrupt source pre_ithread method for MI interrupt framework. - */ -static void -intr_isrc_pre_ithread(void *arg) -{ - struct intr_irqsrc *isrc = arg; - - PIC_PRE_ITHREAD(isrc->isrc_dev, isrc); -} - -/* - * Interrupt source post_ithread method for MI interrupt framework. - */ -static void -intr_isrc_post_ithread(void *arg) -{ - struct intr_irqsrc *isrc = arg; - - PIC_POST_ITHREAD(isrc->isrc_dev, isrc); -} - -/* - * Interrupt source post_filter method for MI interrupt framework. - */ -static void -intr_isrc_post_filter(void *arg) -{ - struct intr_irqsrc *isrc = arg; - - PIC_POST_FILTER(isrc->isrc_dev, isrc); -} - -/* - * Interrupt source assign_cpu method for MI interrupt framework. - */ -static int -intr_isrc_assign_cpu(void *arg, int cpu) -{ -#ifdef SMP - struct intr_irqsrc *isrc = arg; - int error; - - mtx_lock(&isrc_table_lock); - if (cpu == NOCPU) { - CPU_ZERO(&isrc->isrc_cpu); - isrc->isrc_flags &= ~INTR_ISRCF_BOUND; - } else { - CPU_SETOF(cpu, &isrc->isrc_cpu); - isrc->isrc_flags |= INTR_ISRCF_BOUND; - } - - /* - * In NOCPU case, it's up to PIC to either leave ISRC on same CPU or - * re-balance it to another CPU or enable it on more CPUs. However, - * PIC is expected to change isrc_cpu appropriately to keep us well - * informed if the call is successful. - */ - if (irq_assign_cpu) { - error = PIC_BIND_INTR(isrc->isrc_dev, isrc); - if (error) { - CPU_ZERO(&isrc->isrc_cpu); - mtx_unlock(&isrc_table_lock); - return (error); - } - } - mtx_unlock(&isrc_table_lock); - return (0); -#else - return (EOPNOTSUPP); -#endif -} - -/* - * Create interrupt event for interrupt source. - */ -static int -isrc_event_create(struct intr_irqsrc *isrc) -{ - struct intr_event *ie; - int error; - - error = intr_event_create(&ie, isrc, 0, isrc->isrc_irq, - intr_isrc_pre_ithread, intr_isrc_post_ithread, intr_isrc_post_filter, - intr_isrc_assign_cpu, "%s:", isrc->isrc_name); - if (error) - return (error); - - mtx_lock(&isrc_table_lock); - /* - * Make sure that we do not mix the two ways - * how we handle interrupt sources. Let contested event wins. - */ -#ifdef INTR_SOLO - if (isrc->isrc_filter != NULL || isrc->isrc_event != NULL) { -#else - if (isrc->isrc_event != NULL) { -#endif - mtx_unlock(&isrc_table_lock); - intr_event_destroy(ie); - return (isrc->isrc_event != NULL ? EBUSY : 0); - } - isrc->isrc_event = ie; - mtx_unlock(&isrc_table_lock); - - return (0); -} -#ifdef notyet -/* - * Destroy interrupt event for interrupt source. - */ -static void -isrc_event_destroy(struct intr_irqsrc *isrc) -{ - struct intr_event *ie; - - mtx_lock(&isrc_table_lock); - ie = isrc->isrc_event; - isrc->isrc_event = NULL; - mtx_unlock(&isrc_table_lock); - - if (ie != NULL) - intr_event_destroy(ie); -} -#endif /* * Add handler to interrupt source. */ -static int -isrc_add_handler(struct intr_irqsrc *isrc, const char *name, +int +intr_add_handler(struct intr_irqsrc *isrc, const char *name, driver_filter_t filter, driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep) { int error; - if (isrc->isrc_event == NULL) { - error = isrc_event_create(isrc); - if (error) - return (error); - } - error = intr_event_add_handler(isrc->isrc_event, name, filter, handler, arg, intr_priority(flags), flags, cookiep); if (error == 0) { @@ -1129,8 +1116,8 @@ intr_setup_irq(device_t dev, struct resource *res, driver_filter_t filt, } else #endif { - error = isrc_add_handler(isrc, name, filt, hand, arg, flags, - cookiep); + error = intr_add_handler(isrc, name, filt, hand, arg, flags, + cookiep, 0); debugf("irq %u add handler error %d on %s\n", isrc->isrc_irq, error, name); } if (error != 0) @@ -1199,21 +1186,14 @@ intr_teardown_irq(device_t dev, struct resource *res, void *cookie) return (error); } +/* + * Describe an interrupt + */ int -intr_describe_irq(device_t dev, struct resource *res, void *cookie, - const char *descr) +intr_describe(struct intr_irqsrc *isrc, void *cookie, const char *descr) { int error; - struct intr_irqsrc *isrc; - u_int res_id; - - KASSERT(rman_get_start(res) == rman_get_end(res), - ("%s: more interrupts in resource", __func__)); - res_id = (u_int)rman_get_start(res); - isrc = intr_map_get_isrc(res_id); - if (isrc == NULL || isrc->isrc_handlers == 0) - return (EINVAL); #ifdef INTR_SOLO if (isrc->isrc_filter != NULL) { if (isrc != cookie) @@ -1234,6 +1214,23 @@ intr_describe_irq(device_t dev, struct resource *res, void *cookie, return (error); } +int +intr_describe_irq(device_t dev, struct resource *res, void *cookie, + const char *descr) +{ + struct intr_irqsrc *isrc; + u_int res_id; + + KASSERT(rman_get_start(res) == rman_get_end(res), + ("%s: more interrupts in resource", __func__)); + + res_id = (u_int)rman_get_start(res); + isrc = intr_map_get_isrc(res_id); + if (isrc == NULL || isrc->isrc_handlers == 0) + return (EINVAL); + return (intr_describe(isrc, cookie, descr)); +} + #ifdef SMP int intr_bind_irq(device_t dev, struct resource *res, int cpu) @@ -1304,8 +1301,7 @@ intr_irq_shuffle(void *arg __unused) isrc->isrc_flags & (INTR_ISRCF_PPI | INTR_ISRCF_IPI)) continue; - if (isrc->isrc_event != NULL && - isrc->isrc_flags & INTR_ISRCF_BOUND && + if (isrc->isrc_flags & INTR_ISRCF_BOUND && isrc->isrc_event->ie_cpu != CPU_FFS(&isrc->isrc_cpu) - 1) panic("%s: CPU inconsistency", __func__); @@ -1579,12 +1575,10 @@ dosoftints(void) void intr_pic_init_secondary(void) { + struct intr_pic *pic; device_t dev; uint32_t rootnum; - /* - * QQQ: Only root PICs are aware of other CPUs ??? - */ //mtx_lock(&isrc_table_lock); for (rootnum = 0; rootnum < INTR_ROOT_NUM; rootnum++) { dev = intr_irq_roots[rootnum].dev; @@ -1592,6 +1586,9 @@ intr_pic_init_secondary(void) PIC_INIT_SECONDARY(dev, rootnum); } } + + SLIST_FOREACH(pic, &pic_list, pic_next) + PIC_INIT_SECONDARY(pic->pic_dev, INTR_ROOT_COUNT); //mtx_unlock(&isrc_table_lock); } #endif diff --git a/sys/sys/intr.h b/sys/sys/intr.h index f11e96777927a9..8053ee81bf6e9a 100644 --- a/sys/sys/intr.h +++ b/sys/sys/intr.h @@ -105,6 +105,10 @@ int intr_isrc_deregister(struct intr_irqsrc *); int intr_isrc_register(struct intr_irqsrc *, device_t, u_int, const char *, ...) __printflike(4, 5); +int intr_add_handler(struct intr_irqsrc *, const char *, driver_filter_t, + driver_intr_t, void *, enum intr_type, void **); +int intr_describe(struct intr_irqsrc *isrc, void *cookie, const char *descr); + #ifdef SMP bool intr_isrc_init_on_cpu(struct intr_irqsrc *isrc, u_int cpu); #endif diff --git a/sys/x86/include/xen/xen-os.h b/sys/x86/include/xen/xen-os.h index d3f21e2a6c4555..c976c2a321ecbd 100644 --- a/sys/x86/include/xen/xen-os.h +++ b/sys/x86/include/xen/xen-os.h @@ -40,6 +40,9 @@ #include +/* On x86 Xen is probed very early, so this is simply xen_domain() */ +#define xen_domain_early() xen_domain() + /* If non-zero, the hypervisor has been configured to use a direct vector */ extern int xen_vector_callback_enabled; diff --git a/sys/xen/hypercall.h b/sys/xen/hypercall.h new file mode 100644 index 00000000000000..9fd9f8524e4464 --- /dev/null +++ b/sys/xen/hypercall.h @@ -0,0 +1,314 @@ +/****************************************************************************** + * SPDX-License-Identifier: MIT OR GPL-2.0-only + * + * hypercall.h + * + * FreeBSD-specific hypervisor handling. + * + * Copyright (c) 2002-2004, K A Fraser + * + * 64-bit updates: + * Benjamin Liu + * Jun Nakajima + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __XEN_HYPERCALL_H__ +#define __XEN_HYPERCALL_H__ + +#include + +/* + * Architecture hypercall.h must provide the following 7 macros/functions: + * + * _hypercall[0-5](type, name[, arg0[, arg1[, arg2[, arg3[, arg4]]]]]); + * int privcmd_hypercall(op, arg0, arg1, arg2, arg3, arg4); + * + * Where _hypercall#() returns "type", hypercall0() takes no arguments, and + * _hypercall5() takes 5 arguments. The "name" does not include the leading + * __HYPERVISOR_ for the Xen call name. + * + * All arguments to privcmd_hypercall() are assumed to be full register size + * (long). + */ + +#define __must_check + +static inline int __must_check +HYPERVISOR_mmu_update( + mmu_update_t *req, unsigned int count, unsigned int *success_count, + domid_t domid) +{ + return _hypercall4(int, mmu_update, req, count, success_count, domid); +} + +static inline int __must_check +HYPERVISOR_mmuext_op( + mmuext_op_t *op, unsigned int count, unsigned int *success_count, + domid_t domid) +{ + return _hypercall4(int, mmuext_op, op, count, success_count, domid); +} + +static inline int __must_check +HYPERVISOR_set_gdt( + unsigned long *frame_list, unsigned int entries) +{ + return _hypercall2(int, set_gdt, frame_list, entries); +} + +static inline int __must_check +HYPERVISOR_stack_switch( + unsigned long ss, unsigned long esp) +{ + return _hypercall2(int, stack_switch, ss, esp); +} + +static inline int __must_check +HYPERVISOR_set_callbacks( + unsigned long event_selector, unsigned long event_address, + unsigned long failsafe_selector, unsigned long failsafe_address) +{ + return _hypercall4(int, set_callbacks, + event_selector, event_address, + failsafe_selector, failsafe_address); +} + +static inline int +HYPERVISOR_fpu_taskswitch( + int set) +{ + return _hypercall1(int, fpu_taskswitch, set); +} + +static inline int __must_check +HYPERVISOR_sched_op( + int cmd, void *arg) +{ + return _hypercall2(int, sched_op, cmd, arg); +} + +static inline long __must_check +HYPERVISOR_set_timer_op( + uint64_t timeout) +{ +#ifndef __ILP32__ + return _hypercall1(long, set_timer_op, timeout); +#else + unsigned long timeout_hi = (unsigned long)(timeout>>32); + unsigned long timeout_lo = (unsigned long)timeout; + + return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); +#endif +} + +static inline int __must_check +HYPERVISOR_platform_op( + xen_platform_op_t *platform_op) +{ + platform_op->interface_version = XENPF_INTERFACE_VERSION; + return _hypercall1(int, platform_op, platform_op); +} + +static inline int __must_check +HYPERVISOR_set_debugreg( + unsigned int reg, unsigned long value) +{ + return _hypercall2(int, set_debugreg, reg, value); +} + +static inline unsigned long __must_check +HYPERVISOR_get_debugreg( + unsigned int reg) +{ + return _hypercall1(unsigned long, get_debugreg, reg); +} + +static inline int __must_check +HYPERVISOR_update_descriptor( + uint64_t ma, uint64_t desc) +{ +#ifndef __ILP32__ + return _hypercall2(int, update_descriptor, ma, desc); +#else + return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32); +#endif +} + +static inline int __must_check +HYPERVISOR_memory_op( + unsigned int cmd, void *arg) +{ + return _hypercall2(int, memory_op, cmd, arg); +} + +static inline int __must_check +HYPERVISOR_multicall( + multicall_entry_t *call_list, unsigned int nr_calls) +{ + return _hypercall2(int, multicall, call_list, nr_calls); +} + +static inline int __must_check +HYPERVISOR_update_va_mapping( + unsigned long va, uint64_t new_val, unsigned long flags) +{ +#ifndef __ILP32__ + return _hypercall3(int, update_va_mapping, va, new_val, flags); +#else + uint32_t hi, lo; + + lo = (uint32_t)(new_val & 0xffffffff); + hi = (uint32_t)(new_val >> 32); + + return _hypercall4(int, update_va_mapping, va, lo, hi, flags); +#endif +} + +static inline int __must_check +HYPERVISOR_event_channel_op( + int cmd, void *arg) +{ + return _hypercall2(int, event_channel_op, cmd, arg); +} + +static inline int __must_check +HYPERVISOR_xen_version( + int cmd, void *arg) +{ + return _hypercall2(int, xen_version, cmd, arg); +} + +static inline int __must_check +HYPERVISOR_console_io( + int cmd, unsigned int count, const char *str) +{ + return _hypercall3(int, console_io, cmd, count, str); +} + +static inline int __must_check +HYPERVISOR_physdev_op( + int cmd, void *arg) +{ + return _hypercall2(int, physdev_op, cmd, arg); +} + +static inline int __must_check +HYPERVISOR_grant_table_op( + unsigned int cmd, void *uop, unsigned int count) +{ + return _hypercall3(int, grant_table_op, cmd, uop, count); +} + +static inline int __must_check +HYPERVISOR_update_va_mapping_otherdomain( + unsigned long va, uint64_t new_val, unsigned long flags, domid_t domid) +{ +#ifndef __ILP32__ + return _hypercall4(int, update_va_mapping_otherdomain, va, + new_val, flags, domid); +#else + uint32_t hi, lo; + + lo = (uint32_t)(new_val & 0xffffffff); + hi = (uint32_t)(new_val >> 32); + + return _hypercall5(int, update_va_mapping_otherdomain, va, + lo, hi, flags, domid); +#endif +} + +static inline int __must_check +HYPERVISOR_vm_assist( + unsigned int cmd, unsigned int type) +{ + return _hypercall2(int, vm_assist, cmd, type); +} + +static inline int __must_check +HYPERVISOR_vcpu_op( + int cmd, unsigned int vcpuid, void *extra_args) +{ + return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); +} + +static inline int __must_check +HYPERVISOR_set_segment_base( + int reg, unsigned long value) +{ + return _hypercall2(int, set_segment_base, reg, value); +} + +static inline int __must_check +HYPERVISOR_suspend( + unsigned long srec) +{ + sched_shutdown_t sched_shutdown = { + .reason = SHUTDOWN_suspend + }; + + return _hypercall3(int, sched_op, SCHEDOP_shutdown, + &sched_shutdown, srec); +} + +static inline unsigned long __must_check +HYPERVISOR_hvm_op( + int op, void *arg) +{ + return _hypercall2(unsigned long, hvm_op, op, arg); +} + +static inline int __must_check +HYPERVISOR_callback_op( + int cmd, const void *arg) +{ + return _hypercall2(int, callback_op, cmd, arg); +} + +static inline int __must_check +HYPERVISOR_xenoprof_op( + int op, void *arg) +{ + return _hypercall2(int, xenoprof_op, op, arg); +} + +static inline int __must_check +HYPERVISOR_kexec_op( + unsigned long op, void *args) +{ + return _hypercall2(int, kexec_op, op, args); +} + +static inline int __must_check +HYPERVISOR_dm_op( + domid_t domid, unsigned int nr_bufs, const void *bufs) +{ + return _hypercall3(int, dm_op, domid, nr_bufs, bufs); +} + +#undef __must_check + +#endif /* __XEN_HYPERCALL_H__ */