qemu/hw/kvm/clock.c
<<
>>
Prefs
   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
  25typedef struct KVMClockState {
  26    SysBusDevice busdev;
  27    uint64_t clock;
  28    bool clock_valid;
  29} KVMClockState;
  30
  31static void kvmclock_pre_save(void *opaque)
  32{
  33    KVMClockState *s = opaque;
  34    struct kvm_clock_data data;
  35    int ret;
  36
  37    if (s->clock_valid) {
  38        return;
  39    }
  40    ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
  41    if (ret < 0) {
  42        fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
  43        data.clock = 0;
  44    }
  45    s->clock = data.clock;
  46    /*
  47     * If the VM is stopped, declare the clock state valid to avoid re-reading
  48     * it on next vmsave (which would return a different value). Will be reset
  49     * when the VM is continued.
  50     */
  51    s->clock_valid = !runstate_is_running();
  52}
  53
  54static int kvmclock_post_load(void *opaque, int version_id)
  55{
  56    KVMClockState *s = opaque;
  57    struct kvm_clock_data data;
  58
  59    data.clock = s->clock;
  60    data.flags = 0;
  61    return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
  62}
  63
  64static void kvmclock_vm_state_change(void *opaque, int running,
  65                                     RunState state)
  66{
  67    KVMClockState *s = opaque;
  68    CPUArchState *penv = first_cpu;
  69    int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL);
  70    int ret;
  71
  72    if (running) {
  73        s->clock_valid = false;
  74
  75        if (!cap_clock_ctrl) {
  76            return;
  77        }
  78        for (penv = first_cpu; penv != NULL; penv = penv->next_cpu) {
  79            ret = kvm_vcpu_ioctl(ENV_GET_CPU(penv), KVM_KVMCLOCK_CTRL, 0);
  80            if (ret) {
  81                if (ret != -EINVAL) {
  82                    fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
  83                }
  84                return;
  85            }
  86        }
  87    }
  88}
  89
  90static int kvmclock_init(SysBusDevice *dev)
  91{
  92    KVMClockState *s = FROM_SYSBUS(KVMClockState, dev);
  93
  94    qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s);
  95    return 0;
  96}
  97
  98static const VMStateDescription kvmclock_vmsd = {
  99    .name = "kvmclock",
 100    .version_id = 1,
 101    .minimum_version_id = 1,
 102    .minimum_version_id_old = 1,
 103    .pre_save = kvmclock_pre_save,
 104    .post_load = kvmclock_post_load,
 105    .fields = (VMStateField[]) {
 106        VMSTATE_UINT64(clock, KVMClockState),
 107        VMSTATE_END_OF_LIST()
 108    }
 109};
 110
 111static void kvmclock_class_init(ObjectClass *klass, void *data)
 112{
 113    DeviceClass *dc = DEVICE_CLASS(klass);
 114    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 115
 116    k->init = kvmclock_init;
 117    dc->no_user = 1;
 118    dc->vmsd = &kvmclock_vmsd;
 119}
 120
 121static const TypeInfo kvmclock_info = {
 122    .name          = "kvmclock",
 123    .parent        = TYPE_SYS_BUS_DEVICE,
 124    .instance_size = sizeof(KVMClockState),
 125    .class_init    = kvmclock_class_init,
 126};
 127
 128/* Note: Must be called after VCPU initialization. */
 129void kvmclock_create(void)
 130{
 131    if (kvm_enabled() &&
 132        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
 133                                         (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
 134        sysbus_create_simple("kvmclock", -1, NULL);
 135    }
 136}
 137
 138static void kvmclock_register_types(void)
 139{
 140    type_register_static(&kvmclock_info);
 141}
 142
 143type_init(kvmclock_register_types)
 144