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