[PATCH v11 5/6] introduce a new qom device to deal with panicked event
If the target is x86/x86_64, the guest's kernel will write 0x01 to the port KVM_PV_EVENT_PORT when it is panciked. This patch introduces a new qom device kvm_pv_ioport to listen this I/O port, and deal with panicked event according to panicked_action's value. The possible actions are: 1. emit QEVENT_GUEST_PANICKED only 2. emit QEVENT_GUEST_PANICKED and pause the guest 3. emit QEVENT_GUEST_PANICKED and poweroff the guest 4. emit QEVENT_GUEST_PANICKED and reset the guest I/O ports does not work for some targets(for example: s390). And you can implement another qom device, and include it's code into pv_event.c for such target. Note: if we emit QEVENT_GUEST_PANICKED only, and the management application does not receive this event(the management may not run when the event is emitted), the management won't know the guest is panicked. Signed-off-by: Wen Congyang Signed-off-by: Hu Tao --- hw/kvm/Makefile.objs |2 +- hw/kvm/pv_event.c| 197 ++ hw/pc_piix.c |5 ++ kvm-stub.c |4 + kvm.h|2 + 5 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 hw/kvm/pv_event.c diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs index f620d7f..cf93199 100644 --- a/hw/kvm/Makefile.objs +++ b/hw/kvm/Makefile.objs @@ -1 +1 @@ -obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o pv_event.o diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c new file mode 100644 index 000..112491e --- /dev/null +++ b/hw/kvm/pv_event.c @@ -0,0 +1,197 @@ +/* + * QEMU KVM support, paravirtual event device + * + * Copyright Fujitsu, Corp. 2012 + * + * Authors: + * Wen Congyang + * + * 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 +#include +#include +#include +#include +#include +#include + +/* Possible values for action parameter. */ +#define PANICKED_REPORT 1 /* emit QEVENT_GUEST_PANICKED only */ +#define PANICKED_PAUSE 2 /* emit QEVENT_GUEST_PANICKED and pause VM */ +#define PANICKED_POWEROFF 3 /* emit QEVENT_GUEST_PANICKED and quit VM */ +#define PANICKED_RESET 4 /* emit QEVENT_GUEST_PANICKED and reset VM */ + +#define PV_EVENT_DRIVER "kvm_pv_event" + +struct PVEventAction { +char *panicked_action; +int panicked_action_value; +}; + +#define DEFINE_PV_EVENT_PROPERTIES(_state, _conf) \ +DEFINE_PROP_STRING("panicked_action", _state, _conf.panicked_action) + +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 panicked_perform_action(uint32_t panicked_action) +{ +switch (panicked_action) { +case PANICKED_REPORT: +panicked_mon_event("report"); +break; + +case PANICKED_PAUSE: +panicked_mon_event("pause"); +vm_stop(RUN_STATE_GUEST_PANICKED); +break; + +case PANICKED_POWEROFF: +panicked_mon_event("poweroff"); +qemu_system_shutdown_request(); +break; + +case PANICKED_RESET: +panicked_mon_event("reset"); +qemu_system_reset_request(); +break; +} +} + +static uint64_t supported_event(void) +{ +return 1 << KVM_PV_FEATURE_PANICKED; +} + +static void handle_event(int event, struct PVEventAction *conf) +{ +if (event == KVM_PV_EVENT_PANICKED) { +panicked_perform_action(conf->panicked_action_value); +} +} + +static int pv_event_init(struct PVEventAction *conf) +{ +if (!conf->panicked_action) { +conf->panicked_action_value = PANICKED_REPORT; +} else if (strcasecmp(conf->panicked_action, "none") == 0) { +conf->panicked_action_value = PANICKED_REPORT; +} else if (strcasecmp(conf->panicked_action, "pause") == 0) { +conf->panicked_action_value = PANICKED_PAUSE; +} else if (strcasecmp(conf->panicked_action, "poweroff") == 0) { +conf->panicked_action_value = PANICKED_POWEROFF; +} else if (strcasecmp(conf->panicked_action, "reset") == 0) { +conf->panicked_action_value = PANICKED_RESET; +} else { +return -1; +} + +return 0; +} + +#if defined(KVM_PV_EVENT_PORT) + +#include "hw/isa.h" + +typedef struct { +ISADevice dev; +struct PVEventAction conf; +MemoryRegion ioport; +} PVIOPortState; + +static uint64_t pv_io_read(void *opaque, hwaddr addr, unsigned size) +{ +return supported_event(); +} + +static void pv_io_write(void *opaque, hwaddr addr, uint64_t val, +unsigned size) +{ +PVIOPortState *s = opaque; + +handle_event(val, >conf); +} + +static const MemoryRegionOps pv_io_ops = { +.read = pv_io_read, +.write = pv_io_write, +.impl = { +
[PATCH v11 5/6] introduce a new qom device to deal with panicked event
If the target is x86/x86_64, the guest's kernel will write 0x01 to the port KVM_PV_EVENT_PORT when it is panciked. This patch introduces a new qom device kvm_pv_ioport to listen this I/O port, and deal with panicked event according to panicked_action's value. The possible actions are: 1. emit QEVENT_GUEST_PANICKED only 2. emit QEVENT_GUEST_PANICKED and pause the guest 3. emit QEVENT_GUEST_PANICKED and poweroff the guest 4. emit QEVENT_GUEST_PANICKED and reset the guest I/O ports does not work for some targets(for example: s390). And you can implement another qom device, and include it's code into pv_event.c for such target. Note: if we emit QEVENT_GUEST_PANICKED only, and the management application does not receive this event(the management may not run when the event is emitted), the management won't know the guest is panicked. Signed-off-by: Wen Congyang we...@cn.fujitsu.com Signed-off-by: Hu Tao hu...@cn.fujitsu.com --- hw/kvm/Makefile.objs |2 +- hw/kvm/pv_event.c| 197 ++ hw/pc_piix.c |5 ++ kvm-stub.c |4 + kvm.h|2 + 5 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 hw/kvm/pv_event.c diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs index f620d7f..cf93199 100644 --- a/hw/kvm/Makefile.objs +++ b/hw/kvm/Makefile.objs @@ -1 +1 @@ -obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o pv_event.o diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c new file mode 100644 index 000..112491e --- /dev/null +++ b/hw/kvm/pv_event.c @@ -0,0 +1,197 @@ +/* + * QEMU KVM support, paravirtual event device + * + * Copyright Fujitsu, Corp. 2012 + * + * Authors: + * Wen Congyang we...@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 linux/kvm_para.h +#include asm/kvm_para.h +#include qobject.h +#include qjson.h +#include monitor.h +#include sysemu.h +#include kvm.h + +/* Possible values for action parameter. */ +#define PANICKED_REPORT 1 /* emit QEVENT_GUEST_PANICKED only */ +#define PANICKED_PAUSE 2 /* emit QEVENT_GUEST_PANICKED and pause VM */ +#define PANICKED_POWEROFF 3 /* emit QEVENT_GUEST_PANICKED and quit VM */ +#define PANICKED_RESET 4 /* emit QEVENT_GUEST_PANICKED and reset VM */ + +#define PV_EVENT_DRIVER kvm_pv_event + +struct PVEventAction { +char *panicked_action; +int panicked_action_value; +}; + +#define DEFINE_PV_EVENT_PROPERTIES(_state, _conf) \ +DEFINE_PROP_STRING(panicked_action, _state, _conf.panicked_action) + +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 panicked_perform_action(uint32_t panicked_action) +{ +switch (panicked_action) { +case PANICKED_REPORT: +panicked_mon_event(report); +break; + +case PANICKED_PAUSE: +panicked_mon_event(pause); +vm_stop(RUN_STATE_GUEST_PANICKED); +break; + +case PANICKED_POWEROFF: +panicked_mon_event(poweroff); +qemu_system_shutdown_request(); +break; + +case PANICKED_RESET: +panicked_mon_event(reset); +qemu_system_reset_request(); +break; +} +} + +static uint64_t supported_event(void) +{ +return 1 KVM_PV_FEATURE_PANICKED; +} + +static void handle_event(int event, struct PVEventAction *conf) +{ +if (event == KVM_PV_EVENT_PANICKED) { +panicked_perform_action(conf-panicked_action_value); +} +} + +static int pv_event_init(struct PVEventAction *conf) +{ +if (!conf-panicked_action) { +conf-panicked_action_value = PANICKED_REPORT; +} else if (strcasecmp(conf-panicked_action, none) == 0) { +conf-panicked_action_value = PANICKED_REPORT; +} else if (strcasecmp(conf-panicked_action, pause) == 0) { +conf-panicked_action_value = PANICKED_PAUSE; +} else if (strcasecmp(conf-panicked_action, poweroff) == 0) { +conf-panicked_action_value = PANICKED_POWEROFF; +} else if (strcasecmp(conf-panicked_action, reset) == 0) { +conf-panicked_action_value = PANICKED_RESET; +} else { +return -1; +} + +return 0; +} + +#if defined(KVM_PV_EVENT_PORT) + +#include hw/isa.h + +typedef struct { +ISADevice dev; +struct PVEventAction conf; +MemoryRegion ioport; +} PVIOPortState; + +static uint64_t pv_io_read(void *opaque, hwaddr addr, unsigned size) +{ +return supported_event(); +} + +static void pv_io_write(void *opaque, hwaddr addr, uint64_t val, +unsigned size) +{ +PVIOPortState *s = opaque; + +handle_event(val, s-conf); +} + +static const MemoryRegionOps