diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index aba6842a22..10d34254f0 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -50,6 +50,9 @@ struct KVMClockState { /* whether the 'clock' value was obtained in a host with * reliable KVM_GET_CLOCK */ bool clock_is_reliable; + + NotifierWithReturn kvmclock_vcpufd_change_notifier; + NotifierWithReturn kvmclock_vmfd_change_notifier; }; struct pvclock_vcpu_time_info { @@ -63,6 +66,9 @@ struct pvclock_vcpu_time_info { uint8_t pad[2]; } __attribute__((__packed__)); /* 32 bytes */ +static int kvmclock_set_clock(NotifierWithReturn *notifier, + void *data, Error** errp); + static uint64_t kvmclock_current_nsec(KVMClockState *s) { CPUState *cpu = first_cpu; @@ -219,6 +225,54 @@ static void kvmclock_vm_state_change(void *opaque, bool running, } } +static int kvmclock_save_clock(NotifierWithReturn *notifier, + void *data, Error** errp) +{ + if (!((VmfdChangeNotifier *)data)->pre) { + return 0; + } + KVMClockState *s = container_of(notifier, KVMClockState, + kvmclock_vmfd_change_notifier); + kvm_update_clock(s); + return 0; +} + +static int kvmclock_set_clock(NotifierWithReturn *notifier, + void *data, Error** errp) +{ + struct kvm_clock_data clock_data = {}; + CPUState *cpu; + int ret; + KVMClockState *s = container_of(notifier, KVMClockState, + kvmclock_vcpufd_change_notifier); + int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL); + + if (!s->clock_is_reliable) { + uint64_t pvclock_via_mem = kvmclock_current_nsec(s); + /* saved clock value before vmfd change is not reliable */ + if (pvclock_via_mem) { + s->clock = pvclock_via_mem; + } + } + + clock_data.clock = s->clock; + ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &clock_data); + if (ret < 0) { + fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(-ret)); + abort(); + } + + if (!cap_clock_ctrl) { + return 0; + } + CPU_FOREACH(cpu) { + run_on_cpu(cpu, do_kvmclock_ctrl, RUN_ON_CPU_NULL); + } + + return 0; +} + + static void kvmclock_realize(DeviceState *dev, Error **errp) { KVMClockState *s = KVM_CLOCK(dev); @@ -230,7 +284,12 @@ static void kvmclock_realize(DeviceState *dev, Error **errp) kvm_update_clock(s); + s->kvmclock_vcpufd_change_notifier.notify = kvmclock_set_clock; + s->kvmclock_vmfd_change_notifier.notify = kvmclock_save_clock; + qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s); + kvm_vcpufd_add_change_notifier(&s->kvmclock_vcpufd_change_notifier); + kvm_vmfd_add_change_notifier(&s->kvmclock_vmfd_change_notifier); } static bool kvmclock_clock_is_reliable_needed(void *opaque)