@@ -29,6 +29,7 @@
#include "hw/apic.h"
#include "ioport.h"
#include "kvm_x86.h"
+#include "hw/sysbus.h"
#ifdef CONFIG_KVM_PARA
#include <linux/kvm_para.h>
@@ -309,6 +310,64 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
#endif
}
+#ifdef KVM_CAP_ADJUST_CLOCK
+typedef struct KVMClockState {
+ SysBusDevice busdev;
+ uint64_t clock;
+ struct kvm_clock_data data;
+} KVMClockState;
+
+static void kvmclock_pre_save(void *opaque)
+{
+ KVMClockState *s = opaque;
+ struct kvm_clock_data data;
+ int ret;
+
+ ret = kvm_vm_ioctl(KVM_GET_CLOCK, &data);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
+ data.clock = 0;
+ }
+ s->clock = data.clock;
+}
+
+static int kvmclock_post_load(void *opaque, int version_id)
+{
+ KVMClockState *s = opaque;
+ struct kvm_clock_data data;
+
+ data.clock = s->clock;
+ data.flags = 0;
+ return kvm_vm_ioctl(KVM_SET_CLOCK, &data);
+}
+
+static int kvmclock_init(SysBusDevice *dev)
+{
+ return 0;
+}
+
+static const VMStateDescription kvmclock_vmsd= {
+ .name = "kvmclock",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_save = kvmclock_pre_save,
+ .post_load = kvmclock_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(clock, KVMClockState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static SysBusDeviceInfo kvmclock_info = {
+ .qdev.name = "kvmclock",
+ .qdev.size = sizeof(KVMClockState),
+ .qdev.vmsd = &kvmclock_vmsd,
+ .qdev.no_user = 1,
+ .init = kvmclock_init,
+};
+#endif /* KVM_CAP_ADJUST_CLOCK */
+
int kvm_arch_init_vcpu(CPUState *env)
{
struct {
@@ -337,7 +396,6 @@ int kvm_arch_init_vcpu(CPUState *env)
env->cpuid_svm_features &= kvm_x86_get_supported_cpuid(0x8000000A,
0, R_EDX);
-
cpuid_i = 0;
#ifdef CONFIG_KVM_PARA
@@ -444,6 +502,13 @@ int kvm_arch_init_vcpu(CPUState *env)
}
#endif
+#ifdef KVM_CAP_ADJUST_CLOCK
+ if (cpu_is_bsp(env) &&
+ (env->cpuid_kvm_features & (1ULL << KVM_FEATURE_CLOCKSOURCE))) {
+ sysbus_create_simple("kvmclock", -1, NULL);
+ }
+#endif
+
return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
}
@@ -535,6 +600,10 @@ int kvm_arch_init(int smp_cpus)
int ret;
struct utsname utsname;
+#ifdef KVM_CAP_ADJUST_CLOCK
+ sysbus_register_withprop(&kvmclock_info);
+#endif
+
ret = kvm_get_supported_msrs();
if (ret < 0) {
return ret;