7839ff593b
This causes two slight backwards-incompatibilities between "-M pc-1.5" and 1.5's "-M pc": (1) a fw_cfg file is removed with this patch. This is only a problem if migration stops the virtual machine exactly during fw_cfg enumeration. (2) after migration, a VM created without an explicit "-device pvpanic" will stop reporting panics to management. The first problem only occurs if migration is done at a very, very early point (and I'm not sure it can happen in practice for reasonable-size VMs, since it will likely take more time to send the RAM to destination, than it will take for BIOS to scan fw_cfg). The second problem only occurs if the guest panics _and_ has a guest driver _and_ management knows to look at the crash event, so it is mostly theoretical at this point in time. Thus keep the code simple, and pretend it was never broken. Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
154 lines
3.7 KiB
C
154 lines
3.7 KiB
C
/*
|
|
* QEMU simulated pvpanic device.
|
|
*
|
|
* Copyright Fujitsu, Corp. 2013
|
|
*
|
|
* Authors:
|
|
* Wen Congyang <wency@cn.fujitsu.com>
|
|
* Hu Tao <hutao@cn.fujitsu.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
* See the COPYING file in the top-level directory.
|
|
*
|
|
*/
|
|
|
|
#include "qapi/qmp/qobject.h"
|
|
#include "qapi/qmp/qjson.h"
|
|
#include "monitor/monitor.h"
|
|
#include "sysemu/sysemu.h"
|
|
#include "qemu/log.h"
|
|
|
|
#include "hw/nvram/fw_cfg.h"
|
|
#include "hw/i386/pc.h"
|
|
|
|
/* The bit of supported pv event */
|
|
#define PVPANIC_F_PANICKED 0
|
|
|
|
/* The pv event value */
|
|
#define PVPANIC_PANICKED (1 << PVPANIC_F_PANICKED)
|
|
|
|
#define TYPE_ISA_PVPANIC_DEVICE "pvpanic"
|
|
#define ISA_PVPANIC_DEVICE(obj) \
|
|
OBJECT_CHECK(PVPanicState, (obj), TYPE_ISA_PVPANIC_DEVICE)
|
|
|
|
static void panicked_mon_event(const char *action)
|
|
{
|
|
QObject *data;
|
|
|
|
data = qobject_from_jsonf("{ 'action': %s }", action);
|
|
monitor_protocol_event(QEVENT_GUEST_PANICKED, data);
|
|
qobject_decref(data);
|
|
}
|
|
|
|
static void handle_event(int event)
|
|
{
|
|
static bool logged;
|
|
|
|
if (event & ~PVPANIC_PANICKED && !logged) {
|
|
qemu_log_mask(LOG_GUEST_ERROR, "pvpanic: unknown event %#x.\n", event);
|
|
logged = true;
|
|
}
|
|
|
|
if (event & PVPANIC_PANICKED) {
|
|
panicked_mon_event("pause");
|
|
vm_stop(RUN_STATE_GUEST_PANICKED);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#include "hw/isa/isa.h"
|
|
|
|
typedef struct PVPanicState {
|
|
ISADevice parent_obj;
|
|
|
|
MemoryRegion io;
|
|
uint16_t ioport;
|
|
} PVPanicState;
|
|
|
|
/* return supported events on read */
|
|
static uint64_t pvpanic_ioport_read(void *opaque, hwaddr addr, unsigned size)
|
|
{
|
|
return PVPANIC_PANICKED;
|
|
}
|
|
|
|
static void pvpanic_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
|
unsigned size)
|
|
{
|
|
handle_event(val);
|
|
}
|
|
|
|
static const MemoryRegionOps pvpanic_ops = {
|
|
.read = pvpanic_ioport_read,
|
|
.write = pvpanic_ioport_write,
|
|
.impl = {
|
|
.min_access_size = 1,
|
|
.max_access_size = 1,
|
|
},
|
|
};
|
|
|
|
static void pvpanic_isa_initfn(Object *obj)
|
|
{
|
|
PVPanicState *s = ISA_PVPANIC_DEVICE(obj);
|
|
|
|
memory_region_init_io(&s->io, OBJECT(s), &pvpanic_ops, s, "pvpanic", 1);
|
|
}
|
|
|
|
static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
|
|
{
|
|
ISADevice *d = ISA_DEVICE(dev);
|
|
PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
|
|
FWCfgState *fw_cfg = fw_cfg_find();
|
|
uint16_t *pvpanic_port;
|
|
|
|
if (!fw_cfg) {
|
|
return;
|
|
}
|
|
|
|
pvpanic_port = g_malloc(sizeof(*pvpanic_port));
|
|
*pvpanic_port = cpu_to_le16(s->ioport);
|
|
fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
|
|
sizeof(*pvpanic_port));
|
|
|
|
isa_register_ioport(d, &s->io, s->ioport);
|
|
}
|
|
|
|
#define PVPANIC_IOPORT_PROP "ioport"
|
|
|
|
uint16_t pvpanic_port(void)
|
|
{
|
|
Object *o = object_resolve_path_type("", TYPE_ISA_PVPANIC_DEVICE, NULL);
|
|
if (!o) {
|
|
return 0;
|
|
}
|
|
return object_property_get_int(o, PVPANIC_IOPORT_PROP, NULL);
|
|
}
|
|
|
|
static Property pvpanic_isa_properties[] = {
|
|
DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicState, ioport, 0x505),
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
};
|
|
|
|
static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
dc->realize = pvpanic_isa_realizefn;
|
|
dc->props = pvpanic_isa_properties;
|
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
|
}
|
|
|
|
static TypeInfo pvpanic_isa_info = {
|
|
.name = TYPE_ISA_PVPANIC_DEVICE,
|
|
.parent = TYPE_ISA_DEVICE,
|
|
.instance_size = sizeof(PVPanicState),
|
|
.instance_init = pvpanic_isa_initfn,
|
|
.class_init = pvpanic_isa_class_init,
|
|
};
|
|
|
|
static void pvpanic_register_types(void)
|
|
{
|
|
type_register_static(&pvpanic_isa_info);
|
|
}
|
|
|
|
type_init(pvpanic_register_types)
|