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