From: Imre Vadász Date: Sat, 7 Nov 2015 00:37:39 +0000 (+0100) Subject: acpi_pvpanic: Notify Qemu VM host if we panic. X-Git-Tag: v4.6.0rc~1325 X-Git-Url: https://gitweb.dragonflybsd.org/~tuxillo/dragonfly.git/commitdiff_plain/2af72e0ae32e279a57a5bd47226cf522fc024203 acpi_pvpanic: Notify Qemu VM host if we panic. By default the virtual machine is stopped when the pvpanic is triggered. For accessing ddb, the virtual machine execution then needs to be resumed manually (e.g. with the "cont" command on the Qemu-monitor console). Triggering a pvpanic instead of just continuing to the ddb prompt can be useful to avoid hogging the CPU while hanging in ddb, and to provide a kernel panic notification for the VM-host system. --- diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 7dc60bb323..4050f22862 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -8,6 +8,7 @@ MAN= aac.4 \ acpi_fujitsu.4 \ acpi_hp.4 \ acpi_panasonic.4 \ + acpi_pvpanic.4 \ acpi_sony.4 \ acpi_thermal.4 \ acpi_thinkpad.4 \ diff --git a/share/man/man4/acpi_pvpanic.4 b/share/man/man4/acpi_pvpanic.4 new file mode 100644 index 0000000000..bc9c3a5723 --- /dev/null +++ b/share/man/man4/acpi_pvpanic.4 @@ -0,0 +1,85 @@ +.\" +.\" Copyright (c) 2015 The DragonFly Project. 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. +.\" 3. Neither the name of The DragonFly Project nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific, prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 +.\" COPYRIGHT HOLDERS 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. +.\" +.Dd November 23, 2015 +.Dt ACPI_PVPANIC 4 +.Os +.Sh NAME +.Nm acpi_pvpanic +.Nd Qemu pvpanic Device +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device acpi_pvpanic" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +acpi_pvpanic_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the pvpanic device that can be provided +to virtual-machines by the +.Xr qemu 1 +virtual machine monitor. +The pvpanic device can be enabled in +.Xr qemu 1 +by adding the +.Fl device Ar pvpanic +command line option. +When the +.Nm +driver is used, the virtual machine execution will be stopped when the +kernel signals a panic. +For accessing +.Xr ddb 4 +the virtual machine then needs to be resumed manually (e.g. using the +.Dq cont +command in the qemu-monitor console). +.Sh SEE ALSO +.Xr acpi 4 , +.Xr ddb 4 +.Sh HISTORY +The +.Nm +driver first appeared in +.Dx 4.5 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Imre Vadasz Aq Mt imre@vdsz.com . diff --git a/sys/conf/files b/sys/conf/files index ac24134240..5445a323d0 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2225,6 +2225,7 @@ ${OSACPI_MI_DIR}/acpi_dock/acpi_dock.c optional acpi_dock acpi ${OSACPI_MI_DIR}/acpi_fujitsu/acpi_fujitsu.c optional acpi_fujitsu acpi ${OSACPI_MI_DIR}/acpi_hp/acpi_hp.c optional acpi_hp acpi ${OSACPI_MI_DIR}/acpi_panasonic/acpi_panasonic.c optional acpi_panasonic acpi +${OSACPI_MI_DIR}/acpi_pvpanic/acpi_pvpanic.c optional acpi_pvpanic acpi ${OSACPI_MI_DIR}/acpi_sony/acpi_sony.c optional acpi_sony acpi ${OSACPI_MI_DIR}/acpi_thinkpad/acpi_thinkpad.c optional acpi_thinkpad acpi ${OSACPI_MI_DIR}/acpi_toshiba/acpi_toshiba.c optional acpi_toshiba acpi diff --git a/sys/config/LINT64 b/sys/config/LINT64 index 5b52495c78..f123e8c23a 100644 --- a/sys/config/LINT64 +++ b/sys/config/LINT64 @@ -2158,6 +2158,9 @@ device acpi_hp # ACPI Panasonic Extras (LCD backlight/brightness, video output, etc.) device acpi_panasonic +# ACPI pvpanic driver for virtual machines running in Qemu +device acpi_pvpanic + # ACPI Sony extra (LCD brightness) device acpi_sony diff --git a/sys/dev/acpica/Makefile b/sys/dev/acpica/Makefile index 8d5a05dc57..cc36116106 100644 --- a/sys/dev/acpica/Makefile +++ b/sys/dev/acpica/Makefile @@ -116,8 +116,8 @@ acpi_wakecode.h: acpi_wakecode.S ${MAKE} -f ${SYSDIR}/${OSACPI_MD_DIR}/Makefile \ MAKESRCPATH=${SYSDIR}/${OSACPI_MD_DIR} -SUBDIR= acpi_asus acpi_dock acpi_fujitsu acpi_hp acpi_panasonic acpi_sony -SUBDIR+=acpi_thinkpad acpi_toshiba acpi_video acpi_wmi aibs +SUBDIR= acpi_asus acpi_dock acpi_fujitsu acpi_hp acpi_panasonic acpi_pvpanic +SUBDIR+=acpi_sony acpi_thinkpad acpi_toshiba acpi_video acpi_wmi aibs # Empty for concurrent build # diff --git a/sys/dev/acpica/acpi_pvpanic/Makefile b/sys/dev/acpica/acpi_pvpanic/Makefile new file mode 100644 index 0000000000..bc028c694d --- /dev/null +++ b/sys/dev/acpica/acpi_pvpanic/Makefile @@ -0,0 +1,5 @@ +KMOD= acpi_pvpanic +SRCS= acpi_pvpanic.c +SRCS+= opt_acpi.h acpi_if.h bus_if.h device_if.h + +.include diff --git a/sys/dev/acpica/acpi_pvpanic/acpi_pvpanic.c b/sys/dev/acpica/acpi_pvpanic/acpi_pvpanic.c new file mode 100644 index 0000000000..c3cfb90792 --- /dev/null +++ b/sys/dev/acpica/acpi_pvpanic/acpi_pvpanic.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2015 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Imre Vadász + * + * 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. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDERS 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 "opt_acpi.h" +#include +#include +#include +#include +#include +#include + +#include "acpi.h" + +#include + +#define PVPANIC_GUESTPANIC (1 << 0) + +ACPI_MODULE_NAME("pvpanic") + +struct acpi_pvpanic_softc { + device_t dev; + ACPI_HANDLE handle; + int pvpanic_port_rid; + struct resource *pvpanic_port_res; + bus_space_tag_t pvpanic_iot; + bus_space_handle_t pvpanic_ioh; + struct panicerinfo pvpanic_info; +}; + +static int acpi_pvpanic_probe(device_t dev); +static int acpi_pvpanic_attach(device_t dev); +static int acpi_pvpanic_detach(device_t dev); +static void acpi_pvpanic_panic(void *arg); + +static device_method_t acpi_pvpanic_methods[] = { + DEVMETHOD(device_probe, acpi_pvpanic_probe), + DEVMETHOD(device_attach, acpi_pvpanic_attach), + DEVMETHOD(device_detach, acpi_pvpanic_detach), + + DEVMETHOD_END +}; + +static driver_t acpi_pvpanic_driver = { + "acpi_pvpanic", + acpi_pvpanic_methods, + sizeof(struct acpi_pvpanic_softc), +}; + +static devclass_t acpi_pvpanic_devclass; +DRIVER_MODULE(acpi_pvpanic, acpi, acpi_pvpanic_driver, acpi_pvpanic_devclass, + NULL, NULL); +MODULE_DEPEND(acpi_pvpanic, acpi, 1, 1, 1); +MODULE_VERSION(acpi_pvpanic, 1); + +static int +acpi_pvpanic_probe(device_t dev) +{ + static char *pvpanic_ids[] = { "QEMU0001", NULL }; + + if (acpi_disabled("pvpanic") || + ACPI_ID_PROBE(device_get_parent(dev), dev, pvpanic_ids) == NULL || + device_get_unit(dev) != 0) + return (ENXIO); + + device_set_desc(dev, "Qemu pvpanic device"); + return (0); +} + +static int +acpi_pvpanic_attach(device_t dev) +{ + struct acpi_pvpanic_softc *sc; + uint8_t val; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->handle = acpi_get_handle(dev); + + sc->pvpanic_port_rid = 0; + sc->pvpanic_port_res = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT, + &sc->pvpanic_port_rid, RF_ACTIVE); + if (sc->pvpanic_port_res == NULL) { + device_printf(dev, "can't allocate pvpanic port\n"); + return ENXIO; + } + sc->pvpanic_iot = rman_get_bustag(sc->pvpanic_port_res); + sc->pvpanic_ioh = rman_get_bushandle(sc->pvpanic_port_res); + + /* Check for guest panic notification support */ + val = bus_space_read_1(sc->pvpanic_iot, sc->pvpanic_ioh, 0); + if (!(val & PVPANIC_GUESTPANIC)) { + device_printf(dev, "No PVPANIC_GUESTPANIC support\n"); + goto fail; + } + + device_printf(dev, "Registering panic callback\n"); + sc->pvpanic_info.notifier = acpi_pvpanic_panic; + sc->pvpanic_info.arg = sc; + if (set_panic_notifier(&sc->pvpanic_info) != 0) { + device_printf(dev, "Failed to register panic notifier\n"); + goto fail; + } + return (0); + +fail: + bus_release_resource(dev, SYS_RES_IOPORT, + sc->pvpanic_port_rid, sc->pvpanic_port_res); + return ENXIO; +} + +static int +acpi_pvpanic_detach(device_t dev) +{ + struct acpi_pvpanic_softc *sc = device_get_softc(dev); + + set_panic_notifier(NULL); + + bus_release_resource(dev, SYS_RES_IOPORT, + sc->pvpanic_port_rid, sc->pvpanic_port_res); + + return (0); +} + +static void +acpi_pvpanic_panic(void *arg) +{ + struct acpi_pvpanic_softc *sc = (struct acpi_pvpanic_softc *)arg; + + bus_space_write_1(sc->pvpanic_iot, sc->pvpanic_ioh, 0, + PVPANIC_GUESTPANIC); +} diff --git a/sys/dev/acpica/acpi_pvpanic/panic_notifier.h b/sys/dev/acpica/acpi_pvpanic/panic_notifier.h new file mode 100644 index 0000000000..c012007896 --- /dev/null +++ b/sys/dev/acpica/acpi_pvpanic/panic_notifier.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Imre Vadász + * + * 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. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDERS 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 _PANIC_NOTIFIER_H_ +#define _PANIC_NOTIFIER_H_ + +struct panicerinfo { + void (*notifier) (void *); + void *arg; +}; + +int set_panic_notifier(struct panicerinfo *info); + +#endif /* _PANIC_NOTIFIER_H_ */ diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index 26a9a60138..dc17b3a7a0 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -85,6 +85,7 @@ #include #include +#include #include #ifndef PANIC_REBOOT_WAIT_TIME @@ -689,6 +690,21 @@ sysctl_kern_dumpdev(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, sizeof dumpdev, sysctl_kern_dumpdev, "T,udev_t", ""); +static struct panicerinfo *panic_notifier; + +int +set_panic_notifier(struct panicerinfo *info) +{ + if (info == NULL) + panic_notifier = NULL; + else if (panic_notifier != NULL) + return 1; + else + panic_notifier = info; + + return 0; +} + /* * Panic is called on unresolvable fatal errors. It prints "panic: mesg", * and then reboots. If we are called twice, then we avoid trying to sync @@ -792,6 +808,8 @@ panic(const char *fmt, ...) if (panicstr == fmt) panicstr = buf; __va_end(ap); + if (panic_notifier != NULL) + panic_notifier->notifier(panic_notifier->arg); kprintf("panic: %s\n", buf); /* two separate prints in case of an unmapped page and trap */ kprintf("cpuid = %d\n", mycpu->gd_cpuid);