1 /* 2 * TOD (Time Of Day) clock - TCG 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 "qemu-common.h" 13 #include "qapi/error.h" 14 #include "hw/s390x/tod.h" 15 #include "qemu/timer.h" 16 #include "qemu/cutils.h" 17 #include "qemu/module.h" 18 #include "cpu.h" 19 #include "tcg/tcg_s390x.h" 20 21 static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod, 22 Error **errp) 23 { 24 *tod = td->base; 25 26 tod->low += time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 27 if (tod->low < td->base.low) { 28 tod->high++; 29 } 30 } 31 32 static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod, 33 Error **errp) 34 { 35 CPUState *cpu; 36 37 td->base = *tod; 38 39 td->base.low -= time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 40 if (td->base.low > tod->low) { 41 td->base.high--; 42 } 43 44 /* 45 * The TOD has been changed and we have to recalculate the CKC values 46 * for all CPUs. We do this asynchronously, as "SET CLOCK should be 47 * issued only while all other activity on all CPUs .. has been 48 * suspended". 49 */ 50 CPU_FOREACH(cpu) { 51 async_run_on_cpu(cpu, tcg_s390_tod_updated, RUN_ON_CPU_NULL); 52 } 53 } 54 55 static void qemu_s390_tod_class_init(ObjectClass *oc, void *data) 56 { 57 S390TODClass *tdc = S390_TOD_CLASS(oc); 58 59 tdc->get = qemu_s390_tod_get; 60 tdc->set = qemu_s390_tod_set; 61 } 62 63 static void qemu_s390_tod_init(Object *obj) 64 { 65 S390TODState *td = S390_TOD(obj); 66 struct tm tm; 67 68 qemu_get_timedate(&tm, 0); 69 td->base.high = 0; 70 td->base.low = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL); 71 if (td->base.low < TOD_UNIX_EPOCH) { 72 td->base.high += 1; 73 } 74 } 75 76 static TypeInfo qemu_s390_tod_info = { 77 .name = TYPE_QEMU_S390_TOD, 78 .parent = TYPE_S390_TOD, 79 .instance_size = sizeof(S390TODState), 80 .instance_init = qemu_s390_tod_init, 81 .class_init = qemu_s390_tod_class_init, 82 .class_size = sizeof(S390TODClass), 83 }; 84 85 static void register_types(void) 86 { 87 type_register_static(&qemu_s390_tod_info); 88 } 89 type_init(register_types); 90