From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=41918 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PmYJS-0000La-7R for qemu-devel@nongnu.org; Mon, 07 Feb 2011 16:08:02 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PmWwH-0004em-V0 for qemu-devel@nongnu.org; Mon, 07 Feb 2011 14:39:59 -0500 Received: from mail-pw0-f45.google.com ([209.85.160.45]:54599) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PmWwH-0004eh-Lj for qemu-devel@nongnu.org; Mon, 07 Feb 2011 14:39:57 -0500 Received: by pwj6 with SMTP id 6so1286610pwj.4 for ; Mon, 07 Feb 2011 11:39:55 -0800 (PST) MIME-Version: 1.0 In-Reply-To: References: From: Blue Swirl Date: Mon, 7 Feb 2011 21:39:35 +0200 Message-ID: Subject: Re: [Qemu-devel] [PATCH 15/15] kvm: x86: Introduce kvmclock device to save/restore its state Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Jan Kiszka Cc: Glauber Costa , Marcelo Tosatti , Avi Kivity , kvm@vger.kernel.org, qemu-devel@nongnu.org On Mon, Feb 7, 2011 at 1:19 PM, Jan Kiszka wrote: > If kvmclock is used, which implies the kernel supports it, register a > kvmclock device with the sysbus. Its main purpose is to save and restore > 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_CFL= AGS) > > =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_ib700.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 value= ). 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 reas= on) > +{ > + =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_change,= 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, NULL); > + =C2=A0 =C2=A0} > +} ... 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.