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