qemu/hw/s390x/tod.c
<<
>>
Prefs
   1/*
   2 * TOD (Time Of Day) clock
   3 *
   4 * Copyright 2018 Red Hat, Inc.
   5 * Author(s): David Hildenbrand <david@redhat.com>
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   8 * See the COPYING file in the top-level directory.
   9 */
  10
  11#include "qemu/osdep.h"
  12#include "hw/s390x/tod.h"
  13#include "qapi/error.h"
  14#include "qemu/error-report.h"
  15#include "qemu/module.h"
  16#include "sysemu/kvm.h"
  17#include "migration/register.h"
  18
  19void s390_init_tod(void)
  20{
  21    Object *obj;
  22
  23    if (kvm_enabled()) {
  24        obj = object_new(TYPE_KVM_S390_TOD);
  25    } else {
  26        obj = object_new(TYPE_QEMU_S390_TOD);
  27    }
  28    object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj, NULL);
  29    object_unref(obj);
  30
  31    qdev_init_nofail(DEVICE(obj));
  32}
  33
  34S390TODState *s390_get_todstate(void)
  35{
  36    static S390TODState *ts;
  37
  38    if (!ts) {
  39        ts = S390_TOD(object_resolve_path_type("", TYPE_S390_TOD, NULL));
  40    }
  41
  42    return ts;
  43}
  44
  45#define S390_TOD_CLOCK_VALUE_MISSING    0x00
  46#define S390_TOD_CLOCK_VALUE_PRESENT    0x01
  47
  48static void s390_tod_save(QEMUFile *f, void *opaque)
  49{
  50    S390TODState *td = opaque;
  51    S390TODClass *tdc = S390_TOD_GET_CLASS(td);
  52    Error *err = NULL;
  53    S390TOD tod;
  54
  55    tdc->get(td, &tod, &err);
  56    if (err) {
  57        warn_report_err(err);
  58        error_printf("Guest clock will not be migrated "
  59                     "which could cause the guest to hang.");
  60        qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING);
  61        return;
  62    }
  63
  64    qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT);
  65    qemu_put_byte(f, tod.high);
  66    qemu_put_be64(f, tod.low);
  67}
  68
  69static int s390_tod_load(QEMUFile *f, void *opaque, int version_id)
  70{
  71    S390TODState *td = opaque;
  72    S390TODClass *tdc = S390_TOD_GET_CLASS(td);
  73    Error *err = NULL;
  74    S390TOD tod;
  75
  76    if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) {
  77        warn_report("Guest clock was not migrated. This could "
  78                    "cause the guest to hang.");
  79        return 0;
  80    }
  81
  82    tod.high = qemu_get_byte(f);
  83    tod.low = qemu_get_be64(f);
  84
  85    tdc->set(td, &tod, &err);
  86    if (err) {
  87        error_report_err(err);
  88        return -1;
  89    }
  90    return 0;
  91}
  92
  93static SaveVMHandlers savevm_tod = {
  94    .save_state = s390_tod_save,
  95    .load_state = s390_tod_load,
  96};
  97
  98static void s390_tod_realize(DeviceState *dev, Error **errp)
  99{
 100    S390TODState *td = S390_TOD(dev);
 101
 102    /* Legacy migration interface */
 103    register_savevm_live(NULL, "todclock", 0, 1, &savevm_tod, td);
 104}
 105
 106static void s390_tod_class_init(ObjectClass *oc, void *data)
 107{
 108    DeviceClass *dc = DEVICE_CLASS(oc);
 109
 110    dc->desc = "TOD (Time Of Day) Clock";
 111    dc->realize = s390_tod_realize;
 112    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 113
 114    /* We only have one TOD clock in the system attached to the machine */
 115    dc->user_creatable = false;
 116}
 117
 118static TypeInfo s390_tod_info = {
 119    .name = TYPE_S390_TOD,
 120    .parent = TYPE_DEVICE,
 121    .instance_size = sizeof(S390TODState),
 122    .class_init = s390_tod_class_init,
 123    .class_size = sizeof(S390TODClass),
 124    .abstract = true,
 125};
 126
 127static void register_types(void)
 128{
 129    type_register_static(&s390_tod_info);
 130}
 131type_init(register_types);
 132