* [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4)
@ 2009-03-06 18:29 Richard W.M. Jones
2009-03-06 18:32 ` Richard W.M. Jones
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Richard W.M. Jones @ 2009-03-06 18:29 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 757 bytes --]
This is the hardware virtual watchdogs patch. The only change since
the last time I posted it[1] is that I've rebased to latest SVN and
I've changed the header files to use non-reserved QEMU_* symbols
instead of _QEMU_* (thanks Marc for pointing this out).
Rich.
[1] http://lists.gnu.org/archive/html/qemu-devel/2009-03/msg00050.html
http://lists.gnu.org/archive/html/qemu-devel/2009-02/msg01434.html
http://lists.gnu.org/archive/html/qemu-devel/2009-02/msg01404.html
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
Read my OCaml programming blog: http://camltastic.blogspot.com/
Fedora now supports 68 OCaml packages (the OPEN alternative to F#)
http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
[-- Attachment #2: qemu-watchdog-4.patch --]
[-- Type: text/plain, Size: 35923 bytes --]
Index: Makefile.target
===================================================================
--- Makefile.target (revision 6718)
+++ Makefile.target (working copy)
@@ -584,6 +584,7 @@
OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
OBJS += device-hotplug.o pci-hotplug.o
+OBJS+= wdt_ib700.o wdt_i6300esb.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
Index: vl.c
===================================================================
--- vl.c (revision 6718)
+++ vl.c (working copy)
@@ -43,6 +43,7 @@
#include "migration.h"
#include "kvm.h"
#include "balloon.h"
+#include "watchdog.h"
#include <unistd.h>
#include <fcntl.h>
@@ -4103,6 +4104,8 @@
"-old-param old param mode\n"
#endif
"-tb-size n set TB size\n"
+ "-watchdog ib700|i6300esb[,action=reset|shutdown|poweroff|pause]\n"
+ " enable virtual hardware watchdog [default=none]\n"
"-incoming p prepare for incoming migration, listen on port p\n"
#ifndef _WIN32
"-chroot dir Chroot to dir just before starting the VM.\n"
@@ -4219,6 +4222,7 @@
QEMU_OPTION_startdate,
QEMU_OPTION_icount,
QEMU_OPTION_echr,
+ QEMU_OPTION_watchdog,
QEMU_OPTION_virtiocon,
QEMU_OPTION_show_cursor,
QEMU_OPTION_semihosting,
@@ -4347,6 +4351,7 @@
{ "startdate", HAS_ARG, QEMU_OPTION_startdate },
{ "icount", HAS_ARG, QEMU_OPTION_icount },
{ "echr", HAS_ARG, QEMU_OPTION_echr },
+ { "watchdog", HAS_ARG, QEMU_OPTION_watchdog },
{ "virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon },
{ "show-cursor", 0, QEMU_OPTION_show_cursor },
#if defined(TARGET_ARM) || defined(TARGET_M68K)
@@ -5086,6 +5091,14 @@
serial_devices[serial_device_index] = optarg;
serial_device_index++;
break;
+ case QEMU_OPTION_watchdog:
+ if (wdt_option) {
+ fprintf (stderr,
+ "qemu: only one watchdog option may be given\n");
+ exit (1);
+ }
+ wdt_option = optarg;
+ break;
case QEMU_OPTION_virtiocon:
if (virtio_console_index >= MAX_VIRTIO_CONSOLES) {
fprintf(stderr, "qemu: too many virtio consoles\n");
Index: Makefile
===================================================================
--- Makefile (revision 6718)
+++ Makefile (working copy)
@@ -85,6 +85,7 @@
OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
OBJS+=qemu-char.o aio.o net-checksum.o savevm.o cache-utils.o
+OBJS+=watchdog.o
ifdef CONFIG_BRLAPI
OBJS+= baum.o
Index: watchdog.c
===================================================================
--- watchdog.c (revision 0)
+++ watchdog.c (revision 0)
@@ -0,0 +1,161 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "hw/wdt_ib700.h"
+#include "hw/wdt_i6300esb.h"
+#include "watchdog.h"
+
+/* Possible values for action parameter. */
+#define WDT_RESET 1
+#define WDT_SHUTDOWN 2
+#define WDT_POWEROFF 3
+#define WDT_PAUSE 4
+
+static void parse_option (const char *arg, int *action_r);
+static void parse_rest (const char *rest, int *action_r);
+
+/* Linked list of models - virtual watchdog devices add themselves
+ * to this list.
+ */
+wdt_model *wdt_models = NULL;
+
+/* The raw -watchdog option specified on the command line. */
+const char *wdt_option = NULL;
+
+/* Currently enabled watchdog device. Only one may be enabled from
+ * the command line.
+ */
+static wdt_model *wdt = NULL;
+
+/* Called from the PC code to parse the option and finally configure
+ * the device.
+ */
+void
+watchdog_pc_init (PCIBus *pci_bus)
+{
+ int action;
+
+ if (!wdt_option) return;
+ parse_option (wdt_option, &action);
+ if (!wdt) return; /* No watchdog configured. */
+ wdt->wdt_methods->wdt_pc_init (pci_bus, action);
+}
+
+/* This actually performs the "action" once a watchdog has expired,
+ * ie. reboot, shutdown, exit, etc.
+ */
+void
+watchdog_perform_action (int action)
+{
+ switch (action) {
+ case WDT_RESET: /* same as 'system_reset' in monitor */
+ qemu_system_reset_request ();
+ break;
+
+ case WDT_SHUTDOWN: /* same as 'system_powerdown' in monitor */
+ qemu_system_powerdown_request ();
+ break;
+
+ case WDT_POWEROFF: /* same as 'quit' command in monitor */
+ exit (0);
+ break;
+
+ case WDT_PAUSE: /* same as 'stop' command in monitor */
+ vm_stop (0);
+ break;
+ }
+}
+
+/* This function parses the command line parameter of the form:
+ * <<model>>[,action=<<action>>]
+ */
+static void
+parse_option (const char *arg, int *action_r)
+{
+ wdt_model *p;
+ int len;
+
+ if (wdt) {
+ fprintf (stderr, "Only one -watchdog device can be enabled\n");
+ exit (1);
+ }
+
+ /* -watchdog ? lists available devices and exits cleanly. */
+ if (strcmp (arg, "?") == 0) {
+ for (p = wdt_models; p; p = p->wdt_next) {
+ fprintf (stderr, "\t%s\t%s\n",
+ p->wdt_name, p->wdt_description);
+ }
+ exit (0);
+ }
+
+ for (p = wdt_models; p; p = p->wdt_next) {
+ len = strlen (p->wdt_name);
+ if (strncasecmp (arg, p->wdt_name, len) == 0 &&
+ (arg[len] == '\0' || arg[len] == ',')) {
+ parse_rest (&arg[len], action_r);
+ if (p->wdt_methods->wdt_option)
+ p->wdt_methods->wdt_option (&arg[len]);
+ wdt = p;
+ return;
+ }
+ }
+
+ fprintf (stderr, "Unknown -watchdog device. Supported devices are:\n");
+ for (p = wdt_models; p; p = p->wdt_next) {
+ fprintf (stderr, "\t%s\t%s\n",
+ p->wdt_name, p->wdt_description);
+ }
+ exit (1);
+}
+
+/* Parse the remainder of the command line parameter, either:
+ * ,action=<<action>>
+ * or empty string. For forwards compatibility, ignore other
+ * parameters which may appear in the string.
+ */
+static void
+parse_rest (const char *arg, int *action_r)
+{
+ char buf[64];
+
+ *action_r = WDT_RESET; /* Default action. */
+ if (*arg == '\0') return;
+ if (*arg == ',') arg++;
+
+ if (get_param_value (buf, sizeof (buf), "action", arg)) {
+ if (strcasecmp (buf, "reset") == 0)
+ *action_r = WDT_RESET;
+ else if (strcasecmp (buf, "shutdown") == 0)
+ *action_r = WDT_SHUTDOWN;
+ else if (strcasecmp (buf, "poweroff") == 0)
+ *action_r = WDT_POWEROFF;
+ else if (strcasecmp (buf, "pause") == 0)
+ *action_r = WDT_PAUSE;
+ else {
+ fprintf (stderr, "Unknown -watchdog action parameter: %s\n", buf);
+ exit (1);
+ }
+ }
+}
Index: qemu-doc.texi
===================================================================
--- qemu-doc.texi (revision 6718)
+++ qemu-doc.texi (working copy)
@@ -1161,6 +1161,38 @@
@item -echr 20
@end table
+@item -watchdog @var{model}[,action=@var{action}]
+Create a virtual hardware watchdog device. Once enabled (by a guest
+action), the watchdog must be periodically polled by an agent inside
+the guest or else the guest will be restarted.
+
+The @var{model} is the model of hardware watchdog to emulate. Choices
+for model are: @code{ib700} (iBASE 700) which is a very simple ISA
+watchdog with a single timer, or @code{i6300esb} (Intel 6300ESB I/O
+controller hub) which is a much more featureful PCI-based dual-timer
+watchdog. Choose a model for which your guest has drivers.
+
+The @var{action} controls what QEMU will do when the timer expires.
+The default is
+@code{reset} (forcefully reset the guest).
+Other possible actions are:
+@code{shutdown} (attempt to gracefully shutdown the guest),
+@code{poweroff} (forcefully poweroff the guest), or
+@code{pause} (pause the guest).
+
+Note that the @code{shutdown} action requires that the guest responds
+to ACPI signals, which it may not be able to do in the sort of
+situations where the watchdog would have expired, and thus
+@code{action=shutdown} is not recommended for production use.
+
+Use @code{-watchdog ?} to list available hardware models. Only one
+watchdog can be enabled for a guest.
+
+@table @code
+@item -watchdog i6300esb,action=pause
+@item -watchdog ib700
+@end table
+
@item -chroot dir
Immediately before starting guest execution, chroot to the specified
directory. Especially useful in combination with -runas.
Index: watchdog.h
===================================================================
--- watchdog.h (revision 0)
+++ watchdog.h (revision 0)
@@ -0,0 +1,56 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#ifndef QEMU_WATCHDOG_H
+#define QEMU_WATCHDOG_H
+
+extern const char *wdt_option;
+
+extern void watchdog_pc_init (PCIBus *pci_bus);
+extern void watchdog_perform_action (int action);
+
+struct wdt_methods {
+ /* If further option parsing is needed, do it here. */
+ void (*wdt_option) (const char *arg);
+ /* This callback should create/register the device. It is called
+ * indirectly from hw/pc.c when the virtual PC is being set up.
+ */
+ void (*wdt_pc_init) (PCIBus *pci_bus, int action);
+};
+typedef struct wdt_methods wdt_methods;
+
+struct wdt_model {
+ struct wdt_model *wdt_next;
+
+ /* Short name of the device - used to select it on the command line. */
+ const char *wdt_name;
+ /* Longer description (eg. manufacturer and full model number). */
+ const char *wdt_description;
+ /* Callbacks for this device. */
+ wdt_methods *wdt_methods;
+};
+typedef struct wdt_model wdt_model;
+
+/* Watchdog virtual devices add themselves to this linked list. */
+extern wdt_model *wdt_models;
+
+#endif /* QEMU_WATCHDOG_H */
Index: hw/wdt_i6300esb.c
===================================================================
--- hw/wdt_i6300esb.c (revision 0)
+++ hw/wdt_i6300esb.c (revision 0)
@@ -0,0 +1,538 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include <inttypes.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "watchdog.h"
+#include "wdt_i6300esb.h"
+#include "hw.h"
+#include "isa.h"
+#include "pc.h"
+#include "pci.h"
+
+/*#define I6300ESB_DEBUG 1*/
+
+#ifndef PCI_DEVICE_ID_INTEL_ESB_9
+#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
+#endif
+
+/* PCI configuration registers */
+#define ESB_CONFIG_REG 0x60 /* Config register */
+#define ESB_LOCK_REG 0x68 /* WDT lock register */
+
+/* Memory mapped registers (offset from base address) */
+#define ESB_TIMER1_REG 0x00 /* Timer1 value after each reset */
+#define ESB_TIMER2_REG 0x04 /* Timer2 value after each reset */
+#define ESB_GINTSR_REG 0x08 /* General Interrupt Status Register */
+#define ESB_RELOAD_REG 0x0c /* Reload register */
+
+/* Lock register bits */
+#define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */
+#define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */
+#define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */
+
+/* Config register bits */
+#define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */
+#define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */
+#define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */
+
+/* Reload register bits */
+#define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */
+
+/* Magic constants */
+#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
+#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
+
+/* Device state. */
+struct state {
+ PCIDevice dev; /* PCI device state, must be first field. */
+
+ int action; /* Action on expiry. */
+
+ int reboot_enabled; /* "Reboot" on timer expiry. The real action
+ * performed depends on the action=* param
+ * passed on QEMU command line.
+ */
+ int clock_scale; /* Clock scale. */
+#define CLOCK_SCALE_1KHZ 0
+#define CLOCK_SCALE_1MHZ 1
+
+ int int_type; /* Interrupt type generated. */
+#define INT_TYPE_IRQ 0 /* APIC 1, INT 10 */
+#define INT_TYPE_SMI 2
+#define INT_TYPE_DISABLED 3
+
+ int free_run; /* If true, reload timer on expiry. */
+ int locked; /* If true, enabled field cannot be changed. */
+ int enabled; /* If true, watchdog is enabled. */
+
+ QEMUTimer *timer; /* The actual watchdog timer. */
+
+ uint32_t timer1_preload; /* Values preloaded into timer1, timer2. */
+ uint32_t timer2_preload;
+ int stage; /* Stage (1 or 2). */
+
+ int unlock_state; /* Guest writes 0x80, 0x86 to unlock the
+ * registers, and we transition through
+ * states 0 -> 1 -> 2 when this happens.
+ */
+
+ int previous_reboot_flag; /* If the watchdog caused the previous
+ * reboot, this flag will be set.
+ */
+};
+
+typedef struct state state;
+
+static void i6300esb_pc_init (PCIBus *pci_bus, int action);
+static void i6300esb_map (PCIDevice *dev, int region_num, uint32_t addr, uint32_t size, int type);
+static void i6300esb_config_write (PCIDevice *dev, uint32_t addr, uint32_t data, int len);
+static uint32_t i6300esb_config_read (PCIDevice *dev, uint32_t addr, int len);
+static uint32_t i6300esb_mem_readb (void *vp, target_phys_addr_t addr);
+static uint32_t i6300esb_mem_readw (void *vp, target_phys_addr_t addr);
+static uint32_t i6300esb_mem_readl (void *vp, target_phys_addr_t addr);
+static void i6300esb_mem_writeb (void *vp, target_phys_addr_t addr, uint32_t val);
+static void i6300esb_mem_writew (void *vp, target_phys_addr_t addr, uint32_t val);
+static void i6300esb_mem_writel (void *vp, target_phys_addr_t addr, uint32_t val);
+static void i6300esb_restart_timer (state *, int stage);
+static void i6300esb_disable_timer (state *);
+static void i6300esb_timer_expired (void *vp);
+static void i6300esb_reset (state *d);
+static void i6300esb_save (QEMUFile *f, void *vp);
+static int i6300esb_load (QEMUFile *f, void *vp, int version);
+
+static wdt_methods i6300esb_wdt = {
+ .wdt_pc_init = i6300esb_pc_init,
+};
+
+static wdt_model model = {
+ .wdt_name = "i6300esb",
+ .wdt_description = "Intel 6300ESB",
+ .wdt_methods = &i6300esb_wdt,
+};
+
+void
+wdt_i6300esb_init (void)
+{
+ model.wdt_next = wdt_models;
+ wdt_models = &model;
+}
+
+/* Create and initialize a virtual Intel 6300ESB during PC creation. */
+static void
+i6300esb_pc_init (PCIBus *pci_bus, int action)
+{
+ state *d;
+ uint8_t *pci_conf;
+
+ if (!pci_bus) {
+ fprintf (stderr, "wdt_i6300esb: no PCI bus in this machine\n");
+ return;
+ }
+
+ d = (state *)
+ pci_register_device (pci_bus, "i6300esb_wdt", sizeof (state),
+ -1,
+ i6300esb_config_read, i6300esb_config_write);
+
+ d->action = action;
+ d->reboot_enabled = 1;
+ d->clock_scale = CLOCK_SCALE_1KHZ;
+ d->int_type = INT_TYPE_IRQ;
+ d->free_run = 0;
+ d->locked = 0;
+ d->enabled = 0;
+ d->timer = qemu_new_timer (vm_clock, i6300esb_timer_expired, d);
+ d->timer1_preload = 0xfffff;
+ d->timer2_preload = 0xfffff;
+ d->stage = 1;
+ d->unlock_state = 0;
+ d->previous_reboot_flag = 0;
+
+ pci_conf = d->dev.config;
+ pci_config_set_vendor_id (pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id (pci_conf, PCI_DEVICE_ID_INTEL_ESB_9);
+ pci_config_set_class (pci_conf, PCI_CLASS_SYSTEM_OTHER);
+ pci_conf[0x0e] = 0x00;
+
+ pci_register_io_region (&d->dev, 0, 0x10,
+ PCI_ADDRESS_SPACE_MEM, i6300esb_map);
+
+ register_savevm ("i6300esb_wdt", -1, sizeof (state),
+ i6300esb_save, i6300esb_load, d);
+}
+
+static void
+i6300esb_map (PCIDevice *dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ static CPUReadMemoryFunc *mem_read[3] = {
+ i6300esb_mem_readb,
+ i6300esb_mem_readw,
+ i6300esb_mem_readl,
+ };
+ static CPUWriteMemoryFunc *mem_write[3] = {
+ i6300esb_mem_writeb,
+ i6300esb_mem_writew,
+ i6300esb_mem_writel,
+ };
+ state *d = (state *) dev;
+ int io_mem;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_map: addr = %x, size = %x, type = %d\n",
+ addr, size, type);
+#endif
+
+ io_mem = cpu_register_io_memory (0, mem_read, mem_write, d);
+ cpu_register_physical_memory (addr, 0x10, io_mem);
+ /* qemu_register_coalesced_mmio (addr, 0x10); ? */
+}
+
+static void
+i6300esb_config_write (PCIDevice *dev, uint32_t addr, uint32_t data, int len)
+{
+ state *d = (state *) dev;
+ int old;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_config_write: addr = %x, data = %x, len = %d\n",
+ addr, data, len);
+#endif
+
+ if (addr == ESB_CONFIG_REG && len == 2) {
+ d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0;
+ d->clock_scale =
+ (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ;
+ d->int_type = (data & ESB_WDT_INTTYPE);
+ } else if (addr == ESB_LOCK_REG && len == 1) {
+ if (!d->locked) {
+ d->locked = (data & ESB_WDT_LOCK) != 0;
+ d->free_run = (data & ESB_WDT_FUNC) != 0;
+ old = d->enabled;
+ d->enabled = (data & ESB_WDT_ENABLE) != 0;
+ if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */
+ i6300esb_restart_timer (d, 1);
+ else if (!d->enabled)
+ i6300esb_disable_timer (d);
+ }
+ } else {
+ pci_default_write_config (dev, addr, data, len);
+ }
+}
+
+static uint32_t
+i6300esb_config_read (PCIDevice *dev, uint32_t addr, int len)
+{
+ state *d = (state *) dev;
+ uint32_t data;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_config_read: addr = %x, len = %d\n",
+ addr, len);
+#endif
+
+ if (addr == ESB_CONFIG_REG && len == 2) {
+ data =
+ (d->reboot_enabled ? 0 : ESB_WDT_REBOOT) |
+ (d->clock_scale == CLOCK_SCALE_1MHZ ? ESB_WDT_FREQ : 0) |
+ d->int_type;
+ return data;
+ } else if (addr == ESB_LOCK_REG && len == 1) {
+ data =
+ (d->free_run ? ESB_WDT_FUNC : 0) |
+ (d->locked ? ESB_WDT_LOCK : 0) |
+ (d->enabled ? ESB_WDT_ENABLE : 0);
+ return data;
+ } else {
+ return pci_default_read_config (dev, addr, len);
+ }
+}
+
+static uint32_t
+i6300esb_mem_readb (void *vp, target_phys_addr_t addr)
+{
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_mem_readb: addr = %x\n",
+ (int) addr);
+#endif
+
+ return 0;
+}
+
+static uint32_t
+i6300esb_mem_readw (void *vp, target_phys_addr_t addr)
+{
+ uint32_t data = 0;
+ state *d = (state *) vp;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_mem_readw: addr = %x\n",
+ (int) addr);
+#endif
+
+ if (addr == 0xc) {
+ /* The previous reboot flag is really bit 9, but there is
+ * a bug in the Linux driver where it thinks it's bit 12.
+ * Set both.
+ */
+ data = d->previous_reboot_flag ? 0x1200 : 0;
+ }
+
+ return data;
+}
+
+static uint32_t
+i6300esb_mem_readl (void *vp, target_phys_addr_t addr)
+{
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_mem_readl: addr = %x\n",
+ (int) addr);
+#endif
+
+ return 0;
+}
+
+static void
+i6300esb_mem_writeb (void *vp, target_phys_addr_t addr, uint32_t val)
+{
+ state *d = (state *) vp;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_mem_writeb: addr = %x, val = %x\n",
+ (int) addr, val);
+#endif
+
+ if (addr == 0xc && val == 0x80)
+ d->unlock_state = 1;
+ else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+ d->unlock_state = 2;
+}
+
+static void
+i6300esb_mem_writew (void *vp, target_phys_addr_t addr, uint32_t val)
+{
+ state *d = (state *) vp;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_mem_writew: addr = %x, val = %x\n",
+ (int) addr, val);
+#endif
+
+ if (addr == 0xc && val == 0x80)
+ d->unlock_state = 1;
+ else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+ d->unlock_state = 2;
+ else {
+ if (d->unlock_state == 2) {
+ if (addr == 0xc) {
+ if ((val & 0x100) != 0)
+ /* This is the "ping" from the userspace watchdog in
+ * the guest ...
+ */
+ i6300esb_restart_timer (d, 1);
+
+ /* Setting bit 9 resets the previous reboot flag.
+ * There's a bug in the Linux driver where it sets
+ * bit 12 instead.
+ */
+ if ((val & 0x200) != 0 || (val & 0x1000) != 0) {
+ d->previous_reboot_flag = 0;
+ }
+ }
+
+ d->unlock_state = 0;
+ }
+ }
+}
+
+static void
+i6300esb_mem_writel (void *vp, target_phys_addr_t addr, uint32_t val)
+{
+ state *d = (state *) vp;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_mem_writel: addr = %x, val = %x\n",
+ (int) addr, val);
+#endif
+
+ if (addr == 0xc && val == 0x80)
+ d->unlock_state = 1;
+ else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+ d->unlock_state = 2;
+ else {
+ if (d->unlock_state == 2) {
+ if (addr == 0)
+ d->timer1_preload = val & 0xfffff;
+ else if (addr == 4)
+ d->timer2_preload = val & 0xfffff;
+
+ d->unlock_state = 0;
+ }
+ }
+}
+
+/* This function is called when the watchdog has either been enabled
+ * (hence it starts counting down) or has been keep-alived.
+ */
+static void
+i6300esb_restart_timer (state *d, int stage)
+{
+ int64_t timeout;
+
+ if (!d->enabled) return;
+
+ d->stage = stage;
+
+ if (d->stage <= 1)
+ timeout = d->timer1_preload;
+ else
+ timeout = d->timer2_preload;
+
+ if (d->clock_scale == CLOCK_SCALE_1KHZ)
+ timeout <<= 15;
+ else
+ timeout <<= 5;
+
+ /* Get the timeout in units of ticks_per_sec. */
+ timeout = ticks_per_sec * timeout / 33000000;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_restart_timer: stage %d, timeout %" PRIi64 "\n",
+ d->stage, timeout);
+#endif
+
+ qemu_mod_timer (d->timer, qemu_get_clock (vm_clock) + timeout);
+}
+
+/* This is called when the guest disables the watchdog. */
+static void
+i6300esb_disable_timer (state *d)
+{
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_disable_timer: timer disabled\n");
+#endif
+
+ qemu_del_timer (d->timer);
+}
+
+/* This function is called when the watchdog expires. Note that
+ * the hardware has two timers, and so expiry happens in two stages.
+ * If d->stage == 1 then we perform the first stage action (usually,
+ * sending an interrupt) and then restart the timer again for the
+ * second stage. If the second stage expires then the watchdog
+ * really has run out.
+ */
+static void
+i6300esb_timer_expired (void *vp)
+{
+ state *d = (state *) vp;
+
+#ifdef I6300ESB_DEBUG
+ fprintf (stderr, "i6300esb_timer_expired: stage %d\n", d->stage);
+#endif
+
+ if (d->stage == 1) {
+ /* What to do at the end of stage 1? */
+ switch (d->int_type) {
+ case INT_TYPE_IRQ:
+ fprintf (stderr, "i6300esb_timer_expired: I would send APIC 1 INT 10 here if I knew how (XXX)\n");
+ break;
+ case INT_TYPE_SMI:
+ fprintf (stderr, "i6300esb_timer_expired: I would send SMI here if I knew how (XXX)\n");
+ break;
+ }
+
+ /* Start the second stage. */
+ i6300esb_restart_timer (d, 2);
+ } else {
+ /* Second stage expired, reboot for real. */
+ if (d->reboot_enabled) {
+ d->previous_reboot_flag = 1;
+ watchdog_perform_action (d->action); /* This reboots, exits, etc */
+ i6300esb_reset (d);
+ }
+
+ /* In "free running mode" we start stage 1 again. */
+ if (d->free_run)
+ i6300esb_restart_timer (d, 1);
+ }
+}
+
+static void
+i6300esb_reset (state *d)
+{
+ /* XXX We should probably reset other parts of the state here,
+ * but we should also reset our state on general machine reset
+ * too. For now just disable the timer so it doesn't fire
+ * again after the reboot.
+ */
+ i6300esb_disable_timer (d);
+}
+
+static void
+i6300esb_save (QEMUFile *f, void *vp)
+{
+ state *d = (state *) vp;
+
+ pci_device_save (&d->dev, f);
+ qemu_put_be32 (f, d->action);
+ qemu_put_be32 (f, d->reboot_enabled);
+ qemu_put_be32 (f, d->clock_scale);
+ qemu_put_be32 (f, d->int_type);
+ qemu_put_be32 (f, d->free_run);
+ qemu_put_be32 (f, d->locked);
+ qemu_put_be32 (f, d->enabled);
+ qemu_put_timer (f, d->timer);
+ qemu_put_be32 (f, d->timer1_preload);
+ qemu_put_be32 (f, d->timer2_preload);
+ qemu_put_be32 (f, d->stage);
+ qemu_put_be32 (f, d->unlock_state);
+ qemu_put_be32 (f, d->previous_reboot_flag);
+}
+
+static int
+i6300esb_load (QEMUFile *f, void *vp, int version)
+{
+ state *d = (state *) vp;
+
+ if (version != sizeof (state)) return -EINVAL;
+
+ pci_device_load (&d->dev, f);
+ d->action = qemu_get_be32 (f);
+ d->reboot_enabled = qemu_get_be32 (f);
+ d->clock_scale = qemu_get_be32 (f);
+ d->int_type = qemu_get_be32 (f);
+ d->free_run = qemu_get_be32 (f);
+ d->locked = qemu_get_be32 (f);
+ d->enabled = qemu_get_be32 (f);
+ qemu_get_timer (f, d->timer);
+ d->timer1_preload = qemu_get_be32 (f);
+ d->timer2_preload = qemu_get_be32 (f);
+ d->stage = qemu_get_be32 (f);
+ d->unlock_state = qemu_get_be32 (f);
+ d->previous_reboot_flag = qemu_get_be32 (f);
+
+ return 0;
+}
Index: hw/wdt_i6300esb.h
===================================================================
--- hw/wdt_i6300esb.h (revision 0)
+++ hw/wdt_i6300esb.h (revision 0)
@@ -0,0 +1,28 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#ifndef QEMU_WDT_I6300ESB_H
+#define QEMU_WDT_I6300ESB_H
+
+extern void wdt_i6300esb_init (void);
+
+#endif /* QEMU_WDT_I6300ESB_H */
Index: hw/wdt_ib700.c
===================================================================
--- hw/wdt_ib700.c (revision 0)
+++ hw/wdt_ib700.c (revision 0)
@@ -0,0 +1,137 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "watchdog.h"
+#include "wdt_ib700.h"
+#include "hw.h"
+#include "isa.h"
+#include "pc.h"
+
+/*#define IB700_DEBUG 1*/
+
+static void ib700_pc_init (PCIBus *unused, int action);
+static void ib700_write_enable_reg (void *vp, uint32_t addr, uint32_t data);
+static void ib700_write_disable_reg (void *vp, uint32_t addr, uint32_t data);
+static void ib700_timer_expired (void *vp);
+static void ib700_save (QEMUFile *f, void *vp);
+static int ib700_load (QEMUFile *f, void *vp, int version);
+
+/* This is the timer. We use a global here because the watchdog
+ * code ensures there is only one watchdog (it is located at a fixed,
+ * unchangable IO port, so there could only ever be one anyway).
+ */
+static QEMUTimer *timer = NULL;
+static int action = 0;
+
+static wdt_methods ib700_wdt = {
+ .wdt_pc_init = ib700_pc_init,
+};
+
+static wdt_model model = {
+ .wdt_name = "ib700",
+ .wdt_description = "iBASE 700",
+ .wdt_methods = &ib700_wdt,
+};
+
+void
+wdt_ib700_init (void)
+{
+ model.wdt_next = wdt_models;
+ wdt_models = &model;
+
+ timer = qemu_new_timer (vm_clock, ib700_timer_expired, NULL);
+}
+
+/* Create and initialize a virtual IB700 during PC creation. */
+static void
+ib700_pc_init (PCIBus *unused, int _action)
+{
+ register_savevm ("ib700_wdt", -1, 0, ib700_save, ib700_load, NULL);
+
+ register_ioport_write (0x441, 2, 1, ib700_write_disable_reg, NULL);
+ register_ioport_write (0x443, 2, 1, ib700_write_enable_reg, NULL);
+
+ action = _action;
+}
+
+/* A write to this register enables the timer. */
+static void
+ib700_write_enable_reg (void *vp, uint32_t addr, uint32_t data)
+{
+ static int time_map[] = {
+ 30, 28, 26, 24, 22, 20, 18, 16,
+ 14, 12, 10, 8, 6, 4, 2, 0
+ };
+ int64 timeout;
+
+#ifdef IB700_DEBUG
+ fprintf (stderr, "ib700_write_enable_reg: addr = %x, data = %x\n",
+ addr, data);
+#endif
+
+ timeout = (int64_t) time_map[data & 0xF] * ticks_per_sec;
+ qemu_mod_timer (timer, qemu_get_clock (vm_clock) + timeout);
+}
+
+/* A write (of any value) to this register disables the timer. */
+static void
+ib700_write_disable_reg (void *vp, uint32_t addr, uint32_t data)
+{
+#ifdef IB700_DEBUG
+ fprintf (stderr, "ib700_write_disable_reg: addr = %x, data = %x\n",
+ addr, data);
+#endif
+
+ qemu_del_timer (timer);
+}
+
+/* This is called when the watchdog expires. */
+static void
+ib700_timer_expired (void *vp)
+{
+#ifdef IB700_DEBUG
+ fprintf (stderr, "ib700_timer_expired: watchdog expired\n");
+#endif
+
+ watchdog_perform_action (action);
+ qemu_del_timer (timer);
+}
+
+static void
+ib700_save (QEMUFile *f, void *vp)
+{
+ qemu_put_timer (f, timer);
+ qemu_put_be32 (f, action);
+}
+
+static int
+ib700_load (QEMUFile *f, void *vp, int version)
+{
+ if (version != 0) return -EINVAL;
+
+ qemu_get_timer (f, timer);
+ action = qemu_get_be32 (f);
+
+ return 0;
+}
Index: hw/wdt_ib700.h
===================================================================
--- hw/wdt_ib700.h (revision 0)
+++ hw/wdt_ib700.h (revision 0)
@@ -0,0 +1,28 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#ifndef QEMU_WDT_IB700_H
+#define QEMU_WDT_IB700_H
+
+extern void wdt_ib700_init (void);
+
+#endif /* QEMU_WDT_IB700_H */
Index: hw/pc.c
===================================================================
--- hw/pc.c (revision 6718)
+++ hw/pc.c (working copy)
@@ -37,6 +37,9 @@
#include "virtio-balloon.h"
#include "virtio-console.h"
#include "hpet_emul.h"
+#include "wdt_ib700.h"
+#include "wdt_i6300esb.h"
+#include "watchdog.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -1007,6 +1010,10 @@
}
}
+ wdt_ib700_init ();
+ wdt_i6300esb_init ();
+ watchdog_pc_init (pci_bus);
+
for(i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4)
2009-03-06 18:29 [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4) Richard W.M. Jones
@ 2009-03-06 18:32 ` Richard W.M. Jones
2009-03-11 10:48 ` Richard W.M. Jones
2009-03-11 20:30 ` Anthony Liguori
2 siblings, 0 replies; 5+ messages in thread
From: Richard W.M. Jones @ 2009-03-06 18:32 UTC (permalink / raw)
To: qemu-devel
On Fri, Mar 06, 2009 at 06:29:50PM +0000, Richard W.M. Jones wrote:
> instead of _QEMU_* (thanks Marc for pointing this out).
s/Marc/malc/
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine. Supports Linux and Windows.
http://et.redhat.com/~rjones/virt-df/
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4)
2009-03-06 18:29 [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4) Richard W.M. Jones
2009-03-06 18:32 ` Richard W.M. Jones
@ 2009-03-11 10:48 ` Richard W.M. Jones
2009-03-11 20:30 ` Anthony Liguori
2 siblings, 0 replies; 5+ messages in thread
From: Richard W.M. Jones @ 2009-03-11 10:48 UTC (permalink / raw)
To: qemu-devel
On Fri, Mar 06, 2009 at 06:29:50PM +0000, Richard W.M. Jones wrote:
> This is the hardware virtual watchdogs patch.
Anyone? This is a pretty useful little feature ...
Rich.
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4)
2009-03-06 18:29 [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4) Richard W.M. Jones
2009-03-06 18:32 ` Richard W.M. Jones
2009-03-11 10:48 ` Richard W.M. Jones
@ 2009-03-11 20:30 ` Anthony Liguori
2009-03-13 17:26 ` Blue Swirl
2 siblings, 1 reply; 5+ messages in thread
From: Anthony Liguori @ 2009-03-11 20:30 UTC (permalink / raw)
To: qemu-devel
Richard W.M. Jones wrote:
> This is the hardware virtual watchdogs patch. The only change since
> the last time I posted it[1] is that I've rebased to latest SVN and
> I've changed the header files to use non-reserved QEMU_* symbols
> instead of _QEMU_* (thanks Marc for pointing this out).
>
> Rich.
>
> [1] http://lists.gnu.org/archive/html/qemu-devel/2009-03/msg00050.html
> http://lists.gnu.org/archive/html/qemu-devel/2009-02/msg01434.html
> http://lists.gnu.org/archive/html/qemu-devel/2009-02/msg01404.html
>
>
>
> Index: Makefile.target
> ===================================================================
> --- Makefile.target (revision 6718)
> +++ Makefile.target (working copy)
> @@ -584,6 +584,7 @@
> OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
> OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
> OBJS += device-hotplug.o pci-hotplug.o
> +OBJS+= wdt_ib700.o wdt_i6300esb.o
> CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
> endif
> ifeq ($(TARGET_BASE_ARCH), ppc)
> Index: vl.c
> ===================================================================
> --- vl.c (revision 6718)
> +++ vl.c (working copy)
> @@ -43,6 +43,7 @@
> #include "migration.h"
> #include "kvm.h"
> #include "balloon.h"
> +#include "watchdog.h"
>
> #include <unistd.h>
> #include <fcntl.h>
> @@ -4103,6 +4104,8 @@
> "-old-param old param mode\n"
> #endif
> "-tb-size n set TB size\n"
> + "-watchdog ib700|i6300esb[,action=reset|shutdown|poweroff|pause]\n"
> + " enable virtual hardware watchdog [default=none]\n"
>
It would be good to have two separate options. One that enabled the
watch dog device and then another that controlled what the behavior of
it is. The goal is to separate guest configuration information from how
the emulated device is configured in the host. If it's not already
there, the host configuration should be changable via the monitor too.
> ifdef CONFIG_BRLAPI
> OBJS+= baum.o
> Index: watchdog.c
> ===================================================================
> --- watchdog.c (revision 0)
> +++ watchdog.c (revision 0)
> @@ -0,0 +1,161 @@
> +/*
> + * Virtual hardware watchdog.
> + *
> + * Copyright (C) 2009 Red Hat Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + * By Richard W.M. Jones (rjones@redhat.com).
> + */
> +
> +#include "qemu-common.h"
> +#include "sysemu.h"
> +#include "hw/wdt_ib700.h"
> +#include "hw/wdt_i6300esb.h"
> +#include "watchdog.h"
> +
> +/* Possible values for action parameter. */
> +#define WDT_RESET 1
> +#define WDT_SHUTDOWN 2
> +#define WDT_POWEROFF 3
> +#define WDT_PAUSE 4
> +
> +static void parse_option (const char *arg, int *action_r);
> +static void parse_rest (const char *rest, int *action_r);
> +
> +/* Linked list of models - virtual watchdog devices add themselves
> + * to this list.
> + */
> +wdt_model *wdt_models = NULL;
>
This isn't QEMU style. WatchdogTimerModel would be. Also, you can use
the macros in sys-queue.h for lists.
> +/* The raw -watchdog option specified on the command line. */
> +const char *wdt_option = NULL;
>
I'd rather that command line arguments be parsed in vl.c to cleanly
separate things. If you do my above suggestion about splitting up
options though, this problem goes away.
> +static wdt_model *wdt = NULL;
> +
> +/* Called from the PC code to parse the option and finally configure
> + * the device.
> + */
> +void
> +watchdog_pc_init (PCIBus *pci_bus)
> +{
> + int action;
> +
> + if (!wdt_option) return;
> + parse_option (wdt_option, &action);
> + if (!wdt) return; /* No watchdog configured. */
> + wdt->wdt_methods->wdt_pc_init (pci_bus, action);
> +}
>
If this is a PCI device, it should be hot pluggable, right?
The normal thing is for pc.c to directly call the device
initialization. Definitely don't want to wait until then to parse the
options.
> +/* Device state. */
> +struct state {
> + PCIDevice dev; /* PCI device state, must be first field. */
> +
> + int action; /* Action on expiry. */
> +
> + int reboot_enabled; /* "Reboot" on timer expiry. The real action
> + * performed depends on the action=* param
> + * passed on QEMU command line.
> + */
> + int clock_scale; /* Clock scale. */
> +#define CLOCK_SCALE_1KHZ 0
> +#define CLOCK_SCALE_1MHZ 1
> +
> + int int_type; /* Interrupt type generated. */
> +#define INT_TYPE_IRQ 0 /* APIC 1, INT 10 */
> +#define INT_TYPE_SMI 2
> +#define INT_TYPE_DISABLED 3
> +
> + int free_run; /* If true, reload timer on expiry. */
> + int locked; /* If true, enabled field cannot be changed. */
> + int enabled; /* If true, watchdog is enabled. */
> +
> + QEMUTimer *timer; /* The actual watchdog timer. */
> +
> + uint32_t timer1_preload; /* Values preloaded into timer1, timer2. */
> + uint32_t timer2_preload;
> + int stage; /* Stage (1 or 2). */
> +
> + int unlock_state; /* Guest writes 0x80, 0x86 to unlock the
> + * registers, and we transition through
> + * states 0 -> 1 -> 2 when this happens.
> + */
> +
> + int previous_reboot_flag; /* If the watchdog caused the previous
> + * reboot, this flag will be set.
> + */
> +};
> +
> +typedef struct state state;
>
Way too generic of a type name.
> +static void i6300esb_pc_init (PCIBus *pci_bus, int action);
> +static void i6300esb_map (PCIDevice *dev, int region_num, uint32_t addr, uint32_t size, int type);
> +static void i6300esb_config_write (PCIDevice *dev, uint32_t addr, uint32_t data, int len);
> +static uint32_t i6300esb_config_read (PCIDevice *dev, uint32_t addr, int len);
> +static uint32_t i6300esb_mem_readb (void *vp, target_phys_addr_t addr);
> +static uint32_t i6300esb_mem_readw (void *vp, target_phys_addr_t addr);
> +static uint32_t i6300esb_mem_readl (void *vp, target_phys_addr_t addr);
> +static void i6300esb_mem_writeb (void *vp, target_phys_addr_t addr, uint32_t val);
> +static void i6300esb_mem_writew (void *vp, target_phys_addr_t addr, uint32_t val);
> +static void i6300esb_mem_writel (void *vp, target_phys_addr_t addr, uint32_t val);
> +static void i6300esb_restart_timer (state *, int stage);
> +static void i6300esb_disable_timer (state *);
> +static void i6300esb_timer_expired (void *vp);
> +static void i6300esb_reset (state *d);
> +static void i6300esb_save (QEMUFile *f, void *vp);
> +static int i6300esb_load (QEMUFile *f, void *vp, int version);
>
If you have to predefine all of these, you're probably doing something
wrong...
> +static wdt_methods i6300esb_wdt = {
> + .wdt_pc_init = i6300esb_pc_init,
> +};
> +
> +static wdt_model model = {
> + .wdt_name = "i6300esb",
> + .wdt_description = "Intel 6300ESB",
> + .wdt_methods = &i6300esb_wdt,
> +};
> +
> +void
> +wdt_i6300esb_init (void)
> +{
> + model.wdt_next = wdt_models;
> + wdt_models = &model;
> +}
> +
> +/* Create and initialize a virtual Intel 6300ESB during PC creation. */
> +static void
> +i6300esb_pc_init (PCIBus *pci_bus, int action)
> +{
> + state *d;
> + uint8_t *pci_conf;
> +
> + if (!pci_bus) {
> + fprintf (stderr, "wdt_i6300esb: no PCI bus in this machine\n");
> + return;
> + }
> +
> + d = (state *)
> + pci_register_device (pci_bus, "i6300esb_wdt", sizeof (state),
> + -1,
> + i6300esb_config_read, i6300esb_config_write);
> +
> + d->action = action;
>
The device emulation shouldn't need to know the action. It should
notify something else via a callback.
> +
> +static void
> +i6300esb_config_write (PCIDevice *dev, uint32_t addr, uint32_t data, int len)
> +{
> + state *d = (state *) dev;
> + int old;
> +
> +#ifdef I6300ESB_DEBUG
> + fprintf (stderr, "i6300esb_config_write: addr = %x, data = %x, len = %d\n",
> + addr, data, len);
> +#endif
>
A debug macro would be nicer.
> +static void
> +i6300esb_save (QEMUFile *f, void *vp)
> +{
> + state *d = (state *) vp;
> +
> + pci_device_save (&d->dev, f);
> + qemu_put_be32 (f, d->action);
> + qemu_put_be32 (f, d->reboot_enabled);
> + qemu_put_be32 (f, d->clock_scale);
> + qemu_put_be32 (f, d->int_type);
> + qemu_put_be32 (f, d->free_run);
> + qemu_put_be32 (f, d->locked);
> + qemu_put_be32 (f, d->enabled);
> + qemu_put_timer (f, d->timer);
> + qemu_put_be32 (f, d->timer1_preload);
> + qemu_put_be32 (f, d->timer2_preload);
> + qemu_put_be32 (f, d->stage);
> + qemu_put_be32 (f, d->unlock_state);
> + qemu_put_be32 (f, d->previous_reboot_flag);
> +}
>
host state such as action should not be in the save/restore format.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4)
2009-03-11 20:30 ` Anthony Liguori
@ 2009-03-13 17:26 ` Blue Swirl
0 siblings, 0 replies; 5+ messages in thread
From: Blue Swirl @ 2009-03-13 17:26 UTC (permalink / raw)
To: qemu-devel
On 3/11/09, Anthony Liguori <aliguori@us.ibm.com> wrote:
> Richard W.M. Jones wrote:
>
> > This is the hardware virtual watchdogs patch. The only change since
> > the last time I posted it[1] is that I've rebased to latest SVN and
> > I've changed the header files to use non-reserved QEMU_* symbols
> > instead of _QEMU_* (thanks Marc for pointing this out).
> >
> > Rich.
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Please update the FSF address.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-03-13 17:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-06 18:29 [Qemu-devel] [PATCH] Hardware watchdogs (minor update, version 4) Richard W.M. Jones
2009-03-06 18:32 ` Richard W.M. Jones
2009-03-11 10:48 ` Richard W.M. Jones
2009-03-11 20:30 ` Anthony Liguori
2009-03-13 17:26 ` Blue Swirl
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).