Message ID | 5035962D.8050907@cn.fujitsu.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 2012-08-23 04:32, Wen Congyang wrote: > 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 <wency@cn.fujitsu.com> > --- > hw/kvm/Makefile.objs | 2 +- > hw/kvm/pv_event.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/pc_piix.c | 9 +++ > kvm.h | 2 + > 4 files changed, 202 insertions(+), 1 deletions(-) > create mode 100644 hw/kvm/pv_event.c > > diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs > index 226497a..23e3b30 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 > +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pv_event.o > diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c > new file mode 100644 > index 0000000..c03dd22 > --- /dev/null > +++ b/hw/kvm/pv_event.c > @@ -0,0 +1,190 @@ > +/* > + * QEMU KVM support, paravirtual event device > + * > + * Copyright Fujitsu, Corp. 2012 > + * > + * Authors: > + * Wen Congyang <wency@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, target_phys_addr_t addr, unsigned size) > +{ > + return supported_event(); > +} > + > +static void pv_io_write(void *opaque, target_phys_addr_t addr, uint64_t val, > + unsigned size) > +{ > + PVIOPortState *s = opaque; > + > + handle_event(val, &s->conf); > +} > + > +static const MemoryRegionOps pv_io_ops = { > + .read = pv_io_read, > + .write = pv_io_write, > + .impl = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > +}; > + > +static int pv_ioport_initfn(ISADevice *dev) > +{ > + PVIOPortState *s = DO_UPCAST(PVIOPortState, dev, dev); > + > + if (pv_event_init(&s->conf) < 0) { > + return -1; > + } > + > + memory_region_init_io(&s->ioport, &pv_io_ops, s, "pv_event", 1); > + isa_register_ioport(dev, &s->ioport, KVM_PV_EVENT_PORT); > + > + return 0; > +} > + > +static Property pv_ioport_properties[] = { > + DEFINE_PV_EVENT_PROPERTIES(PVIOPortState, conf), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void pv_ioport_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); > + > + ic->init = pv_ioport_initfn; > + dc->no_user = 1; > + dc->props = pv_ioport_properties; > +} > + > +static TypeInfo pv_ioport_info = { > + .name = PV_EVENT_DRIVER, > + .parent = TYPE_ISA_DEVICE, > + .instance_size = sizeof(PVIOPortState), > + .class_init = pv_ioport_class_init, > +}; > + > +static void pv_ioport_register_types(void) > +{ > + type_register_static(&pv_ioport_info); > +} > + > +type_init(pv_ioport_register_types) > + > +void kvm_pv_event_init(void *opaque) > +{ > + ISABus *bus = opaque; > + ISADevice *dev; > + > + dev = isa_create(bus, PV_EVENT_DRIVER); > + qdev_init_nofail(&dev->qdev); > +} > + > +#else > +void kvm_pv_event_init(void *opaque) > +{ Some comment that this stub requires an implementation whenever it is actually built would be helpful. Something that explains a different transport than PIO will be needed. > +} > +#endif > diff --git a/hw/pc_piix.c b/hw/pc_piix.c > index 88ff041..f73fb85 100644 > --- a/hw/pc_piix.c > +++ b/hw/pc_piix.c > @@ -46,6 +46,9 @@ > #ifdef CONFIG_XEN > # include <xen/hvm/hvm_info_table.h> > #endif > +#ifdef CONFIG_KVM > +# include <asm/kvm_para.h> > +#endif > > #define MAX_IDE_BUS 2 > > @@ -285,6 +288,12 @@ static void pc_init1(MemoryRegion *system_memory, > if (pci_enabled) { > pc_pci_device_init(pci_bus); > } > + > +#ifdef KVM_PV_EVENT_PORT This file is x86-only, and there we have KVM_PV_EVENT_PORT unconditionally. So drop the #ifdef. > + if (kvm_enabled()) { > + kvm_pv_event_init(isa_bus); But you are missing a kvm-stub entry for kvm_pv_event_init. A --disable-kvm build should be broken for that reason. > + } > +#endif > } > > static void pc_init_pci(ram_addr_t ram_size, > diff --git a/kvm.h b/kvm.h > index 5b8f588..41ce1b2 100644 > --- a/kvm.h > +++ b/kvm.h > @@ -276,4 +276,6 @@ int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq); > int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq); > int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq); > int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq); > + > +void kvm_pv_event_init(void *opaque); > #endif > Jan
At 08/23/2012 06:51 PM, Jan Kiszka Wrote: > On 2012-08-23 04:32, Wen Congyang wrote: >> 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 <wency@cn.fujitsu.com> >> --- >> hw/kvm/Makefile.objs | 2 +- >> hw/kvm/pv_event.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ >> hw/pc_piix.c | 9 +++ >> kvm.h | 2 + >> 4 files changed, 202 insertions(+), 1 deletions(-) >> create mode 100644 hw/kvm/pv_event.c >> >> diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs >> index 226497a..23e3b30 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 >> +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pv_event.o >> diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c >> new file mode 100644 >> index 0000000..c03dd22 >> --- /dev/null >> +++ b/hw/kvm/pv_event.c >> @@ -0,0 +1,190 @@ >> +/* >> + * QEMU KVM support, paravirtual event device >> + * >> + * Copyright Fujitsu, Corp. 2012 >> + * >> + * Authors: >> + * Wen Congyang <wency@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, target_phys_addr_t addr, unsigned size) >> +{ >> + return supported_event(); >> +} >> + >> +static void pv_io_write(void *opaque, target_phys_addr_t addr, uint64_t val, >> + unsigned size) >> +{ >> + PVIOPortState *s = opaque; >> + >> + handle_event(val, &s->conf); >> +} >> + >> +static const MemoryRegionOps pv_io_ops = { >> + .read = pv_io_read, >> + .write = pv_io_write, >> + .impl = { >> + .min_access_size = 4, >> + .max_access_size = 4, >> + }, >> +}; >> + >> +static int pv_ioport_initfn(ISADevice *dev) >> +{ >> + PVIOPortState *s = DO_UPCAST(PVIOPortState, dev, dev); >> + >> + if (pv_event_init(&s->conf) < 0) { >> + return -1; >> + } >> + >> + memory_region_init_io(&s->ioport, &pv_io_ops, s, "pv_event", 1); >> + isa_register_ioport(dev, &s->ioport, KVM_PV_EVENT_PORT); >> + >> + return 0; >> +} >> + >> +static Property pv_ioport_properties[] = { >> + DEFINE_PV_EVENT_PROPERTIES(PVIOPortState, conf), >> + DEFINE_PROP_END_OF_LIST(), >> +}; >> + >> +static void pv_ioport_class_init(ObjectClass *klass, void *data) >> +{ >> + DeviceClass *dc = DEVICE_CLASS(klass); >> + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); >> + >> + ic->init = pv_ioport_initfn; >> + dc->no_user = 1; >> + dc->props = pv_ioport_properties; >> +} >> + >> +static TypeInfo pv_ioport_info = { >> + .name = PV_EVENT_DRIVER, >> + .parent = TYPE_ISA_DEVICE, >> + .instance_size = sizeof(PVIOPortState), >> + .class_init = pv_ioport_class_init, >> +}; >> + >> +static void pv_ioport_register_types(void) >> +{ >> + type_register_static(&pv_ioport_info); >> +} >> + >> +type_init(pv_ioport_register_types) >> + >> +void kvm_pv_event_init(void *opaque) >> +{ >> + ISABus *bus = opaque; >> + ISADevice *dev; >> + >> + dev = isa_create(bus, PV_EVENT_DRIVER); >> + qdev_init_nofail(&dev->qdev); >> +} >> + >> +#else >> +void kvm_pv_event_init(void *opaque) >> +{ > > Some comment that this stub requires an implementation whenever it is > actually built would be helpful. Something that explains a different > transport than PIO will be needed. OK > >> +} >> +#endif >> diff --git a/hw/pc_piix.c b/hw/pc_piix.c >> index 88ff041..f73fb85 100644 >> --- a/hw/pc_piix.c >> +++ b/hw/pc_piix.c >> @@ -46,6 +46,9 @@ >> #ifdef CONFIG_XEN >> # include <xen/hvm/hvm_info_table.h> >> #endif >> +#ifdef CONFIG_KVM >> +# include <asm/kvm_para.h> >> +#endif >> >> #define MAX_IDE_BUS 2 >> >> @@ -285,6 +288,12 @@ static void pc_init1(MemoryRegion *system_memory, >> if (pci_enabled) { >> pc_pci_device_init(pci_bus); >> } >> + >> +#ifdef KVM_PV_EVENT_PORT > > This file is x86-only, and there we have KVM_PV_EVENT_PORT > unconditionally. So drop the #ifdef. > >> + if (kvm_enabled()) { >> + kvm_pv_event_init(isa_bus); > > But you are missing a kvm-stub entry for kvm_pv_event_init. A > --disable-kvm build should be broken for that reason. Hmm, KVM_PV_EVENT_PORT is defined in asm/kvm_para.h, and I include this file only when CONFIG_KVM is defined. So --disable-kvm build does not be broken in my test. Thanks Wen Congyang > >> + } >> +#endif >> } >> >> static void pc_init_pci(ram_addr_t ram_size, >> diff --git a/kvm.h b/kvm.h >> index 5b8f588..41ce1b2 100644 >> --- a/kvm.h >> +++ b/kvm.h >> @@ -276,4 +276,6 @@ int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq); >> int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq); >> int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq); >> int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq); >> + >> +void kvm_pv_event_init(void *opaque); >> #endif >> > > Jan > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 2012-08-24 08:05, Wen Congyang wrote: > At 08/23/2012 06:51 PM, Jan Kiszka Wrote: >> On 2012-08-23 04:32, Wen Congyang wrote: >>> 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 <wency@cn.fujitsu.com> >>> --- >>> hw/kvm/Makefile.objs | 2 +- >>> hw/kvm/pv_event.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ >>> hw/pc_piix.c | 9 +++ >>> kvm.h | 2 + >>> 4 files changed, 202 insertions(+), 1 deletions(-) >>> create mode 100644 hw/kvm/pv_event.c >>> >>> diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs >>> index 226497a..23e3b30 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 >>> +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pv_event.o >>> diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c >>> new file mode 100644 >>> index 0000000..c03dd22 >>> --- /dev/null >>> +++ b/hw/kvm/pv_event.c >>> @@ -0,0 +1,190 @@ >>> +/* >>> + * QEMU KVM support, paravirtual event device >>> + * >>> + * Copyright Fujitsu, Corp. 2012 >>> + * >>> + * Authors: >>> + * Wen Congyang <wency@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, target_phys_addr_t addr, unsigned size) >>> +{ >>> + return supported_event(); >>> +} >>> + >>> +static void pv_io_write(void *opaque, target_phys_addr_t addr, uint64_t val, >>> + unsigned size) >>> +{ >>> + PVIOPortState *s = opaque; >>> + >>> + handle_event(val, &s->conf); >>> +} >>> + >>> +static const MemoryRegionOps pv_io_ops = { >>> + .read = pv_io_read, >>> + .write = pv_io_write, >>> + .impl = { >>> + .min_access_size = 4, >>> + .max_access_size = 4, >>> + }, >>> +}; >>> + >>> +static int pv_ioport_initfn(ISADevice *dev) >>> +{ >>> + PVIOPortState *s = DO_UPCAST(PVIOPortState, dev, dev); >>> + >>> + if (pv_event_init(&s->conf) < 0) { >>> + return -1; >>> + } >>> + >>> + memory_region_init_io(&s->ioport, &pv_io_ops, s, "pv_event", 1); >>> + isa_register_ioport(dev, &s->ioport, KVM_PV_EVENT_PORT); >>> + >>> + return 0; >>> +} >>> + >>> +static Property pv_ioport_properties[] = { >>> + DEFINE_PV_EVENT_PROPERTIES(PVIOPortState, conf), >>> + DEFINE_PROP_END_OF_LIST(), >>> +}; >>> + >>> +static void pv_ioport_class_init(ObjectClass *klass, void *data) >>> +{ >>> + DeviceClass *dc = DEVICE_CLASS(klass); >>> + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); >>> + >>> + ic->init = pv_ioport_initfn; >>> + dc->no_user = 1; >>> + dc->props = pv_ioport_properties; >>> +} >>> + >>> +static TypeInfo pv_ioport_info = { >>> + .name = PV_EVENT_DRIVER, >>> + .parent = TYPE_ISA_DEVICE, >>> + .instance_size = sizeof(PVIOPortState), >>> + .class_init = pv_ioport_class_init, >>> +}; >>> + >>> +static void pv_ioport_register_types(void) >>> +{ >>> + type_register_static(&pv_ioport_info); >>> +} >>> + >>> +type_init(pv_ioport_register_types) >>> + >>> +void kvm_pv_event_init(void *opaque) >>> +{ >>> + ISABus *bus = opaque; >>> + ISADevice *dev; >>> + >>> + dev = isa_create(bus, PV_EVENT_DRIVER); >>> + qdev_init_nofail(&dev->qdev); >>> +} >>> + >>> +#else >>> +void kvm_pv_event_init(void *opaque) >>> +{ >> >> Some comment that this stub requires an implementation whenever it is >> actually built would be helpful. Something that explains a different >> transport than PIO will be needed. > > OK > >> >>> +} >>> +#endif >>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c >>> index 88ff041..f73fb85 100644 >>> --- a/hw/pc_piix.c >>> +++ b/hw/pc_piix.c >>> @@ -46,6 +46,9 @@ >>> #ifdef CONFIG_XEN >>> # include <xen/hvm/hvm_info_table.h> >>> #endif >>> +#ifdef CONFIG_KVM >>> +# include <asm/kvm_para.h> >>> +#endif >>> >>> #define MAX_IDE_BUS 2 >>> >>> @@ -285,6 +288,12 @@ static void pc_init1(MemoryRegion *system_memory, >>> if (pci_enabled) { >>> pc_pci_device_init(pci_bus); >>> } >>> + >>> +#ifdef KVM_PV_EVENT_PORT >> >> This file is x86-only, and there we have KVM_PV_EVENT_PORT >> unconditionally. So drop the #ifdef. >> >>> + if (kvm_enabled()) { >>> + kvm_pv_event_init(isa_bus); >> >> But you are missing a kvm-stub entry for kvm_pv_event_init. A >> --disable-kvm build should be broken for that reason. > > Hmm, KVM_PV_EVENT_PORT is defined in asm/kvm_para.h, and I include > this file only when CONFIG_KVM is defined. So --disable-kvm build > does not be broken in my test. Yeah, but that is a bit ugly and another reason to go for a proper kvm-stub. Jan
On 2012-08-24 08:33, Wen Congyang wrote: > At 08/24/2012 02:21 PM, Jan Kiszka Wrote: >> On 2012-08-24 08:05, Wen Congyang wrote: >>> At 08/23/2012 06:51 PM, Jan Kiszka Wrote: >>>> On 2012-08-23 04:32, Wen Congyang wrote: >>>>> 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 <wency@cn.fujitsu.com> >>>>> --- >>>>> hw/kvm/Makefile.objs | 2 +- >>>>> hw/kvm/pv_event.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ >>>>> hw/pc_piix.c | 9 +++ >>>>> kvm.h | 2 + >>>>> 4 files changed, 202 insertions(+), 1 deletions(-) >>>>> create mode 100644 hw/kvm/pv_event.c >>>>> >>>>> diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs >>>>> index 226497a..23e3b30 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 >>>>> +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pv_event.o >>>>> diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c >>>>> new file mode 100644 >>>>> index 0000000..c03dd22 >>>>> --- /dev/null >>>>> +++ b/hw/kvm/pv_event.c >>>>> @@ -0,0 +1,190 @@ >>>>> +/* >>>>> + * QEMU KVM support, paravirtual event device >>>>> + * >>>>> + * Copyright Fujitsu, Corp. 2012 >>>>> + * >>>>> + * Authors: >>>>> + * Wen Congyang <wency@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, target_phys_addr_t addr, unsigned size) >>>>> +{ >>>>> + return supported_event(); >>>>> +} >>>>> + >>>>> +static void pv_io_write(void *opaque, target_phys_addr_t addr, uint64_t val, >>>>> + unsigned size) >>>>> +{ >>>>> + PVIOPortState *s = opaque; >>>>> + >>>>> + handle_event(val, &s->conf); >>>>> +} >>>>> + >>>>> +static const MemoryRegionOps pv_io_ops = { >>>>> + .read = pv_io_read, >>>>> + .write = pv_io_write, >>>>> + .impl = { >>>>> + .min_access_size = 4, >>>>> + .max_access_size = 4, >>>>> + }, >>>>> +}; >>>>> + >>>>> +static int pv_ioport_initfn(ISADevice *dev) >>>>> +{ >>>>> + PVIOPortState *s = DO_UPCAST(PVIOPortState, dev, dev); >>>>> + >>>>> + if (pv_event_init(&s->conf) < 0) { >>>>> + return -1; >>>>> + } >>>>> + >>>>> + memory_region_init_io(&s->ioport, &pv_io_ops, s, "pv_event", 1); >>>>> + isa_register_ioport(dev, &s->ioport, KVM_PV_EVENT_PORT); >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static Property pv_ioport_properties[] = { >>>>> + DEFINE_PV_EVENT_PROPERTIES(PVIOPortState, conf), >>>>> + DEFINE_PROP_END_OF_LIST(), >>>>> +}; >>>>> + >>>>> +static void pv_ioport_class_init(ObjectClass *klass, void *data) >>>>> +{ >>>>> + DeviceClass *dc = DEVICE_CLASS(klass); >>>>> + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); >>>>> + >>>>> + ic->init = pv_ioport_initfn; >>>>> + dc->no_user = 1; >>>>> + dc->props = pv_ioport_properties; >>>>> +} >>>>> + >>>>> +static TypeInfo pv_ioport_info = { >>>>> + .name = PV_EVENT_DRIVER, >>>>> + .parent = TYPE_ISA_DEVICE, >>>>> + .instance_size = sizeof(PVIOPortState), >>>>> + .class_init = pv_ioport_class_init, >>>>> +}; >>>>> + >>>>> +static void pv_ioport_register_types(void) >>>>> +{ >>>>> + type_register_static(&pv_ioport_info); >>>>> +} >>>>> + >>>>> +type_init(pv_ioport_register_types) >>>>> + >>>>> +void kvm_pv_event_init(void *opaque) >>>>> +{ >>>>> + ISABus *bus = opaque; >>>>> + ISADevice *dev; >>>>> + >>>>> + dev = isa_create(bus, PV_EVENT_DRIVER); >>>>> + qdev_init_nofail(&dev->qdev); >>>>> +} >>>>> + >>>>> +#else >>>>> +void kvm_pv_event_init(void *opaque) >>>>> +{ >>>> >>>> Some comment that this stub requires an implementation whenever it is >>>> actually built would be helpful. Something that explains a different >>>> transport than PIO will be needed. >>> >>> OK >>> >>>> >>>>> +} >>>>> +#endif >>>>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c >>>>> index 88ff041..f73fb85 100644 >>>>> --- a/hw/pc_piix.c >>>>> +++ b/hw/pc_piix.c >>>>> @@ -46,6 +46,9 @@ >>>>> #ifdef CONFIG_XEN >>>>> # include <xen/hvm/hvm_info_table.h> >>>>> #endif >>>>> +#ifdef CONFIG_KVM >>>>> +# include <asm/kvm_para.h> >>>>> +#endif >>>>> >>>>> #define MAX_IDE_BUS 2 >>>>> >>>>> @@ -285,6 +288,12 @@ static void pc_init1(MemoryRegion *system_memory, >>>>> if (pci_enabled) { >>>>> pc_pci_device_init(pci_bus); >>>>> } >>>>> + >>>>> +#ifdef KVM_PV_EVENT_PORT >>>> >>>> This file is x86-only, and there we have KVM_PV_EVENT_PORT >>>> unconditionally. So drop the #ifdef. >>>> >>>>> + if (kvm_enabled()) { >>>>> + kvm_pv_event_init(isa_bus); >>>> >>>> But you are missing a kvm-stub entry for kvm_pv_event_init. A >>>> --disable-kvm build should be broken for that reason. >>> >>> Hmm, KVM_PV_EVENT_PORT is defined in asm/kvm_para.h, and I include >>> this file only when CONFIG_KVM is defined. So --disable-kvm build >>> does not be broken in my test. >> >> Yeah, but that is a bit ugly and another reason to go for a proper kvm-stub. > > Yes, it is ugly. I will add a stub function in kvm-stub. And the header > file asm/kvm_para.h can be included unconditionally. And "#ifdef KVM_PV_EVENT_PORT" > can be dropped. Actually, not asm/kvm_para.h but linux/kvm_para.h. And you will then only need it in pv_event.c. Jan
At 08/24/2012 02:21 PM, Jan Kiszka Wrote: > On 2012-08-24 08:05, Wen Congyang wrote: >> At 08/23/2012 06:51 PM, Jan Kiszka Wrote: >>> On 2012-08-23 04:32, Wen Congyang wrote: >>>> 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 <wency@cn.fujitsu.com> >>>> --- >>>> hw/kvm/Makefile.objs | 2 +- >>>> hw/kvm/pv_event.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ >>>> hw/pc_piix.c | 9 +++ >>>> kvm.h | 2 + >>>> 4 files changed, 202 insertions(+), 1 deletions(-) >>>> create mode 100644 hw/kvm/pv_event.c >>>> >>>> diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs >>>> index 226497a..23e3b30 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 >>>> +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pv_event.o >>>> diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c >>>> new file mode 100644 >>>> index 0000000..c03dd22 >>>> --- /dev/null >>>> +++ b/hw/kvm/pv_event.c >>>> @@ -0,0 +1,190 @@ >>>> +/* >>>> + * QEMU KVM support, paravirtual event device >>>> + * >>>> + * Copyright Fujitsu, Corp. 2012 >>>> + * >>>> + * Authors: >>>> + * Wen Congyang <wency@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, target_phys_addr_t addr, unsigned size) >>>> +{ >>>> + return supported_event(); >>>> +} >>>> + >>>> +static void pv_io_write(void *opaque, target_phys_addr_t addr, uint64_t val, >>>> + unsigned size) >>>> +{ >>>> + PVIOPortState *s = opaque; >>>> + >>>> + handle_event(val, &s->conf); >>>> +} >>>> + >>>> +static const MemoryRegionOps pv_io_ops = { >>>> + .read = pv_io_read, >>>> + .write = pv_io_write, >>>> + .impl = { >>>> + .min_access_size = 4, >>>> + .max_access_size = 4, >>>> + }, >>>> +}; >>>> + >>>> +static int pv_ioport_initfn(ISADevice *dev) >>>> +{ >>>> + PVIOPortState *s = DO_UPCAST(PVIOPortState, dev, dev); >>>> + >>>> + if (pv_event_init(&s->conf) < 0) { >>>> + return -1; >>>> + } >>>> + >>>> + memory_region_init_io(&s->ioport, &pv_io_ops, s, "pv_event", 1); >>>> + isa_register_ioport(dev, &s->ioport, KVM_PV_EVENT_PORT); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static Property pv_ioport_properties[] = { >>>> + DEFINE_PV_EVENT_PROPERTIES(PVIOPortState, conf), >>>> + DEFINE_PROP_END_OF_LIST(), >>>> +}; >>>> + >>>> +static void pv_ioport_class_init(ObjectClass *klass, void *data) >>>> +{ >>>> + DeviceClass *dc = DEVICE_CLASS(klass); >>>> + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); >>>> + >>>> + ic->init = pv_ioport_initfn; >>>> + dc->no_user = 1; >>>> + dc->props = pv_ioport_properties; >>>> +} >>>> + >>>> +static TypeInfo pv_ioport_info = { >>>> + .name = PV_EVENT_DRIVER, >>>> + .parent = TYPE_ISA_DEVICE, >>>> + .instance_size = sizeof(PVIOPortState), >>>> + .class_init = pv_ioport_class_init, >>>> +}; >>>> + >>>> +static void pv_ioport_register_types(void) >>>> +{ >>>> + type_register_static(&pv_ioport_info); >>>> +} >>>> + >>>> +type_init(pv_ioport_register_types) >>>> + >>>> +void kvm_pv_event_init(void *opaque) >>>> +{ >>>> + ISABus *bus = opaque; >>>> + ISADevice *dev; >>>> + >>>> + dev = isa_create(bus, PV_EVENT_DRIVER); >>>> + qdev_init_nofail(&dev->qdev); >>>> +} >>>> + >>>> +#else >>>> +void kvm_pv_event_init(void *opaque) >>>> +{ >>> >>> Some comment that this stub requires an implementation whenever it is >>> actually built would be helpful. Something that explains a different >>> transport than PIO will be needed. >> >> OK >> >>> >>>> +} >>>> +#endif >>>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c >>>> index 88ff041..f73fb85 100644 >>>> --- a/hw/pc_piix.c >>>> +++ b/hw/pc_piix.c >>>> @@ -46,6 +46,9 @@ >>>> #ifdef CONFIG_XEN >>>> # include <xen/hvm/hvm_info_table.h> >>>> #endif >>>> +#ifdef CONFIG_KVM >>>> +# include <asm/kvm_para.h> >>>> +#endif >>>> >>>> #define MAX_IDE_BUS 2 >>>> >>>> @@ -285,6 +288,12 @@ static void pc_init1(MemoryRegion *system_memory, >>>> if (pci_enabled) { >>>> pc_pci_device_init(pci_bus); >>>> } >>>> + >>>> +#ifdef KVM_PV_EVENT_PORT >>> >>> This file is x86-only, and there we have KVM_PV_EVENT_PORT >>> unconditionally. So drop the #ifdef. >>> >>>> + if (kvm_enabled()) { >>>> + kvm_pv_event_init(isa_bus); >>> >>> But you are missing a kvm-stub entry for kvm_pv_event_init. A >>> --disable-kvm build should be broken for that reason. >> >> Hmm, KVM_PV_EVENT_PORT is defined in asm/kvm_para.h, and I include >> this file only when CONFIG_KVM is defined. So --disable-kvm build >> does not be broken in my test. > > Yeah, but that is a bit ugly and another reason to go for a proper kvm-stub. Yes, it is ugly. I will add a stub function in kvm-stub. And the header file asm/kvm_para.h can be included unconditionally. And "#ifdef KVM_PV_EVENT_PORT" can be dropped. Thanks Wen Congyang > > Jan > > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
At 08/24/2012 02:30 PM, Jan Kiszka Wrote: > On 2012-08-24 08:33, Wen Congyang wrote: >> At 08/24/2012 02:21 PM, Jan Kiszka Wrote: >>> On 2012-08-24 08:05, Wen Congyang wrote: >>>> At 08/23/2012 06:51 PM, Jan Kiszka Wrote: >>>>> On 2012-08-23 04:32, Wen Congyang wrote: >>>>>> 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 <wency@cn.fujitsu.com> >>>>>> --- >>>>>> hw/kvm/Makefile.objs | 2 +- >>>>>> hw/kvm/pv_event.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ >>>>>> hw/pc_piix.c | 9 +++ >>>>>> kvm.h | 2 + >>>>>> 4 files changed, 202 insertions(+), 1 deletions(-) >>>>>> create mode 100644 hw/kvm/pv_event.c >>>>>> >>>>>> diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs >>>>>> index 226497a..23e3b30 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 >>>>>> +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pv_event.o >>>>>> diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c >>>>>> new file mode 100644 >>>>>> index 0000000..c03dd22 >>>>>> --- /dev/null >>>>>> +++ b/hw/kvm/pv_event.c >>>>>> @@ -0,0 +1,190 @@ >>>>>> +/* >>>>>> + * QEMU KVM support, paravirtual event device >>>>>> + * >>>>>> + * Copyright Fujitsu, Corp. 2012 >>>>>> + * >>>>>> + * Authors: >>>>>> + * Wen Congyang <wency@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, target_phys_addr_t addr, unsigned size) >>>>>> +{ >>>>>> + return supported_event(); >>>>>> +} >>>>>> + >>>>>> +static void pv_io_write(void *opaque, target_phys_addr_t addr, uint64_t val, >>>>>> + unsigned size) >>>>>> +{ >>>>>> + PVIOPortState *s = opaque; >>>>>> + >>>>>> + handle_event(val, &s->conf); >>>>>> +} >>>>>> + >>>>>> +static const MemoryRegionOps pv_io_ops = { >>>>>> + .read = pv_io_read, >>>>>> + .write = pv_io_write, >>>>>> + .impl = { >>>>>> + .min_access_size = 4, >>>>>> + .max_access_size = 4, >>>>>> + }, >>>>>> +}; >>>>>> + >>>>>> +static int pv_ioport_initfn(ISADevice *dev) >>>>>> +{ >>>>>> + PVIOPortState *s = DO_UPCAST(PVIOPortState, dev, dev); >>>>>> + >>>>>> + if (pv_event_init(&s->conf) < 0) { >>>>>> + return -1; >>>>>> + } >>>>>> + >>>>>> + memory_region_init_io(&s->ioport, &pv_io_ops, s, "pv_event", 1); >>>>>> + isa_register_ioport(dev, &s->ioport, KVM_PV_EVENT_PORT); >>>>>> + >>>>>> + return 0; >>>>>> +} >>>>>> + >>>>>> +static Property pv_ioport_properties[] = { >>>>>> + DEFINE_PV_EVENT_PROPERTIES(PVIOPortState, conf), >>>>>> + DEFINE_PROP_END_OF_LIST(), >>>>>> +}; >>>>>> + >>>>>> +static void pv_ioport_class_init(ObjectClass *klass, void *data) >>>>>> +{ >>>>>> + DeviceClass *dc = DEVICE_CLASS(klass); >>>>>> + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); >>>>>> + >>>>>> + ic->init = pv_ioport_initfn; >>>>>> + dc->no_user = 1; >>>>>> + dc->props = pv_ioport_properties; >>>>>> +} >>>>>> + >>>>>> +static TypeInfo pv_ioport_info = { >>>>>> + .name = PV_EVENT_DRIVER, >>>>>> + .parent = TYPE_ISA_DEVICE, >>>>>> + .instance_size = sizeof(PVIOPortState), >>>>>> + .class_init = pv_ioport_class_init, >>>>>> +}; >>>>>> + >>>>>> +static void pv_ioport_register_types(void) >>>>>> +{ >>>>>> + type_register_static(&pv_ioport_info); >>>>>> +} >>>>>> + >>>>>> +type_init(pv_ioport_register_types) >>>>>> + >>>>>> +void kvm_pv_event_init(void *opaque) >>>>>> +{ >>>>>> + ISABus *bus = opaque; >>>>>> + ISADevice *dev; >>>>>> + >>>>>> + dev = isa_create(bus, PV_EVENT_DRIVER); >>>>>> + qdev_init_nofail(&dev->qdev); >>>>>> +} >>>>>> + >>>>>> +#else >>>>>> +void kvm_pv_event_init(void *opaque) >>>>>> +{ >>>>> >>>>> Some comment that this stub requires an implementation whenever it is >>>>> actually built would be helpful. Something that explains a different >>>>> transport than PIO will be needed. >>>> >>>> OK >>>> >>>>> >>>>>> +} >>>>>> +#endif >>>>>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c >>>>>> index 88ff041..f73fb85 100644 >>>>>> --- a/hw/pc_piix.c >>>>>> +++ b/hw/pc_piix.c >>>>>> @@ -46,6 +46,9 @@ >>>>>> #ifdef CONFIG_XEN >>>>>> # include <xen/hvm/hvm_info_table.h> >>>>>> #endif >>>>>> +#ifdef CONFIG_KVM >>>>>> +# include <asm/kvm_para.h> >>>>>> +#endif >>>>>> >>>>>> #define MAX_IDE_BUS 2 >>>>>> >>>>>> @@ -285,6 +288,12 @@ static void pc_init1(MemoryRegion *system_memory, >>>>>> if (pci_enabled) { >>>>>> pc_pci_device_init(pci_bus); >>>>>> } >>>>>> + >>>>>> +#ifdef KVM_PV_EVENT_PORT >>>>> >>>>> This file is x86-only, and there we have KVM_PV_EVENT_PORT >>>>> unconditionally. So drop the #ifdef. >>>>> >>>>>> + if (kvm_enabled()) { >>>>>> + kvm_pv_event_init(isa_bus); >>>>> >>>>> But you are missing a kvm-stub entry for kvm_pv_event_init. A >>>>> --disable-kvm build should be broken for that reason. >>>> >>>> Hmm, KVM_PV_EVENT_PORT is defined in asm/kvm_para.h, and I include >>>> this file only when CONFIG_KVM is defined. So --disable-kvm build >>>> does not be broken in my test. >>> >>> Yeah, but that is a bit ugly and another reason to go for a proper kvm-stub. >> >> Yes, it is ugly. I will add a stub function in kvm-stub. And the header >> file asm/kvm_para.h can be included unconditionally. And "#ifdef KVM_PV_EVENT_PORT" >> can be dropped. > > Actually, not asm/kvm_para.h but linux/kvm_para.h. And you will then > only need it in pv_event.c. OK. Thanks Wen Congyang > > Jan > > -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs index 226497a..23e3b30 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 +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pv_event.o diff --git a/hw/kvm/pv_event.c b/hw/kvm/pv_event.c new file mode 100644 index 0000000..c03dd22 --- /dev/null +++ b/hw/kvm/pv_event.c @@ -0,0 +1,190 @@ +/* + * QEMU KVM support, paravirtual event device + * + * Copyright Fujitsu, Corp. 2012 + * + * Authors: + * Wen Congyang <wency@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, target_phys_addr_t addr, unsigned size) +{ + return supported_event(); +} + +static void pv_io_write(void *opaque, target_phys_addr_t addr, uint64_t val, + unsigned size) +{ + PVIOPortState *s = opaque; + + handle_event(val, &s->conf); +} + +static const MemoryRegionOps pv_io_ops = { + .read = pv_io_read, + .write = pv_io_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static int pv_ioport_initfn(ISADevice *dev) +{ + PVIOPortState *s = DO_UPCAST(PVIOPortState, dev, dev); + + if (pv_event_init(&s->conf) < 0) { + return -1; + } + + memory_region_init_io(&s->ioport, &pv_io_ops, s, "pv_event", 1); + isa_register_ioport(dev, &s->ioport, KVM_PV_EVENT_PORT); + + return 0; +} + +static Property pv_ioport_properties[] = { + DEFINE_PV_EVENT_PROPERTIES(PVIOPortState, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pv_ioport_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + + ic->init = pv_ioport_initfn; + dc->no_user = 1; + dc->props = pv_ioport_properties; +} + +static TypeInfo pv_ioport_info = { + .name = PV_EVENT_DRIVER, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(PVIOPortState), + .class_init = pv_ioport_class_init, +}; + +static void pv_ioport_register_types(void) +{ + type_register_static(&pv_ioport_info); +} + +type_init(pv_ioport_register_types) + +void kvm_pv_event_init(void *opaque) +{ + ISABus *bus = opaque; + ISADevice *dev; + + dev = isa_create(bus, PV_EVENT_DRIVER); + qdev_init_nofail(&dev->qdev); +} + +#else +void kvm_pv_event_init(void *opaque) +{ +} +#endif diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 88ff041..f73fb85 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -46,6 +46,9 @@ #ifdef CONFIG_XEN # include <xen/hvm/hvm_info_table.h> #endif +#ifdef CONFIG_KVM +# include <asm/kvm_para.h> +#endif #define MAX_IDE_BUS 2 @@ -285,6 +288,12 @@ static void pc_init1(MemoryRegion *system_memory, if (pci_enabled) { pc_pci_device_init(pci_bus); } + +#ifdef KVM_PV_EVENT_PORT + if (kvm_enabled()) { + kvm_pv_event_init(isa_bus); + } +#endif } static void pc_init_pci(ram_addr_t ram_size, diff --git a/kvm.h b/kvm.h index 5b8f588..41ce1b2 100644 --- a/kvm.h +++ b/kvm.h @@ -276,4 +276,6 @@ int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq); int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq); int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq); int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq); + +void kvm_pv_event_init(void *opaque); #endif
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 <wency@cn.fujitsu.com> --- hw/kvm/Makefile.objs | 2 +- hw/kvm/pv_event.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc_piix.c | 9 +++ kvm.h | 2 + 4 files changed, 202 insertions(+), 1 deletions(-) create mode 100644 hw/kvm/pv_event.c