kvm: i8254: Cache kernel clock offset in KVMPITState
[qemu-kvm.git] / hw / kvm / i8254.c
blobc235d80a5adc33d181e2c5cfeaf70a48a2f1f844
1 /*
2 * KVM in-kernel PIT (i8254) support
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 * Copyright (c) 2012 Jan Kiszka, Siemens AG
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
25 #include "qemu-timer.h"
26 #include "sysemu.h"
27 #include "hw/i8254.h"
28 #include "hw/i8254_internal.h"
29 #include "kvm.h"
31 #define KVM_PIT_REINJECT_BIT 0
33 #define CALIBRATION_ROUNDS 3
35 typedef struct KVMPITState {
36 PITCommonState pit;
37 LostTickPolicy lost_tick_policy;
38 bool vm_stopped;
39 int64_t kernel_clock_offset;
40 } KVMPITState;
42 static int64_t abs64(int64_t v)
44 return v < 0 ? -v : v;
47 static void kvm_pit_update_clock_offset(KVMPITState *s)
49 int64_t offset, clock_offset;
50 struct timespec ts;
51 int i;
54 * Measure the delta between CLOCK_MONOTONIC, the base used for
55 * kvm_pit_channel_state::count_load_time, and vm_clock. Take the
56 * minimum of several samples to filter out scheduling noise.
58 clock_offset = INT64_MAX;
59 for (i = 0; i < CALIBRATION_ROUNDS; i++) {
60 offset = qemu_get_clock_ns(vm_clock);
61 clock_gettime(CLOCK_MONOTONIC, &ts);
62 offset -= ts.tv_nsec;
63 offset -= (int64_t)ts.tv_sec * 1000000000;
64 if (abs64(offset) < abs64(clock_offset)) {
65 clock_offset = offset;
68 s->kernel_clock_offset = clock_offset;
71 static void kvm_pit_get(PITCommonState *pit)
73 KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
74 struct kvm_pit_state2 kpit;
75 struct kvm_pit_channel_state *kchan;
76 struct PITChannelState *sc;
77 int i, ret;
79 /* No need to re-read the state if VM is stopped. */
80 if (s->vm_stopped) {
81 return;
84 if (kvm_has_pit_state2()) {
85 ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
86 if (ret < 0) {
87 fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
88 abort();
90 pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
91 } else {
93 * kvm_pit_state2 is superset of kvm_pit_state struct,
94 * so we can use it for KVM_GET_PIT as well.
96 ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT, &kpit);
97 if (ret < 0) {
98 fprintf(stderr, "KVM_GET_PIT failed: %s\n", strerror(ret));
99 abort();
102 for (i = 0; i < 3; i++) {
103 kchan = &kpit.channels[i];
104 sc = &pit->channels[i];
105 sc->count = kchan->count;
106 sc->latched_count = kchan->latched_count;
107 sc->count_latched = kchan->count_latched;
108 sc->status_latched = kchan->status_latched;
109 sc->status = kchan->status;
110 sc->read_state = kchan->read_state;
111 sc->write_state = kchan->write_state;
112 sc->write_latch = kchan->write_latch;
113 sc->rw_mode = kchan->rw_mode;
114 sc->mode = kchan->mode;
115 sc->bcd = kchan->bcd;
116 sc->gate = kchan->gate;
117 sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
120 sc = &pit->channels[0];
121 sc->next_transition_time =
122 pit_get_next_transition_time(sc, sc->count_load_time);
125 static void kvm_pit_put(PITCommonState *s)
127 struct kvm_pit_state2 kpit;
128 struct kvm_pit_channel_state *kchan;
129 struct PITChannelState *sc;
130 int i, ret;
132 kpit.flags = s->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
133 for (i = 0; i < 3; i++) {
134 kchan = &kpit.channels[i];
135 sc = &s->channels[i];
136 kchan->count = sc->count;
137 kchan->latched_count = sc->latched_count;
138 kchan->count_latched = sc->count_latched;
139 kchan->status_latched = sc->status_latched;
140 kchan->status = sc->status;
141 kchan->read_state = sc->read_state;
142 kchan->write_state = sc->write_state;
143 kchan->write_latch = sc->write_latch;
144 kchan->rw_mode = sc->rw_mode;
145 kchan->mode = sc->mode;
146 kchan->bcd = sc->bcd;
147 kchan->gate = sc->gate;
148 kchan->count_load_time = sc->count_load_time;
151 ret = kvm_vm_ioctl(kvm_state,
152 kvm_has_pit_state2() ? KVM_SET_PIT2 : KVM_SET_PIT,
153 &kpit);
154 if (ret < 0) {
155 fprintf(stderr, "%s failed: %s\n",
156 kvm_has_pit_state2() ? "KVM_SET_PIT2" : "KVM_SET_PIT",
157 strerror(ret));
158 abort();
162 static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
164 kvm_pit_get(s);
166 switch (sc->mode) {
167 default:
168 case 0:
169 case 4:
170 /* XXX: just disable/enable counting */
171 break;
172 case 1:
173 case 2:
174 case 3:
175 case 5:
176 if (sc->gate < val) {
177 /* restart counting on rising edge */
178 sc->count_load_time = qemu_get_clock_ns(vm_clock);
180 break;
182 sc->gate = val;
184 kvm_pit_put(s);
187 static void kvm_pit_get_channel_info(PITCommonState *s, PITChannelState *sc,
188 PITChannelInfo *info)
190 kvm_pit_get(s);
192 pit_get_channel_info_common(s, sc, info);
195 static void kvm_pit_reset(DeviceState *dev)
197 PITCommonState *s = DO_UPCAST(PITCommonState, dev.qdev, dev);
199 pit_reset_common(s);
201 kvm_pit_put(s);
204 static void kvm_pit_irq_control(void *opaque, int n, int enable)
206 PITCommonState *pit = opaque;
207 PITChannelState *s = &pit->channels[0];
209 kvm_pit_get(pit);
211 s->irq_disabled = !enable;
213 kvm_pit_put(pit);
216 static void kvm_pit_vm_state_change(void *opaque, int running,
217 RunState state)
219 KVMPITState *s = opaque;
221 if (running) {
222 kvm_pit_update_clock_offset(s);
223 s->vm_stopped = false;
224 } else {
225 kvm_pit_update_clock_offset(s);
226 kvm_pit_get(&s->pit);
227 s->vm_stopped = true;
231 static int kvm_pit_initfn(PITCommonState *pit)
233 KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
234 struct kvm_pit_config config = {
235 .flags = 0,
237 int ret;
239 if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) {
240 ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config);
241 } else {
242 ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
244 if (ret < 0) {
245 fprintf(stderr, "Create kernel PIC irqchip failed: %s\n",
246 strerror(ret));
247 return ret;
249 switch (s->lost_tick_policy) {
250 case LOST_TICK_DELAY:
251 break; /* enabled by default */
252 case LOST_TICK_DISCARD:
253 if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) {
254 struct kvm_reinject_control control = { .pit_reinject = 0 };
256 ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
257 if (ret < 0) {
258 fprintf(stderr,
259 "Can't disable in-kernel PIT reinjection: %s\n",
260 strerror(ret));
261 return ret;
264 break;
265 default:
266 return -EINVAL;
269 memory_region_init_reservation(&pit->ioports, "kvm-pit", 4);
271 qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
273 qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
275 return 0;
278 static Property kvm_pit_properties[] = {
279 DEFINE_PROP_HEX32("iobase", KVMPITState, pit.iobase, -1),
280 DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
281 lost_tick_policy, LOST_TICK_DELAY),
282 DEFINE_PROP_END_OF_LIST(),
285 static void kvm_pit_class_init(ObjectClass *klass, void *data)
287 PITCommonClass *k = PIT_COMMON_CLASS(klass);
288 DeviceClass *dc = DEVICE_CLASS(klass);
290 k->init = kvm_pit_initfn;
291 k->set_channel_gate = kvm_pit_set_gate;
292 k->get_channel_info = kvm_pit_get_channel_info;
293 k->pre_save = kvm_pit_get;
294 k->post_load = kvm_pit_put;
295 dc->reset = kvm_pit_reset;
296 dc->props = kvm_pit_properties;
299 static TypeInfo kvm_pit_info = {
300 .name = "kvm-pit",
301 .parent = TYPE_PIT_COMMON,
302 .instance_size = sizeof(KVMPITState),
303 .class_init = kvm_pit_class_init,
306 static void kvm_pit_register(void)
308 type_register_static(&kvm_pit_info);
311 type_init(kvm_pit_register)