The branch main has been updated by royger: URL: https://cgit.FreeBSD.org/src/commit/?id=db16856110cbdbdfdc3c8d44edae1b3a7463198e
commit db16856110cbdbdfdc3c8d44edae1b3a7463198e Author: Roger Pau Monné <[email protected]> AuthorDate: 2026-02-24 20:23:08 +0000 Commit: Roger Pau Monné <[email protected]> CommitDate: 2026-02-27 07:39:11 +0000 xen/acpi: implement hook to notify Xen about entering sleep state This is required so that ACPI power-off (entering S5) works as expected, as the ACPI PM1a and PM1b blocks might not be accessible by dom0 directly. Additionally, Xen also needs to do cleanup before entering a sleep state, so it needs to be notified about it. With this patch FreeBSD dom0 now powers off the host correctly: acpi0: Powering system off... (XEN) [ 85.686598] arch/x86/hvm/emulate.c:415:d0v0 fixup p2m mapping for page fedc6 added (XEN) [ 85.687606] arch/x86/hvm/emulate.c:415:d0v0 fixup p2m mapping for page fbc10 added (XEN) [ 85.692357] Preparing system for ACPI S5 state. (XEN) [ 85.692702] Disabling non-boot CPUs ... (XEN) [ 85.694471] Broke affinity for IRQ9, new: {0-7} [...] (XEN) [ 85.903118] Entering ACPI S5 state. Should be a non-functional change when not running as a Xen dom0. Reviewed by: kib Sponsored by: Citrix Systems R&D MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D55504 --- sys/conf/files | 1 + sys/dev/acpica/Osd/OsdHardware.c | 13 +++++++ sys/dev/acpica/acpivar.h | 13 +++++++ sys/dev/xen/acpi/xen-acpi.c | 75 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+) diff --git a/sys/conf/files b/sys/conf/files index 4913efebf00d..632fddef2cb5 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3578,6 +3578,7 @@ dev/xdma/xdma_mbuf.c optional xdma dev/xdma/xdma_queue.c optional xdma dev/xdma/xdma_sg.c optional xdma dev/xdma/xdma_sglist.c optional xdma +dev/xen/acpi/xen-acpi.c optional xenhvm dev/xen/balloon/balloon.c optional xenhvm dev/xen/blkfront/blkfront.c optional xenhvm dev/xen/blkback/blkback.c optional xenhvm diff --git a/sys/dev/acpica/Osd/OsdHardware.c b/sys/dev/acpica/Osd/OsdHardware.c index fbaf76d2a91a..4252cbc63222 100644 --- a/sys/dev/acpica/Osd/OsdHardware.c +++ b/sys/dev/acpica/Osd/OsdHardware.c @@ -37,6 +37,8 @@ extern int acpi_susp_bounce; +int (*acpi_prepare_sleep)(uint8_t state, uint32_t a, uint32_t b, bool ext); + ACPI_STATUS AcpiOsEnterSleep(UINT8 SleepState, UINT32 RegaValue, UINT32 RegbValue) { @@ -45,6 +47,17 @@ AcpiOsEnterSleep(UINT8 SleepState, UINT32 RegaValue, UINT32 RegbValue) if (acpi_susp_bounce) return (AE_CTRL_TERMINATE); + if (acpi_prepare_sleep != NULL) + { + int ret = acpi_prepare_sleep(SleepState, RegaValue, RegbValue, + ACPI_REDUCED_HARDWARE ? true : AcpiGbl_ReducedHardware); + + if (ret < 0) + return (AE_ERROR); + if (ret > 0) + return (AE_CTRL_TERMINATE); + } + return (AE_OK); } diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index aa8d5bd0971f..b86c6c1aa3c6 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -610,6 +610,19 @@ int acpi_pxm_parse(device_t dev); int acpi_map_pxm_to_vm_domainid(int pxm); bus_get_cpus_t acpi_get_cpus; +/* + * Hook for ACPI sleep routine. + */ +extern int (*acpi_prepare_sleep)(uint8_t state, uint32_t a, uint32_t b, + bool ext); + +static inline void +acpi_set_prepare_sleep( + int (*hook)(uint8_t state, uint32_t a, uint32_t b, bool ext)) +{ + acpi_prepare_sleep = hook; +} + #ifdef __aarch64__ /* * ARM specific ACPI interfaces, relating to IORT table. diff --git a/sys/dev/xen/acpi/xen-acpi.c b/sys/dev/xen/acpi/xen-acpi.c new file mode 100644 index 000000000000..1e46883e2c86 --- /dev/null +++ b/sys/dev/xen/acpi/xen-acpi.c @@ -0,0 +1,75 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026 Citrix Systems R&D + * All rights reserved. + * + * 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 <sys/cdefs.h> +#include "opt_acpi.h" +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/kobj.h> + +#include <machine/_inttypes.h> + +#include <contrib/dev/acpica/include/acpi.h> +#include <contrib/dev/acpica/include/accommon.h> + +#include <dev/acpica/acpivar.h> + +#include <xen/xen-os.h> + +static int prepare_sleep_state(uint8_t state, uint32_t a, uint32_t b, bool ext) +{ + struct xen_platform_op op = { + .cmd = XENPF_enter_acpi_sleep, + .interface_version = XENPF_INTERFACE_VERSION, + .u.enter_acpi_sleep.val_a = a, + .u.enter_acpi_sleep.val_b = b, + .u.enter_acpi_sleep.sleep_state = state, + .u.enter_acpi_sleep.flags = + ext ? XENPF_ACPI_SLEEP_EXTENDED : 0, + }; + int error; + + error = HYPERVISOR_platform_op(&op); + if (error) + printf("Xen notify ACPI sleep failed - " + "State %#x A %#x B %#x: %d\n", state, a, b, error); + + return (error ? error : 1); +} + +static int init_xen_acpi_sleep(void *arg) +{ + if (!xen_initial_domain()) + return (0); + + acpi_set_prepare_sleep(&prepare_sleep_state); + return (0); +} + +SYSINIT(xen_sleep, SI_SUB_CONFIGURE, SI_ORDER_ANY, init_xen_acpi_sleep, NULL);
