xref: /openbmc/qemu/hw/i386/kvm/clock.c (revision 9121d02c)
1 /*
2  * QEMU KVM support, paravirtual clock device
3  *
4  * Copyright (C) 2011 Siemens AG
5  *
6  * Authors:
7  *  Jan Kiszka        <jan.kiszka@siemens.com>
8  *
9  * This work is licensed under the terms of the GNU GPL version 2.
10  * See the COPYING file in the top-level directory.
11  *
12  * Contributions after 2012-01-13 are licensed under the terms of the
13  * GNU GPL, version 2 or (at your option) any later version.
14  */
15 
16 #include "qemu-common.h"
17 #include "sysemu/sysemu.h"
18 #include "sysemu/kvm.h"
19 #include "hw/sysbus.h"
20 #include "hw/kvm/clock.h"
21 
22 #include <linux/kvm.h>
23 #include <linux/kvm_para.h>
24 
25 typedef struct KVMClockState {
26     SysBusDevice busdev;
27     uint64_t clock;
28     bool clock_valid;
29 } KVMClockState;
30 
31 
32 static void kvmclock_vm_state_change(void *opaque, int running,
33                                      RunState state)
34 {
35     KVMClockState *s = opaque;
36     CPUState *cpu = first_cpu;
37     int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL);
38     int ret;
39 
40     if (running) {
41         struct kvm_clock_data data;
42 
43         s->clock_valid = false;
44 
45         data.clock = s->clock;
46         data.flags = 0;
47         ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
48         if (ret < 0) {
49             fprintf(stderr, "KVM_SET_CLOCK failed: %s\n", strerror(ret));
50             abort();
51         }
52 
53         if (!cap_clock_ctrl) {
54             return;
55         }
56         for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
57             ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
58             if (ret) {
59                 if (ret != -EINVAL) {
60                     fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
61                 }
62                 return;
63             }
64         }
65     } else {
66         struct kvm_clock_data data;
67         int ret;
68 
69         if (s->clock_valid) {
70             return;
71         }
72         ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
73         if (ret < 0) {
74             fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
75             abort();
76         }
77         s->clock = data.clock;
78 
79         /*
80          * If the VM is stopped, declare the clock state valid to
81          * avoid re-reading it on next vmsave (which would return
82          * a different value). Will be reset when the VM is continued.
83          */
84         s->clock_valid = true;
85     }
86 }
87 
88 static int kvmclock_init(SysBusDevice *dev)
89 {
90     KVMClockState *s = FROM_SYSBUS(KVMClockState, dev);
91 
92     qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
93     return 0;
94 }
95 
96 static const VMStateDescription kvmclock_vmsd = {
97     .name = "kvmclock",
98     .version_id = 1,
99     .minimum_version_id = 1,
100     .minimum_version_id_old = 1,
101     .fields = (VMStateField[]) {
102         VMSTATE_UINT64(clock, KVMClockState),
103         VMSTATE_END_OF_LIST()
104     }
105 };
106 
107 static void kvmclock_class_init(ObjectClass *klass, void *data)
108 {
109     DeviceClass *dc = DEVICE_CLASS(klass);
110     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
111 
112     k->init = kvmclock_init;
113     dc->no_user = 1;
114     dc->vmsd = &kvmclock_vmsd;
115 }
116 
117 static const TypeInfo kvmclock_info = {
118     .name          = "kvmclock",
119     .parent        = TYPE_SYS_BUS_DEVICE,
120     .instance_size = sizeof(KVMClockState),
121     .class_init    = kvmclock_class_init,
122 };
123 
124 /* Note: Must be called after VCPU initialization. */
125 void kvmclock_create(void)
126 {
127     X86CPU *cpu = X86_CPU(first_cpu);
128 
129     if (kvm_enabled() &&
130         cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
131                                        (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
132         sysbus_create_simple("kvmclock", -1, NULL);
133     }
134 }
135 
136 static void kvmclock_register_types(void)
137 {
138     type_register_static(&kvmclock_info);
139 }
140 
141 type_init(kvmclock_register_types)
142