Statistics
| Branch: | Revision:

root / hw / kvm / i8254.c @ 9c17d615

History | View | Annotate | Download (9.2 kB)

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/i8254.h"
28
#include "hw/i8254_internal.h"
29
#include "sysemu/kvm.h"
30

    
31
#define KVM_PIT_REINJECT_BIT 0
32

    
33
#define CALIBRATION_ROUNDS   3
34

    
35
typedef struct KVMPITState {
36
    PITCommonState pit;
37
    LostTickPolicy lost_tick_policy;
38
    bool vm_stopped;
39
    int64_t kernel_clock_offset;
40
} KVMPITState;
41

    
42
static int64_t abs64(int64_t v)
43
{
44
    return v < 0 ? -v : v;
45
}
46

    
47
static void kvm_pit_update_clock_offset(KVMPITState *s)
48
{
49
    int64_t offset, clock_offset;
50
    struct timespec ts;
51
    int i;
52

    
53
    /*
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.
57
     */
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;
66
        }
67
    }
68
    s->kernel_clock_offset = clock_offset;
69
}
70

    
71
static void kvm_pit_get(PITCommonState *pit)
72
{
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;
78

    
79
    /* No need to re-read the state if VM is stopped. */
80
    if (s->vm_stopped) {
81
        return;
82
    }
83

    
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();
89
        }
90
        pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
91
    } else {
92
        /*
93
         * kvm_pit_state2 is superset of kvm_pit_state struct,
94
         * so we can use it for KVM_GET_PIT as well.
95
         */
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();
100
        }
101
    }
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;
118
    }
119

    
120
    sc = &pit->channels[0];
121
    sc->next_transition_time =
122
        pit_get_next_transition_time(sc, sc->count_load_time);
123
}
124

    
125
static void kvm_pit_put(PITCommonState *pit)
126
{
127
    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
128
    struct kvm_pit_state2 kpit;
129
    struct kvm_pit_channel_state *kchan;
130
    struct PITChannelState *sc;
131
    int i, ret;
132

    
133
    /* The offset keeps changing as long as the VM is stopped. */
134
    if (s->vm_stopped) {
135
        kvm_pit_update_clock_offset(s);
136
    }
137

    
138
    kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
139
    for (i = 0; i < 3; i++) {
140
        kchan = &kpit.channels[i];
141
        sc = &pit->channels[i];
142
        kchan->count = sc->count;
143
        kchan->latched_count = sc->latched_count;
144
        kchan->count_latched = sc->count_latched;
145
        kchan->status_latched = sc->status_latched;
146
        kchan->status = sc->status;
147
        kchan->read_state = sc->read_state;
148
        kchan->write_state = sc->write_state;
149
        kchan->write_latch = sc->write_latch;
150
        kchan->rw_mode = sc->rw_mode;
151
        kchan->mode = sc->mode;
152
        kchan->bcd = sc->bcd;
153
        kchan->gate = sc->gate;
154
        kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
155
    }
156

    
157
    ret = kvm_vm_ioctl(kvm_state,
158
                       kvm_has_pit_state2() ? KVM_SET_PIT2 : KVM_SET_PIT,
159
                       &kpit);
160
    if (ret < 0) {
161
        fprintf(stderr, "%s failed: %s\n",
162
                kvm_has_pit_state2() ? "KVM_SET_PIT2" : "KVM_SET_PIT",
163
                strerror(ret));
164
        abort();
165
    }
166
}
167

    
168
static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
169
{
170
    kvm_pit_get(s);
171

    
172
    switch (sc->mode) {
173
    default:
174
    case 0:
175
    case 4:
176
        /* XXX: just disable/enable counting */
177
        break;
178
    case 1:
179
    case 2:
180
    case 3:
181
    case 5:
182
        if (sc->gate < val) {
183
            /* restart counting on rising edge */
184
            sc->count_load_time = qemu_get_clock_ns(vm_clock);
185
        }
186
        break;
187
    }
188
    sc->gate = val;
189

    
190
    kvm_pit_put(s);
191
}
192

    
193
static void kvm_pit_get_channel_info(PITCommonState *s, PITChannelState *sc,
194
                                     PITChannelInfo *info)
195
{
196
    kvm_pit_get(s);
197

    
198
    pit_get_channel_info_common(s, sc, info);
199
}
200

    
201
static void kvm_pit_reset(DeviceState *dev)
202
{
203
    PITCommonState *s = DO_UPCAST(PITCommonState, dev.qdev, dev);
204

    
205
    pit_reset_common(s);
206

    
207
    kvm_pit_put(s);
208
}
209

    
210
static void kvm_pit_irq_control(void *opaque, int n, int enable)
211
{
212
    PITCommonState *pit = opaque;
213
    PITChannelState *s = &pit->channels[0];
214

    
215
    kvm_pit_get(pit);
216

    
217
    s->irq_disabled = !enable;
218

    
219
    kvm_pit_put(pit);
220
}
221

    
222
static void kvm_pit_vm_state_change(void *opaque, int running,
223
                                    RunState state)
224
{
225
    KVMPITState *s = opaque;
226

    
227
    if (running) {
228
        kvm_pit_update_clock_offset(s);
229
        s->vm_stopped = false;
230
    } else {
231
        kvm_pit_update_clock_offset(s);
232
        kvm_pit_get(&s->pit);
233
        s->vm_stopped = true;
234
    }
235
}
236

    
237
static int kvm_pit_initfn(PITCommonState *pit)
238
{
239
    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
240
    struct kvm_pit_config config = {
241
        .flags = 0,
242
    };
243
    int ret;
244

    
245
    if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) {
246
        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config);
247
    } else {
248
        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
249
    }
250
    if (ret < 0) {
251
        fprintf(stderr, "Create kernel PIC irqchip failed: %s\n",
252
                strerror(ret));
253
        return ret;
254
    }
255
    switch (s->lost_tick_policy) {
256
    case LOST_TICK_DELAY:
257
        break; /* enabled by default */
258
    case LOST_TICK_DISCARD:
259
        if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) {
260
            struct kvm_reinject_control control = { .pit_reinject = 0 };
261

    
262
            ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
263
            if (ret < 0) {
264
                fprintf(stderr,
265
                        "Can't disable in-kernel PIT reinjection: %s\n",
266
                        strerror(ret));
267
                return ret;
268
            }
269
        }
270
        break;
271
    default:
272
        return -EINVAL;
273
    }
274

    
275
    memory_region_init_reservation(&pit->ioports, "kvm-pit", 4);
276

    
277
    qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
278

    
279
    qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
280

    
281
    return 0;
282
}
283

    
284
static Property kvm_pit_properties[] = {
285
    DEFINE_PROP_HEX32("iobase", KVMPITState, pit.iobase,  -1),
286
    DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
287
                               lost_tick_policy, LOST_TICK_DELAY),
288
    DEFINE_PROP_END_OF_LIST(),
289
};
290

    
291
static void kvm_pit_class_init(ObjectClass *klass, void *data)
292
{
293
    PITCommonClass *k = PIT_COMMON_CLASS(klass);
294
    DeviceClass *dc = DEVICE_CLASS(klass);
295

    
296
    k->init = kvm_pit_initfn;
297
    k->set_channel_gate = kvm_pit_set_gate;
298
    k->get_channel_info = kvm_pit_get_channel_info;
299
    k->pre_save = kvm_pit_get;
300
    k->post_load = kvm_pit_put;
301
    dc->reset = kvm_pit_reset;
302
    dc->props = kvm_pit_properties;
303
}
304

    
305
static TypeInfo kvm_pit_info = {
306
    .name          = "kvm-pit",
307
    .parent        = TYPE_PIT_COMMON,
308
    .instance_size = sizeof(KVMPITState),
309
    .class_init = kvm_pit_class_init,
310
};
311

    
312
static void kvm_pit_register(void)
313
{
314
    type_register_static(&kvm_pit_info);
315
}
316

    
317
type_init(kvm_pit_register)