1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26#include "qemu-common.h"
27#include "qemu/cutils.h"
28#include "migration/vmstate.h"
29#include "qapi/error.h"
30#include "qemu/error-report.h"
31#include "sysemu/cpus.h"
32#include "qemu/main-loop.h"
33#include "qemu/option.h"
34#include "qemu/seqlock.h"
35#include "sysemu/replay.h"
36#include "sysemu/runstate.h"
37#include "hw/core/cpu.h"
38#include "sysemu/cpu-timers.h"
39#include "sysemu/cpu-throttle.h"
40#include "timers-state.h"
41
42
43
44static int64_t cpu_get_ticks_locked(void)
45{
46 int64_t ticks = timers_state.cpu_ticks_offset;
47 if (timers_state.cpu_ticks_enabled) {
48 ticks += cpu_get_host_ticks();
49 }
50
51 if (timers_state.cpu_ticks_prev > ticks) {
52
53 timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
54 ticks = timers_state.cpu_ticks_prev;
55 }
56
57 timers_state.cpu_ticks_prev = ticks;
58 return ticks;
59}
60
61
62
63
64
65int64_t cpu_get_ticks(void)
66{
67 int64_t ticks;
68
69 qemu_spin_lock(&timers_state.vm_clock_lock);
70 ticks = cpu_get_ticks_locked();
71 qemu_spin_unlock(&timers_state.vm_clock_lock);
72 return ticks;
73}
74
75int64_t cpu_get_clock_locked(void)
76{
77 int64_t time;
78
79 time = timers_state.cpu_clock_offset;
80 if (timers_state.cpu_ticks_enabled) {
81 time += get_clock();
82 }
83
84 return time;
85}
86
87
88
89
90
91int64_t cpu_get_clock(void)
92{
93 int64_t ti;
94 unsigned start;
95
96 do {
97 start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
98 ti = cpu_get_clock_locked();
99 } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
100
101 return ti;
102}
103
104
105
106
107
108void cpu_enable_ticks(void)
109{
110 seqlock_write_lock(&timers_state.vm_clock_seqlock,
111 &timers_state.vm_clock_lock);
112 if (!timers_state.cpu_ticks_enabled) {
113 timers_state.cpu_ticks_offset -= cpu_get_host_ticks();
114 timers_state.cpu_clock_offset -= get_clock();
115 timers_state.cpu_ticks_enabled = 1;
116 }
117 seqlock_write_unlock(&timers_state.vm_clock_seqlock,
118 &timers_state.vm_clock_lock);
119}
120
121
122
123
124
125
126void cpu_disable_ticks(void)
127{
128 seqlock_write_lock(&timers_state.vm_clock_seqlock,
129 &timers_state.vm_clock_lock);
130 if (timers_state.cpu_ticks_enabled) {
131 timers_state.cpu_ticks_offset += cpu_get_host_ticks();
132 timers_state.cpu_clock_offset = cpu_get_clock_locked();
133 timers_state.cpu_ticks_enabled = 0;
134 }
135 seqlock_write_unlock(&timers_state.vm_clock_seqlock,
136 &timers_state.vm_clock_lock);
137}
138
139static bool icount_state_needed(void *opaque)
140{
141 return icount_enabled();
142}
143
144static bool warp_timer_state_needed(void *opaque)
145{
146 TimersState *s = opaque;
147 return s->icount_warp_timer != NULL;
148}
149
150static bool adjust_timers_state_needed(void *opaque)
151{
152 TimersState *s = opaque;
153 return s->icount_rt_timer != NULL;
154}
155
156static bool icount_shift_state_needed(void *opaque)
157{
158 return icount_enabled() == 2;
159}
160
161
162
163
164static const VMStateDescription icount_vmstate_warp_timer = {
165 .name = "timer/icount/warp_timer",
166 .version_id = 1,
167 .minimum_version_id = 1,
168 .needed = warp_timer_state_needed,
169 .fields = (VMStateField[]) {
170 VMSTATE_INT64(vm_clock_warp_start, TimersState),
171 VMSTATE_TIMER_PTR(icount_warp_timer, TimersState),
172 VMSTATE_END_OF_LIST()
173 }
174};
175
176static const VMStateDescription icount_vmstate_adjust_timers = {
177 .name = "timer/icount/timers",
178 .version_id = 1,
179 .minimum_version_id = 1,
180 .needed = adjust_timers_state_needed,
181 .fields = (VMStateField[]) {
182 VMSTATE_TIMER_PTR(icount_rt_timer, TimersState),
183 VMSTATE_TIMER_PTR(icount_vm_timer, TimersState),
184 VMSTATE_END_OF_LIST()
185 }
186};
187
188static const VMStateDescription icount_vmstate_shift = {
189 .name = "timer/icount/shift",
190 .version_id = 2,
191 .minimum_version_id = 2,
192 .needed = icount_shift_state_needed,
193 .fields = (VMStateField[]) {
194 VMSTATE_INT16(icount_time_shift, TimersState),
195 VMSTATE_INT64(last_delta, TimersState),
196 VMSTATE_END_OF_LIST()
197 }
198};
199
200
201
202
203static const VMStateDescription icount_vmstate_timers = {
204 .name = "timer/icount",
205 .version_id = 1,
206 .minimum_version_id = 1,
207 .needed = icount_state_needed,
208 .fields = (VMStateField[]) {
209 VMSTATE_INT64(qemu_icount_bias, TimersState),
210 VMSTATE_INT64(qemu_icount, TimersState),
211 VMSTATE_END_OF_LIST()
212 },
213 .subsections = (const VMStateDescription * []) {
214 &icount_vmstate_warp_timer,
215 &icount_vmstate_adjust_timers,
216 &icount_vmstate_shift,
217 NULL
218 }
219};
220
221static const VMStateDescription vmstate_timers = {
222 .name = "timer",
223 .version_id = 2,
224 .minimum_version_id = 1,
225 .fields = (VMStateField[]) {
226 VMSTATE_INT64(cpu_ticks_offset, TimersState),
227 VMSTATE_UNUSED(8),
228 VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
229 VMSTATE_END_OF_LIST()
230 },
231 .subsections = (const VMStateDescription * []) {
232 &icount_vmstate_timers,
233 NULL
234 }
235};
236
237static void do_nothing(CPUState *cpu, run_on_cpu_data unused)
238{
239}
240
241void qemu_timer_notify_cb(void *opaque, QEMUClockType type)
242{
243 if (!icount_enabled() || type != QEMU_CLOCK_VIRTUAL) {
244 qemu_notify_event();
245 return;
246 }
247
248 if (qemu_in_vcpu_thread()) {
249
250
251
252
253
254 qemu_cpu_kick(current_cpu);
255 } else if (first_cpu) {
256
257
258
259
260
261
262
263
264 async_run_on_cpu(first_cpu, do_nothing, RUN_ON_CPU_NULL);
265 }
266}
267
268TimersState timers_state;
269
270
271void cpu_timers_init(void)
272{
273 seqlock_init(&timers_state.vm_clock_seqlock);
274 qemu_spin_init(&timers_state.vm_clock_lock);
275 vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
276
277 cpu_throttle_init();
278}
279