]> git.proxmox.com Git - mirror_qemu.git/blob - replay/replay-internal.c
ci: Disable migration compatibility tests for aarch64
[mirror_qemu.git] / replay / replay-internal.c
1 /*
2 * replay-internal.c
3 *
4 * Copyright (c) 2010-2015 Institute for System Programming
5 * of the Russian Academy of Sciences.
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
12 #include "qemu/osdep.h"
13 #include "sysemu/replay.h"
14 #include "sysemu/runstate.h"
15 #include "replay-internal.h"
16 #include "qemu/error-report.h"
17 #include "qemu/main-loop.h"
18
19 /* Mutex to protect reading and writing events to the log.
20 data_kind and has_unread_data are also protected
21 by this mutex.
22 It also protects replay events queue which stores events to be
23 written or read to the log. */
24 static QemuMutex lock;
25 /* Condition and queue for fair ordering of mutex lock requests. */
26 static QemuCond mutex_cond;
27 static unsigned long mutex_head, mutex_tail;
28
29 /* File for replay writing */
30 static bool write_error;
31 FILE *replay_file;
32
33 static void replay_write_error(void)
34 {
35 if (!write_error) {
36 error_report("replay write error");
37 write_error = true;
38 }
39 }
40
41 static void replay_read_error(void)
42 {
43 error_report("error reading the replay data");
44 exit(1);
45 }
46
47 void replay_put_byte(uint8_t byte)
48 {
49 if (replay_file) {
50 if (putc(byte, replay_file) == EOF) {
51 replay_write_error();
52 }
53 }
54 }
55
56 void replay_put_event(uint8_t event)
57 {
58 assert(event < EVENT_COUNT);
59 replay_put_byte(event);
60 }
61
62
63 void replay_put_word(uint16_t word)
64 {
65 replay_put_byte(word >> 8);
66 replay_put_byte(word);
67 }
68
69 void replay_put_dword(uint32_t dword)
70 {
71 replay_put_word(dword >> 16);
72 replay_put_word(dword);
73 }
74
75 void replay_put_qword(int64_t qword)
76 {
77 replay_put_dword(qword >> 32);
78 replay_put_dword(qword);
79 }
80
81 void replay_put_array(const uint8_t *buf, size_t size)
82 {
83 if (replay_file) {
84 replay_put_dword(size);
85 if (fwrite(buf, 1, size, replay_file) != size) {
86 replay_write_error();
87 }
88 }
89 }
90
91 uint8_t replay_get_byte(void)
92 {
93 uint8_t byte = 0;
94 if (replay_file) {
95 int r = getc(replay_file);
96 if (r == EOF) {
97 replay_read_error();
98 }
99 byte = r;
100 }
101 return byte;
102 }
103
104 uint16_t replay_get_word(void)
105 {
106 uint16_t word = 0;
107 if (replay_file) {
108 word = replay_get_byte();
109 word = (word << 8) + replay_get_byte();
110 }
111
112 return word;
113 }
114
115 uint32_t replay_get_dword(void)
116 {
117 uint32_t dword = 0;
118 if (replay_file) {
119 dword = replay_get_word();
120 dword = (dword << 16) + replay_get_word();
121 }
122
123 return dword;
124 }
125
126 int64_t replay_get_qword(void)
127 {
128 int64_t qword = 0;
129 if (replay_file) {
130 qword = replay_get_dword();
131 qword = (qword << 32) + replay_get_dword();
132 }
133
134 return qword;
135 }
136
137 void replay_get_array(uint8_t *buf, size_t *size)
138 {
139 if (replay_file) {
140 *size = replay_get_dword();
141 if (fread(buf, 1, *size, replay_file) != *size) {
142 replay_read_error();
143 }
144 }
145 }
146
147 void replay_get_array_alloc(uint8_t **buf, size_t *size)
148 {
149 if (replay_file) {
150 *size = replay_get_dword();
151 *buf = g_malloc(*size);
152 if (fread(*buf, 1, *size, replay_file) != *size) {
153 replay_read_error();
154 }
155 }
156 }
157
158 void replay_check_error(void)
159 {
160 if (replay_file) {
161 if (feof(replay_file)) {
162 error_report("replay file is over");
163 qemu_system_vmstop_request_prepare();
164 qemu_system_vmstop_request(RUN_STATE_PAUSED);
165 } else if (ferror(replay_file)) {
166 error_report("replay file is over or something goes wrong");
167 qemu_system_vmstop_request_prepare();
168 qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
169 }
170 }
171 }
172
173 void replay_fetch_data_kind(void)
174 {
175 if (replay_file) {
176 if (!replay_state.has_unread_data) {
177 replay_state.data_kind = replay_get_byte();
178 replay_state.current_event++;
179 if (replay_state.data_kind == EVENT_INSTRUCTION) {
180 replay_state.instruction_count = replay_get_dword();
181 }
182 replay_check_error();
183 replay_state.has_unread_data = true;
184 if (replay_state.data_kind >= EVENT_COUNT) {
185 error_report("Replay: unknown event kind %d",
186 replay_state.data_kind);
187 exit(1);
188 }
189 }
190 }
191 }
192
193 void replay_finish_event(void)
194 {
195 replay_state.has_unread_data = false;
196 replay_fetch_data_kind();
197 }
198
199 static __thread bool replay_locked;
200
201 void replay_mutex_init(void)
202 {
203 qemu_mutex_init(&lock);
204 qemu_cond_init(&mutex_cond);
205 /* Hold the mutex while we start-up */
206 replay_locked = true;
207 ++mutex_tail;
208 }
209
210 bool replay_mutex_locked(void)
211 {
212 return replay_locked;
213 }
214
215 /* Ordering constraints, replay_lock must be taken before BQL */
216 void replay_mutex_lock(void)
217 {
218 if (replay_mode != REPLAY_MODE_NONE) {
219 unsigned long id;
220 g_assert(!bql_locked());
221 g_assert(!replay_mutex_locked());
222 qemu_mutex_lock(&lock);
223 id = mutex_tail++;
224 while (id != mutex_head) {
225 qemu_cond_wait(&mutex_cond, &lock);
226 }
227 replay_locked = true;
228 qemu_mutex_unlock(&lock);
229 }
230 }
231
232 void replay_mutex_unlock(void)
233 {
234 if (replay_mode != REPLAY_MODE_NONE) {
235 g_assert(replay_mutex_locked());
236 qemu_mutex_lock(&lock);
237 ++mutex_head;
238 replay_locked = false;
239 qemu_cond_broadcast(&mutex_cond);
240 qemu_mutex_unlock(&lock);
241 }
242 }
243
244 void replay_advance_current_icount(uint64_t current_icount)
245 {
246 int diff = (int)(current_icount - replay_state.current_icount);
247
248 /* Time can only go forward */
249 assert(diff >= 0);
250
251 if (replay_mode == REPLAY_MODE_RECORD) {
252 if (diff > 0) {
253 replay_put_event(EVENT_INSTRUCTION);
254 replay_put_dword(diff);
255 replay_state.current_icount += diff;
256 }
257 } else if (replay_mode == REPLAY_MODE_PLAY) {
258 if (diff > 0) {
259 replay_state.instruction_count -= diff;
260 replay_state.current_icount += diff;
261 if (replay_state.instruction_count == 0) {
262 assert(replay_state.data_kind == EVENT_INSTRUCTION);
263 replay_finish_event();
264 /* Wake up iothread. This is required because
265 timers will not expire until clock counters
266 will be read from the log. */
267 qemu_notify_event();
268 }
269 }
270 /* Execution reached the break step */
271 if (replay_break_icount == replay_state.current_icount) {
272 /* Cannot make callback directly from the vCPU thread */
273 timer_mod_ns(replay_break_timer,
274 qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
275 }
276 }
277 }
278
279 /*! Saves cached instructions. */
280 void replay_save_instructions(void)
281 {
282 if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
283 g_assert(replay_mutex_locked());
284 replay_advance_current_icount(replay_get_current_icount());
285 }
286 }