acpi_pvpanic: Notify Qemu VM host if we panic.
authorImre Vadász <imre@vdsz.com>
Sat, 7 Nov 2015 00:37:39 +0000 (01:37 +0100)
committerImre Vadász <imre@vdsz.com>
Tue, 24 Nov 2015 23:25:22 +0000 (00:25 +0100)
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.

share/man/man4/Makefile
share/man/man4/acpi_pvpanic.4 [new file with mode: 0644]
sys/conf/files
sys/config/LINT64
sys/dev/acpica/Makefile
sys/dev/acpica/acpi_pvpanic/Makefile [new file with mode: 0644]
sys/dev/acpica/acpi_pvpanic/acpi_pvpanic.c [new file with mode: 0644]
sys/dev/acpica/acpi_pvpanic/panic_notifier.h [new file with mode: 0644]
sys/kern/kern_shutdown.c

index 7dc60bb..4050f22 100644 (file)
@@ -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 (file)
index 0000000..bc9c3a5
--- /dev/null
@@ -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 .
index ac24134..5445a32 100644 (file)
@@ -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
index 5b52495..f123e8c 100644 (file)
@@ -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
 
index 8d5a05d..cc36116 100644 (file)
@@ -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 (file)
index 0000000..bc028c6
--- /dev/null
@@ -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 <bsd.kmod.mk>
diff --git a/sys/dev/acpica/acpi_pvpanic/acpi_pvpanic.c b/sys/dev/acpica/acpi_pvpanic/acpi_pvpanic.c
new file mode 100644 (file)
index 0000000..c3cfb90
--- /dev/null
@@ -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 <imre@vdsz.com>
+ *
+ * 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 <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <dev/acpica/acpi_pvpanic/panic_notifier.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#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 (file)
index 0000000..c012007
--- /dev/null
@@ -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 <imre@vdsz.com>
+ *
+ * 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_ */
index 26a9a60..dc17b3a 100644 (file)
@@ -85,6 +85,7 @@
 #include <sys/signalvar.h>
 
 #include <sys/wdog.h>
+#include <dev/acpica/acpi_pvpanic/panic_notifier.h>
 #include <dev/misc/gpio/gpio.h>
 
 #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);