xref: /openbmc/qemu/hw/i386/kvm/i8254.c (revision 58cd986422d7353e7fac56969ac59daab3cdca67)
1 /*
2  * KVM in-kernel PIT (i8254) support
3  *
4  * Copyright (c) 2003-2004 Fabrice Bellard
5  * Copyright (c) 2012      Jan Kiszka, Siemens AG
6  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
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.
24  */
25 #include "qemu/timer.h"
26 #include "sysemu/sysemu.h"
27 #include "hw/timer/i8254.h"
28 #include "hw/timer/i8254_internal.h"
29 #include "sysemu/kvm.h"
30 
31 #define KVM_PIT_REINJECT_BIT 0
32 
33 #define CALIBRATION_ROUNDS   3
34 
35 #define KVM_PIT(obj) OBJECT_CHECK(KVMPITState, (obj), TYPE_KVM_I8254)
36 
37 typedef struct KVMPITState {
38     PITCommonState parent_obj;
39 
40     LostTickPolicy lost_tick_policy;
41     bool vm_stopped;
42     int64_t kernel_clock_offset;
43 } KVMPITState;
44 
45 static int64_t abs64(int64_t v)
46 {
47     return v < 0 ? -v : v;
48 }
49 
50 static void kvm_pit_update_clock_offset(KVMPITState *s)
51 {
52     int64_t offset, clock_offset;
53     struct timespec ts;
54     int i;
55 
56     /*
57      * Measure the delta between CLOCK_MONOTONIC, the base used for
58      * kvm_pit_channel_state::count_load_time, and vm_clock. Take the
59      * minimum of several samples to filter out scheduling noise.
60      */
61     clock_offset = INT64_MAX;
62     for (i = 0; i < CALIBRATION_ROUNDS; i++) {
63         offset = qemu_get_clock_ns(vm_clock);
64         clock_gettime(CLOCK_MONOTONIC, &ts);
65         offset -= ts.tv_nsec;
66         offset -= (int64_t)ts.tv_sec * 1000000000;
67         if (abs64(offset) < abs64(clock_offset)) {
68             clock_offset = offset;
69         }
70     }
71     s->kernel_clock_offset = clock_offset;
72 }
73 
74 static void kvm_pit_get(PITCommonState *pit)
75 {
76     KVMPITState *s = KVM_PIT(pit);
77     struct kvm_pit_state2 kpit;
78     struct kvm_pit_channel_state *kchan;
79     struct PITChannelState *sc;
80     int i, ret;
81 
82     /* No need to re-read the state if VM is stopped. */
83     if (s->vm_stopped) {
84         return;
85     }
86 
87     if (kvm_has_pit_state2()) {
88         ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
89         if (ret < 0) {
90             fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
91             abort();
92         }
93         pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
94     } else {
95         /*
96          * kvm_pit_state2 is superset of kvm_pit_state struct,
97          * so we can use it for KVM_GET_PIT as well.
98          */
99         ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT, &kpit);
100         if (ret < 0) {
101             fprintf(stderr, "KVM_GET_PIT failed: %s\n", strerror(ret));
102             abort();
103         }
104     }
105     for (i = 0; i < 3; i++) {
106         kchan = &kpit.channels[i];
107         sc = &pit->channels[i];
108         sc->count = kchan->count;
109         sc->latched_count = kchan->latched_count;
110         sc->count_latched = kchan->count_latched;
111         sc->status_latched = kchan->status_latched;
112         sc->status = kchan->status;
113         sc->read_state = kchan->read_state;
114         sc->write_state = kchan->write_state;
115         sc->write_latch = kchan->write_latch;
116         sc->rw_mode = kchan->rw_mode;
117         sc->mode = kchan->mode;
118         sc->bcd = kchan->bcd;
119         sc->gate = kchan->gate;
120         sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
121     }
122 
123     sc = &pit->channels[0];
124     sc->next_transition_time =
125         pit_get_next_transition_time(sc, sc->count_load_time);
126 }
127 
128 static void kvm_pit_put(PITCommonState *pit)
129 {
130     KVMPITState *s = KVM_PIT(pit);
131     struct kvm_pit_state2 kpit;
132     struct kvm_pit_channel_state *kchan;
133     struct PITChannelState *sc;
134     int i, ret;
135 
136     /* The offset keeps changing as long as the VM is stopped. */
137     if (s->vm_stopped) {
138         kvm_pit_update_clock_offset(s);
139     }
140 
141     kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
142     for (i = 0; i < 3; i++) {
143         kchan = &kpit.channels[i];
144         sc = &pit->channels[i];
145         kchan->count = sc->count;
146         kchan->latched_count = sc->latched_count;
147         kchan->count_latched = sc->count_latched;
148         kchan->status_latched = sc->status_latched;
149         kchan->status = sc->status;
150         kchan->read_state = sc->read_state;
151         kchan->write_state = sc->write_state;
152         kchan->write_latch = sc->write_latch;
153         kchan->rw_mode = sc->rw_mode;
154         kchan->mode = sc->mode;
155         kchan->bcd = sc->bcd;
156         kchan->gate = sc->gate;
157         kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
158     }
159 
160     ret = kvm_vm_ioctl(kvm_state,
161                        kvm_has_pit_state2() ? KVM_SET_PIT2 : KVM_SET_PIT,
162                        &kpit);
163     if (ret < 0) {
164         fprintf(stderr, "%s failed: %s\n",
165                 kvm_has_pit_state2() ? "KVM_SET_PIT2" : "KVM_SET_PIT",
166                 strerror(ret));
167         abort();
168     }
169 }
170 
171 static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
172 {
173     kvm_pit_get(s);
174 
175     switch (sc->mode) {
176     default:
177     case 0:
178     case 4:
179         /* XXX: just disable/enable counting */
180         break;
181     case 1:
182     case 2:
183     case 3:
184     case 5:
185         if (sc->gate < val) {
186             /* restart counting on rising edge */
187             sc->count_load_time = qemu_get_clock_ns(vm_clock);
188         }
189         break;
190     }
191     sc->gate = val;
192 
193     kvm_pit_put(s);
194 }
195 
196 static void kvm_pit_get_channel_info(PITCommonState *s, PITChannelState *sc,
197                                      PITChannelInfo *info)
198 {
199     kvm_pit_get(s);
200 
201     pit_get_channel_info_common(s, sc, info);
202 }
203 
204 static void kvm_pit_reset(DeviceState *dev)
205 {
206     PITCommonState *s = PIT_COMMON(dev);
207 
208     pit_reset_common(s);
209 
210     kvm_pit_put(s);
211 }
212 
213 static void kvm_pit_irq_control(void *opaque, int n, int enable)
214 {
215     PITCommonState *pit = opaque;
216     PITChannelState *s = &pit->channels[0];
217 
218     kvm_pit_get(pit);
219 
220     s->irq_disabled = !enable;
221 
222     kvm_pit_put(pit);
223 }
224 
225 static void kvm_pit_vm_state_change(void *opaque, int running,
226                                     RunState state)
227 {
228     KVMPITState *s = opaque;
229 
230     if (running) {
231         kvm_pit_update_clock_offset(s);
232         s->vm_stopped = false;
233     } else {
234         kvm_pit_update_clock_offset(s);
235         kvm_pit_get(PIT_COMMON(s));
236         s->vm_stopped = true;
237     }
238 }
239 
240 static int kvm_pit_initfn(PITCommonState *pit)
241 {
242     KVMPITState *s = KVM_PIT(pit);
243     struct kvm_pit_config config = {
244         .flags = 0,
245     };
246     int ret;
247 
248     if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) {
249         ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config);
250     } else {
251         ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
252     }
253     if (ret < 0) {
254         fprintf(stderr, "Create kernel PIC irqchip failed: %s\n",
255                 strerror(ret));
256         return ret;
257     }
258     switch (s->lost_tick_policy) {
259     case LOST_TICK_DELAY:
260         break; /* enabled by default */
261     case LOST_TICK_DISCARD:
262         if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) {
263             struct kvm_reinject_control control = { .pit_reinject = 0 };
264 
265             ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
266             if (ret < 0) {
267                 fprintf(stderr,
268                         "Can't disable in-kernel PIT reinjection: %s\n",
269                         strerror(ret));
270                 return ret;
271             }
272         }
273         break;
274     default:
275         return -EINVAL;
276     }
277 
278     memory_region_init_reservation(&pit->ioports, "kvm-pit", 4);
279 
280     qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
281 
282     qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
283 
284     return 0;
285 }
286 
287 static Property kvm_pit_properties[] = {
288     DEFINE_PROP_HEX32("iobase", PITCommonState, iobase,  -1),
289     DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
290                                lost_tick_policy, LOST_TICK_DELAY),
291     DEFINE_PROP_END_OF_LIST(),
292 };
293 
294 static void kvm_pit_class_init(ObjectClass *klass, void *data)
295 {
296     PITCommonClass *k = PIT_COMMON_CLASS(klass);
297     DeviceClass *dc = DEVICE_CLASS(klass);
298 
299     k->init = kvm_pit_initfn;
300     k->set_channel_gate = kvm_pit_set_gate;
301     k->get_channel_info = kvm_pit_get_channel_info;
302     k->pre_save = kvm_pit_get;
303     k->post_load = kvm_pit_put;
304     dc->reset = kvm_pit_reset;
305     dc->props = kvm_pit_properties;
306 }
307 
308 static const TypeInfo kvm_pit_info = {
309     .name          = TYPE_KVM_I8254,
310     .parent        = TYPE_PIT_COMMON,
311     .instance_size = sizeof(KVMPITState),
312     .class_init = kvm_pit_class_init,
313 };
314 
315 static void kvm_pit_register(void)
316 {
317     type_register_static(&kvm_pit_info);
318 }
319 
320 type_init(kvm_pit_register)
321