From mboxrd@z Thu Jan 1 00:00:00 1970 From: Blue Swirl Subject: Re: [Qemu-devel] [PATCH 15/15] kvm: x86: Introduce kvmclock device to save/restore its state Date: Mon, 7 Feb 2011 21:39:35 +0200 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: Avi Kivity , Marcelo Tosatti , Glauber Costa , qemu-devel@nongnu.org, kvm@vger.kernel.org To: Jan Kiszka Return-path: Received: from mail-px0-f174.google.com ([209.85.212.174]:36966 "EHLO mail-px0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754526Ab1BGTj4 convert rfc822-to-8bit (ORCPT ); Mon, 7 Feb 2011 14:39:56 -0500 Received: by pxi15 with SMTP id 15so969834pxi.19 for ; Mon, 07 Feb 2011 11:39:55 -0800 (PST) In-Reply-To: Sender: kvm-owner@vger.kernel.org List-ID: On Mon, Feb 7, 2011 at 1:19 PM, Jan Kiszka wro= te: > If kvmclock is used, which implies the kernel supports it, register a > kvmclock device with the sysbus. Its main purpose is to save and rest= ore > the kernel state on migration, but this will also allow to visualize = it > one day. > > Signed-off-by: Jan Kiszka > CC: Glauber Costa > --- > =C2=A0Makefile.target | =C2=A0 =C2=A04 +- > =C2=A0hw/kvmclock.c =C2=A0 | =C2=A0125 ++++++++++++++++++++++++++++++= +++++++++++++++++++++++++ > =C2=A0hw/kvmclock.h =C2=A0 | =C2=A0 14 ++++++ > =C2=A0hw/pc_piix.c =C2=A0 =C2=A0| =C2=A0 31 +++++++++++--- > =C2=A04 files changed, 165 insertions(+), 9 deletions(-) > =C2=A0create mode 100644 hw/kvmclock.c > =C2=A0create mode 100644 hw/kvmclock.h > > diff --git a/Makefile.target b/Makefile.target > index b0ba95f..30232fa 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -37,7 +37,7 @@ ifndef CONFIG_HAIKU > =C2=A0LIBS+=3D-lm > =C2=A0endif > > -kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=3D$(KVM_CFLAGS) > +kvm.o kvm-all.o vhost.o vhost_net.o kvmclock.o: QEMU_CFLAGS+=3D$(KVM= _CFLAGS) > > =C2=A0config-target.h: config-target.h-timestamp > =C2=A0config-target.h-timestamp: config-target.mak > @@ -218,7 +218,7 @@ obj-i386-y +=3D cirrus_vga.o apic.o ioapic.o piix= _pci.o > =C2=A0obj-i386-y +=3D vmmouse.o vmport.o hpet.o applesmc.o > =C2=A0obj-i386-y +=3D device-hotplug.o pci-hotplug.o smbios.o wdt_ib7= 00.o > =C2=A0obj-i386-y +=3D debugcon.o multiboot.o > -obj-i386-y +=3D pc_piix.o > +obj-i386-y +=3D pc_piix.o kvmclock.o Please build kvmclock.o conditionally to CONFIG_something... > =C2=A0obj-i386-$(CONFIG_SPICE) +=3D qxl.o qxl-logger.o qxl-render.o > > =C2=A0# shared objects > diff --git a/hw/kvmclock.c b/hw/kvmclock.c > new file mode 100644 > index 0000000..b6ceddf > --- /dev/null > +++ b/hw/kvmclock.c > @@ -0,0 +1,125 @@ > +/* > + * QEMU KVM support, paravirtual clock device > + * > + * Copyright (C) 2011 Siemens AG > + * > + * Authors: > + * =C2=A0Jan Kiszka =C2=A0 =C2=A0 =C2=A0 =C2=A0 > + * > + * This work is licensed under the terms of the GNU GPL version 2. > + * See the COPYING file in the top-level directory. > + * > + */ > + > +#include "qemu-common.h" > +#include "sysemu.h" > +#include "sysbus.h" > +#include "kvm.h" > +#include "kvmclock.h" > + > +#if defined(CONFIG_KVM_PARA) && defined(KVM_CAP_ADJUST_CLOCK) > + > +#include > +#include > + > +typedef struct KVMClockState { > + =C2=A0 =C2=A0SysBusDevice busdev; > + =C2=A0 =C2=A0uint64_t clock; > + =C2=A0 =C2=A0bool clock_valid; > +} KVMClockState; > + > +static void kvmclock_pre_save(void *opaque) > +{ > + =C2=A0 =C2=A0KVMClockState *s =3D opaque; > + =C2=A0 =C2=A0struct kvm_clock_data data; > + =C2=A0 =C2=A0int ret; > + > + =C2=A0 =C2=A0if (s->clock_valid) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0ret =3D kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); > + =C2=A0 =C2=A0if (ret < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0fprintf(stderr, "KVM_GET_CLOCK failed: %= s\n", strerror(ret)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0data.clock =3D 0; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0s->clock =3D data.clock; > + =C2=A0 =C2=A0/* > + =C2=A0 =C2=A0 * If the VM is stopped, declare the clock state valid= to avoid re-reading > + =C2=A0 =C2=A0 * it on next vmsave (which would return a different v= alue). Will be reset > + =C2=A0 =C2=A0 * when the VM is continued. > + =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0s->clock_valid =3D !vm_running; > +} > + > +static int kvmclock_post_load(void *opaque, int version_id) > +{ > + =C2=A0 =C2=A0KVMClockState *s =3D opaque; > + =C2=A0 =C2=A0struct kvm_clock_data data; > + > + =C2=A0 =C2=A0data.clock =3D s->clock; > + =C2=A0 =C2=A0data.flags =3D 0; > + =C2=A0 =C2=A0return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data); > +} > + > +static void kvmclock_vm_state_change(void *opaque, int running, int = reason) > +{ > + =C2=A0 =C2=A0KVMClockState *s =3D opaque; > + > + =C2=A0 =C2=A0if (running) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0s->clock_valid =3D false; > + =C2=A0 =C2=A0} > +} > + > +static int kvmclock_init(SysBusDevice *dev) > +{ > + =C2=A0 =C2=A0KVMClockState *s =3D FROM_SYSBUS(KVMClockState, dev); > + > + =C2=A0 =C2=A0qemu_add_vm_change_state_handler(kvmclock_vm_state_cha= nge, s); > + =C2=A0 =C2=A0return 0; > +} > + > +static const VMStateDescription kvmclock_vmsd =3D { > + =C2=A0 =C2=A0.name =3D "kvmclock", > + =C2=A0 =C2=A0.version_id =3D 1, > + =C2=A0 =C2=A0.minimum_version_id =3D 1, > + =C2=A0 =C2=A0.minimum_version_id_old =3D 1, > + =C2=A0 =C2=A0.pre_save =3D kvmclock_pre_save, > + =C2=A0 =C2=A0.post_load =3D kvmclock_post_load, > + =C2=A0 =C2=A0.fields =3D (VMStateField[]) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINT64(clock, KVMClockState), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_END_OF_LIST() > + =C2=A0 =C2=A0} > +}; > + > +static SysBusDeviceInfo kvmclock_info =3D { > + =C2=A0 =C2=A0.qdev.name =3D "kvmclock", > + =C2=A0 =C2=A0.qdev.size =3D sizeof(KVMClockState), > + =C2=A0 =C2=A0.qdev.vmsd =3D &kvmclock_vmsd, > + =C2=A0 =C2=A0.qdev.no_user =3D 1, > + =C2=A0 =C2=A0.init =3D kvmclock_init, > +}; > + > +/* Note: Must be called after VCPU initialization. */ > +void kvmclock_create(void) > +{ > + =C2=A0 =C2=A0if (kvm_enabled() && > + =C2=A0 =C2=A0 =C2=A0 =C2=A0first_cpu->cpuid_kvm_features & (1ULL <<= KVM_FEATURE_CLOCKSOURCE)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0sysbus_create_simple("kvmclock", -1, NUL= L); > + =C2=A0 =C2=A0} > +} =2E.. and with this moved to a header as a static inline function, it should be possible to use sysbus_try_create() (coming soon) to try to create the device. Then it's not fatal if the device can't be created, that just means that the capability was not available at build time.