1 /* 2 * TOD (Time Of Day) clock - KVM implementation 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 "qapi/error.h" 13 #include "qemu/module.h" 14 #include "sysemu/runstate.h" 15 #include "hw/s390x/tod.h" 16 #include "hw/s390x/pv.h" 17 #include "kvm/kvm_s390x.h" 18 19 static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp) 20 { 21 int r; 22 23 r = kvm_s390_get_clock_ext(&tod->high, &tod->low); 24 if (r == -ENXIO) { 25 r = kvm_s390_get_clock(&tod->high, &tod->low); 26 } 27 if (r) { 28 error_setg(errp, "Unable to get KVM guest TOD clock: %s", 29 strerror(-r)); 30 } 31 } 32 33 static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp) 34 { 35 if (td->stopped) { 36 *tod = td->base; 37 return; 38 } 39 40 kvm_s390_get_tod_raw(tod, errp); 41 } 42 43 static void kvm_s390_set_tod_raw(const S390TOD *tod, Error **errp) 44 { 45 int r; 46 47 r = kvm_s390_set_clock_ext(tod->high, tod->low); 48 if (r == -ENXIO) { 49 r = kvm_s390_set_clock(tod->high, tod->low); 50 } 51 if (r) { 52 error_setg(errp, "Unable to set KVM guest TOD clock: %s", 53 strerror(-r)); 54 } 55 } 56 57 static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp) 58 { 59 Error *local_err = NULL; 60 61 /* 62 * Somebody (e.g. migration) set the TOD. We'll store it into KVM to 63 * properly detect errors now but take a look at the runstate to decide 64 * whether really to keep the tod running. E.g. during migration, this 65 * is the point where we want to stop the initially running TOD to fire 66 * it back up when actually starting the migrated guest. 67 */ 68 kvm_s390_set_tod_raw(tod, &local_err); 69 if (local_err) { 70 error_propagate(errp, local_err); 71 return; 72 } 73 74 if (runstate_is_running()) { 75 td->stopped = false; 76 } else { 77 td->stopped = true; 78 td->base = *tod; 79 } 80 } 81 82 static void kvm_s390_tod_vm_state_change(void *opaque, bool running, 83 RunState state) 84 { 85 S390TODState *td = opaque; 86 Error *local_err = NULL; 87 88 /* 89 * Under PV, the clock is under ultravisor control, hence we cannot restore 90 * it on resume. 91 */ 92 if (s390_is_pv()) { 93 return; 94 } 95 96 if (running && td->stopped) { 97 /* Set the old TOD when running the VM - start the TOD clock. */ 98 kvm_s390_set_tod_raw(&td->base, &local_err); 99 if (local_err) { 100 warn_report_err(local_err); 101 } 102 /* Treat errors like the TOD was running all the time. */ 103 td->stopped = false; 104 } else if (!running && !td->stopped) { 105 /* Store the TOD when stopping the VM - stop the TOD clock. */ 106 kvm_s390_get_tod_raw(&td->base, &local_err); 107 if (local_err) { 108 /* Keep the TOD running in case we could not back it up. */ 109 warn_report_err(local_err); 110 } else { 111 td->stopped = true; 112 } 113 } 114 } 115 116 static void kvm_s390_tod_realize(DeviceState *dev, Error **errp) 117 { 118 S390TODState *td = S390_TOD(dev); 119 S390TODClass *tdc = S390_TOD_GET_CLASS(td); 120 Error *local_err = NULL; 121 122 tdc->parent_realize(dev, &local_err); 123 if (local_err) { 124 error_propagate(errp, local_err); 125 return; 126 } 127 128 /* 129 * We need to know when the VM gets started/stopped to start/stop the TOD. 130 * As we can never have more than one TOD instance (and that will never be 131 * removed), registering here and never unregistering is good enough. 132 */ 133 qemu_add_vm_change_state_handler(kvm_s390_tod_vm_state_change, td); 134 } 135 136 static void kvm_s390_tod_class_init(ObjectClass *oc, void *data) 137 { 138 S390TODClass *tdc = S390_TOD_CLASS(oc); 139 140 device_class_set_parent_realize(DEVICE_CLASS(oc), kvm_s390_tod_realize, 141 &tdc->parent_realize); 142 tdc->get = kvm_s390_tod_get; 143 tdc->set = kvm_s390_tod_set; 144 } 145 146 static void kvm_s390_tod_init(Object *obj) 147 { 148 S390TODState *td = S390_TOD(obj); 149 150 /* 151 * The TOD is initially running (value stored in KVM). Avoid needless 152 * loading/storing of the TOD when starting a simple VM, so let it 153 * run although the (never started) VM is stopped. For migration, we 154 * will properly set the TOD later. 155 */ 156 td->stopped = false; 157 } 158 159 static const TypeInfo kvm_s390_tod_info = { 160 .name = TYPE_KVM_S390_TOD, 161 .parent = TYPE_S390_TOD, 162 .instance_size = sizeof(S390TODState), 163 .instance_init = kvm_s390_tod_init, 164 .class_init = kvm_s390_tod_class_init, 165 .class_size = sizeof(S390TODClass), 166 }; 167 168 static void register_types(void) 169 { 170 type_register_static(&kvm_s390_tod_info); 171 } 172 type_init(register_types); 173