*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
#include "qemu/host-utils.h"
-#include "sysemu/sysemu.h"
+#include "qemu/module.h"
#include "sysemu/kvm.h"
+#include "sysemu/runstate.h"
#include "sysemu/hw_accel.h"
-#include "kvm_i386.h"
+#include "kvm/kvm_i386.h"
+#include "migration/vmstate.h"
#include "hw/sysbus.h"
-#include "hw/kvm/clock.h"
+#include "hw/i386/kvm/clock.h"
+#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include <linux/kvm.h>
-#include <linux/kvm_para.h>
+#include "standard-headers/asm-x86/kvm_para.h"
+#include "qom/object.h"
#define TYPE_KVM_CLOCK "kvmclock"
-#define KVM_CLOCK(obj) OBJECT_CHECK(KVMClockState, (obj), TYPE_KVM_CLOCK)
+OBJECT_DECLARE_SIMPLE_TYPE(KVMClockState, KVM_CLOCK)
-typedef struct KVMClockState {
+struct KVMClockState {
/*< private >*/
SysBusDevice busdev;
/*< public >*/
uint64_t clock;
bool clock_valid;
+ /* whether the 'clock' value was obtained in the 'paused' state */
+ bool runstate_paused;
+
/* whether machine type supports reliable KVM_GET_CLOCK */
bool mach_use_reliable_get_clock;
/* whether the 'clock' value was obtained in a host with
* reliable KVM_GET_CLOCK */
bool clock_is_reliable;
-} KVMClockState;
+};
struct pvclock_vcpu_time_info {
uint32_t version;
static uint64_t kvmclock_current_nsec(KVMClockState *s)
{
CPUState *cpu = first_cpu;
- CPUX86State *env = cpu->env_ptr;
+ CPUX86State *env = cpu_env(cpu);
hwaddr kvmclock_struct_pa;
uint64_t migration_tsc = env->tsc;
struct pvclock_vcpu_time_info time;
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
if (ret < 0) {
- fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
+ fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(-ret));
abort();
}
s->clock = data.clock;
s->clock_is_reliable = kvm_has_adjust_clock_stable();
}
-static void kvmclock_vm_state_change(void *opaque, int running,
+static void do_kvmclock_ctrl(CPUState *cpu, run_on_cpu_data data)
+{
+ int ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
+
+ if (ret && ret != -EINVAL) {
+ fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
+ }
+}
+
+static void kvmclock_vm_state_change(void *opaque, bool running,
RunState state)
{
KVMClockState *s = opaque;
data.clock = s->clock;
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
if (ret < 0) {
- fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(ret));
+ fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(-ret));
abort();
}
return;
}
CPU_FOREACH(cpu) {
- ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
- if (ret) {
- if (ret != -EINVAL) {
- fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
- }
- return;
- }
+ run_on_cpu(cpu, do_kvmclock_ctrl, RUN_ON_CPU_NULL);
}
} else {
return;
}
+ s->runstate_paused = runstate_check(RUN_STATE_PAUSED);
+
kvm_synchronize_all_tsc();
kvm_update_clock(s);
};
/*
- * When migrating, read the clock just before migration,
- * so that the guest clock counts during the events
- * between:
+ * When migrating, assume the source has an unreliable
+ * KVM_GET_CLOCK unless told otherwise.
+ */
+static int kvmclock_pre_load(void *opaque)
+{
+ KVMClockState *s = opaque;
+
+ s->clock_is_reliable = false;
+
+ return 0;
+}
+
+/*
+ * When migrating a running guest, read the clock just
+ * before migration, so that the guest clock counts
+ * during the events between:
*
* * vm_stop()
* *
{
KVMClockState *s = opaque;
- kvm_update_clock(s);
+ if (!s->runstate_paused) {
+ kvm_update_clock(s);
+ }
return 0;
}
.name = "kvmclock",
.version_id = 1,
.minimum_version_id = 1,
+ .pre_load = kvmclock_pre_load,
.pre_save = kvmclock_pre_save,
.fields = (VMStateField[]) {
VMSTATE_UINT64(clock, KVMClockState),
dc->realize = kvmclock_realize;
dc->vmsd = &kvmclock_vmsd;
- dc->props = kvmclock_properties;
+ device_class_set_props(dc, kvmclock_properties);
}
static const TypeInfo kvmclock_info = {
};
/* Note: Must be called after VCPU initialization. */
-void kvmclock_create(void)
+void kvmclock_create(bool create_always)
{
X86CPU *cpu = X86_CPU(first_cpu);
- if (kvm_enabled() &&
+ assert(kvm_enabled());
+ if (!kvm_has_adjust_clock()) {
+ return;
+ }
+
+ if (create_always ||
cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
(1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
sysbus_create_simple(TYPE_KVM_CLOCK, -1, NULL);