Message ID | 5021D328.4020105@cn.fujitsu.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Aug 8, 2012 at 2:47 AM, Wen Congyang <wency@cn.fujitsu.com> 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 | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/kvm/pv_ioport.c | 93 ++++++++++++++++++++++++++++++++++++++++++ > hw/pc_piix.c | 9 ++++ > kvm.h | 2 + > 5 files changed, 214 insertions(+), 1 deletions(-) > create mode 100644 hw/kvm/pv_event.c > create mode 100644 hw/kvm/pv_ioport.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..8897237 > --- /dev/null > +++ b/hw/kvm/pv_event.c > @@ -0,0 +1,109 @@ > +/* > + * 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 pv_event_action { 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; Misses a line break unlike other cases. > + 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 pv_event_action *conf) > +{ > + if (event == KVM_PV_EVENT_PANICKED) { > + panicked_perform_action(conf->panicked_action_value); > + } > +} > + > +static int pv_event_init(struct pv_event_action *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 "pv_ioport.c" I'd rather not include any .c files but insert the contents here directly. > + > +#else > +void kvm_pv_event_init(void *opaque) > +{ > +} > +#endif > diff --git a/hw/kvm/pv_ioport.c b/hw/kvm/pv_ioport.c > new file mode 100644 > index 0000000..c2ed6b5 > --- /dev/null > +++ b/hw/kvm/pv_ioport.c > @@ -0,0 +1,93 @@ > +/* > + * QEMU KVM support, paravirtual I/O port 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 "hw/isa.h" > + > +typedef struct { > + ISADevice dev; > + struct pv_event_action 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; Mandatory braces missing. > + > + 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); > +} > diff --git a/hw/pc_piix.c b/hw/pc_piix.c > index 0c0096f..4af8403 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 I'd remove this and the #ifdeffery below since a stub function is provided. This is not performance critical. > > #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 2617dd5..598dcbe 100644 > --- a/kvm.h > +++ b/kvm.h > @@ -222,4 +222,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 > -- > 1.7.1 > > -- 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/09/2012 03:01 AM, Blue Swirl Wrote: > On Wed, Aug 8, 2012 at 2:47 AM, Wen Congyang <wency@cn.fujitsu.com> 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 | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ >> hw/kvm/pv_ioport.c | 93 ++++++++++++++++++++++++++++++++++++++++++ >> hw/pc_piix.c | 9 ++++ >> kvm.h | 2 + >> 5 files changed, 214 insertions(+), 1 deletions(-) >> create mode 100644 hw/kvm/pv_event.c >> create mode 100644 hw/kvm/pv_ioport.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..8897237 >> --- /dev/null >> +++ b/hw/kvm/pv_event.c >> @@ -0,0 +1,109 @@ >> +/* >> + * 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 pv_event_action { > > 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; > > Misses a line break unlike other cases. > >> + 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 pv_event_action *conf) >> +{ >> + if (event == KVM_PV_EVENT_PANICKED) { >> + panicked_perform_action(conf->panicked_action_value); >> + } >> +} >> + >> +static int pv_event_init(struct pv_event_action *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 "pv_ioport.c" > > I'd rather not include any .c files but insert the contents here directly. > >> + >> +#else >> +void kvm_pv_event_init(void *opaque) >> +{ >> +} >> +#endif >> diff --git a/hw/kvm/pv_ioport.c b/hw/kvm/pv_ioport.c >> new file mode 100644 >> index 0000000..c2ed6b5 >> --- /dev/null >> +++ b/hw/kvm/pv_ioport.c >> @@ -0,0 +1,93 @@ >> +/* >> + * QEMU KVM support, paravirtual I/O port 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 "hw/isa.h" >> + >> +typedef struct { >> + ISADevice dev; >> + struct pv_event_action 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; > > Mandatory braces missing. > >> + >> + 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); >> +} >> diff --git a/hw/pc_piix.c b/hw/pc_piix.c >> index 0c0096f..4af8403 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 > > I'd remove this and the #ifdeffery below since a stub function is > provided. This is not performance critical. The stub function is in the file hw/kvm/pv_event.c, and this file will be complied only when CONFIG_KVM is y. Thanks Wen Congyang > >> >> #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 2617dd5..598dcbe 100644 >> --- a/kvm.h >> +++ b/kvm.h >> @@ -222,4 +222,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 >> -- >> 1.7.1 >> >> > -- 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 Wed, Aug 22, 2012 at 7:30 AM, Wen Congyang <wency@cn.fujitsu.com> wrote: > At 08/09/2012 03:01 AM, Blue Swirl Wrote: >> On Wed, Aug 8, 2012 at 2:47 AM, Wen Congyang <wency@cn.fujitsu.com> 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 | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ >>> hw/kvm/pv_ioport.c | 93 ++++++++++++++++++++++++++++++++++++++++++ >>> hw/pc_piix.c | 9 ++++ >>> kvm.h | 2 + >>> 5 files changed, 214 insertions(+), 1 deletions(-) >>> create mode 100644 hw/kvm/pv_event.c >>> create mode 100644 hw/kvm/pv_ioport.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..8897237 >>> --- /dev/null >>> +++ b/hw/kvm/pv_event.c >>> @@ -0,0 +1,109 @@ >>> +/* >>> + * 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 pv_event_action { >> >> 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; >> >> Misses a line break unlike other cases. >> >>> + 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 pv_event_action *conf) >>> +{ >>> + if (event == KVM_PV_EVENT_PANICKED) { >>> + panicked_perform_action(conf->panicked_action_value); >>> + } >>> +} >>> + >>> +static int pv_event_init(struct pv_event_action *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 "pv_ioport.c" >> >> I'd rather not include any .c files but insert the contents here directly. >> >>> + >>> +#else >>> +void kvm_pv_event_init(void *opaque) >>> +{ >>> +} >>> +#endif >>> diff --git a/hw/kvm/pv_ioport.c b/hw/kvm/pv_ioport.c >>> new file mode 100644 >>> index 0000000..c2ed6b5 >>> --- /dev/null >>> +++ b/hw/kvm/pv_ioport.c >>> @@ -0,0 +1,93 @@ >>> +/* >>> + * QEMU KVM support, paravirtual I/O port 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 "hw/isa.h" >>> + >>> +typedef struct { >>> + ISADevice dev; >>> + struct pv_event_action 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; >> >> Mandatory braces missing. >> >>> + >>> + 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); >>> +} >>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c >>> index 0c0096f..4af8403 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 >> >> I'd remove this and the #ifdeffery below since a stub function is >> provided. This is not performance critical. > > The stub function is in the file hw/kvm/pv_event.c, and this file > will be complied only when CONFIG_KVM is y. Usually the stubs are always provided, compare to for example kvm-stub.c. Wouldn't that simplify the code? > > Thanks > Wen Congyang > >> >>> >>> #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 2617dd5..598dcbe 100644 >>> --- a/kvm.h >>> +++ b/kvm.h >>> @@ -222,4 +222,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 >>> -- >>> 1.7.1 >>> >>> >> > -- 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..8897237 --- /dev/null +++ b/hw/kvm/pv_event.c @@ -0,0 +1,109 @@ +/* + * 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 pv_event_action { + 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 pv_event_action *conf) +{ + if (event == KVM_PV_EVENT_PANICKED) { + panicked_perform_action(conf->panicked_action_value); + } +} + +static int pv_event_init(struct pv_event_action *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 "pv_ioport.c" + +#else +void kvm_pv_event_init(void *opaque) +{ +} +#endif diff --git a/hw/kvm/pv_ioport.c b/hw/kvm/pv_ioport.c new file mode 100644 index 0000000..c2ed6b5 --- /dev/null +++ b/hw/kvm/pv_ioport.c @@ -0,0 +1,93 @@ +/* + * QEMU KVM support, paravirtual I/O port 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 "hw/isa.h" + +typedef struct { + ISADevice dev; + struct pv_event_action 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); +} diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 0c0096f..4af8403 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 2617dd5..598dcbe 100644 --- a/kvm.h +++ b/kvm.h @@ -222,4 +222,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 | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/kvm/pv_ioport.c | 93 ++++++++++++++++++++++++++++++++++++++++++ hw/pc_piix.c | 9 ++++ kvm.h | 2 + 5 files changed, 214 insertions(+), 1 deletions(-) create mode 100644 hw/kvm/pv_event.c create mode 100644 hw/kvm/pv_ioport.c