1c92079f4SPavel Dovgalyuk /*
2c92079f4SPavel Dovgalyuk * replay-internal.c
3c92079f4SPavel Dovgalyuk *
4c92079f4SPavel Dovgalyuk * Copyright (c) 2010-2015 Institute for System Programming
5c92079f4SPavel Dovgalyuk * of the Russian Academy of Sciences.
6c92079f4SPavel Dovgalyuk *
7c92079f4SPavel Dovgalyuk * This work is licensed under the terms of the GNU GPL, version 2 or later.
8c92079f4SPavel Dovgalyuk * See the COPYING file in the top-level directory.
9c92079f4SPavel Dovgalyuk *
10c92079f4SPavel Dovgalyuk */
11c92079f4SPavel Dovgalyuk
12d38ea87aSPeter Maydell #include "qemu/osdep.h"
1326bc60acSPavel Dovgalyuk #include "sysemu/replay.h"
1454d31236SMarkus Armbruster #include "sysemu/runstate.h"
15c92079f4SPavel Dovgalyuk #include "replay-internal.h"
16c92079f4SPavel Dovgalyuk #include "qemu/error-report.h"
17db725815SMarkus Armbruster #include "qemu/main-loop.h"
18c92079f4SPavel Dovgalyuk
19c16861efSPavel Dovgalyuk /* Mutex to protect reading and writing events to the log.
20f186d64dSPavel Dovgalyuk data_kind and has_unread_data are also protected
21c16861efSPavel Dovgalyuk by this mutex.
22c16861efSPavel Dovgalyuk It also protects replay events queue which stores events to be
23c16861efSPavel Dovgalyuk written or read to the log. */
24c16861efSPavel Dovgalyuk static QemuMutex lock;
25ddf63df7SPavel Dovgalyuk /* Condition and queue for fair ordering of mutex lock requests. */
26ddf63df7SPavel Dovgalyuk static QemuCond mutex_cond;
27ddf63df7SPavel Dovgalyuk static unsigned long mutex_head, mutex_tail;
28c16861efSPavel Dovgalyuk
29c92079f4SPavel Dovgalyuk /* File for replay writing */
306dc0f529SPavel Dovgalyuk static bool write_error;
31c92079f4SPavel Dovgalyuk FILE *replay_file;
32c92079f4SPavel Dovgalyuk
replay_write_error(void)336dc0f529SPavel Dovgalyuk static void replay_write_error(void)
346dc0f529SPavel Dovgalyuk {
356dc0f529SPavel Dovgalyuk if (!write_error) {
366dc0f529SPavel Dovgalyuk error_report("replay write error");
376dc0f529SPavel Dovgalyuk write_error = true;
386dc0f529SPavel Dovgalyuk }
396dc0f529SPavel Dovgalyuk }
406dc0f529SPavel Dovgalyuk
replay_read_error(void)410b570077SPeter Maydell static void replay_read_error(void)
420b570077SPeter Maydell {
430b570077SPeter Maydell error_report("error reading the replay data");
440b570077SPeter Maydell exit(1);
450b570077SPeter Maydell }
460b570077SPeter Maydell
replay_put_byte(uint8_t byte)47c92079f4SPavel Dovgalyuk void replay_put_byte(uint8_t byte)
48c92079f4SPavel Dovgalyuk {
49c92079f4SPavel Dovgalyuk if (replay_file) {
506dc0f529SPavel Dovgalyuk if (putc(byte, replay_file) == EOF) {
516dc0f529SPavel Dovgalyuk replay_write_error();
526dc0f529SPavel Dovgalyuk }
53c92079f4SPavel Dovgalyuk }
54c92079f4SPavel Dovgalyuk }
55c92079f4SPavel Dovgalyuk
replay_put_event(uint8_t event)56c92079f4SPavel Dovgalyuk void replay_put_event(uint8_t event)
57c92079f4SPavel Dovgalyuk {
5826bc60acSPavel Dovgalyuk assert(event < EVENT_COUNT);
59c92079f4SPavel Dovgalyuk replay_put_byte(event);
60c92079f4SPavel Dovgalyuk }
61c92079f4SPavel Dovgalyuk
62c92079f4SPavel Dovgalyuk
replay_put_word(uint16_t word)63c92079f4SPavel Dovgalyuk void replay_put_word(uint16_t word)
64c92079f4SPavel Dovgalyuk {
65c92079f4SPavel Dovgalyuk replay_put_byte(word >> 8);
66c92079f4SPavel Dovgalyuk replay_put_byte(word);
67c92079f4SPavel Dovgalyuk }
68c92079f4SPavel Dovgalyuk
replay_put_dword(uint32_t dword)69c92079f4SPavel Dovgalyuk void replay_put_dword(uint32_t dword)
70c92079f4SPavel Dovgalyuk {
71c92079f4SPavel Dovgalyuk replay_put_word(dword >> 16);
72c92079f4SPavel Dovgalyuk replay_put_word(dword);
73c92079f4SPavel Dovgalyuk }
74c92079f4SPavel Dovgalyuk
replay_put_qword(int64_t qword)75c92079f4SPavel Dovgalyuk void replay_put_qword(int64_t qword)
76c92079f4SPavel Dovgalyuk {
77c92079f4SPavel Dovgalyuk replay_put_dword(qword >> 32);
78c92079f4SPavel Dovgalyuk replay_put_dword(qword);
79c92079f4SPavel Dovgalyuk }
80c92079f4SPavel Dovgalyuk
replay_put_array(const uint8_t * buf,size_t size)81c92079f4SPavel Dovgalyuk void replay_put_array(const uint8_t *buf, size_t size)
82c92079f4SPavel Dovgalyuk {
83c92079f4SPavel Dovgalyuk if (replay_file) {
84c92079f4SPavel Dovgalyuk replay_put_dword(size);
856dc0f529SPavel Dovgalyuk if (fwrite(buf, 1, size, replay_file) != size) {
866dc0f529SPavel Dovgalyuk replay_write_error();
876dc0f529SPavel Dovgalyuk }
88c92079f4SPavel Dovgalyuk }
89c92079f4SPavel Dovgalyuk }
90c92079f4SPavel Dovgalyuk
replay_get_byte(void)91c92079f4SPavel Dovgalyuk uint8_t replay_get_byte(void)
92c92079f4SPavel Dovgalyuk {
93c92079f4SPavel Dovgalyuk uint8_t byte = 0;
94c92079f4SPavel Dovgalyuk if (replay_file) {
950b570077SPeter Maydell int r = getc(replay_file);
960b570077SPeter Maydell if (r == EOF) {
970b570077SPeter Maydell replay_read_error();
980b570077SPeter Maydell }
990b570077SPeter Maydell byte = r;
100c92079f4SPavel Dovgalyuk }
101c92079f4SPavel Dovgalyuk return byte;
102c92079f4SPavel Dovgalyuk }
103c92079f4SPavel Dovgalyuk
replay_get_word(void)104c92079f4SPavel Dovgalyuk uint16_t replay_get_word(void)
105c92079f4SPavel Dovgalyuk {
106c92079f4SPavel Dovgalyuk uint16_t word = 0;
107c92079f4SPavel Dovgalyuk if (replay_file) {
108c92079f4SPavel Dovgalyuk word = replay_get_byte();
109c92079f4SPavel Dovgalyuk word = (word << 8) + replay_get_byte();
110c92079f4SPavel Dovgalyuk }
111c92079f4SPavel Dovgalyuk
112c92079f4SPavel Dovgalyuk return word;
113c92079f4SPavel Dovgalyuk }
114c92079f4SPavel Dovgalyuk
replay_get_dword(void)115c92079f4SPavel Dovgalyuk uint32_t replay_get_dword(void)
116c92079f4SPavel Dovgalyuk {
117c92079f4SPavel Dovgalyuk uint32_t dword = 0;
118c92079f4SPavel Dovgalyuk if (replay_file) {
119c92079f4SPavel Dovgalyuk dword = replay_get_word();
120c92079f4SPavel Dovgalyuk dword = (dword << 16) + replay_get_word();
121c92079f4SPavel Dovgalyuk }
122c92079f4SPavel Dovgalyuk
123c92079f4SPavel Dovgalyuk return dword;
124c92079f4SPavel Dovgalyuk }
125c92079f4SPavel Dovgalyuk
replay_get_qword(void)126c92079f4SPavel Dovgalyuk int64_t replay_get_qword(void)
127c92079f4SPavel Dovgalyuk {
128c92079f4SPavel Dovgalyuk int64_t qword = 0;
129c92079f4SPavel Dovgalyuk if (replay_file) {
130c92079f4SPavel Dovgalyuk qword = replay_get_dword();
131c92079f4SPavel Dovgalyuk qword = (qword << 32) + replay_get_dword();
132c92079f4SPavel Dovgalyuk }
133c92079f4SPavel Dovgalyuk
134c92079f4SPavel Dovgalyuk return qword;
135c92079f4SPavel Dovgalyuk }
136c92079f4SPavel Dovgalyuk
replay_get_array(uint8_t * buf,size_t * size)137c92079f4SPavel Dovgalyuk void replay_get_array(uint8_t *buf, size_t *size)
138c92079f4SPavel Dovgalyuk {
139c92079f4SPavel Dovgalyuk if (replay_file) {
140c92079f4SPavel Dovgalyuk *size = replay_get_dword();
141c92079f4SPavel Dovgalyuk if (fread(buf, 1, *size, replay_file) != *size) {
1420b570077SPeter Maydell replay_read_error();
143c92079f4SPavel Dovgalyuk }
144c92079f4SPavel Dovgalyuk }
145c92079f4SPavel Dovgalyuk }
146c92079f4SPavel Dovgalyuk
replay_get_array_alloc(uint8_t ** buf,size_t * size)147c92079f4SPavel Dovgalyuk void replay_get_array_alloc(uint8_t **buf, size_t *size)
148c92079f4SPavel Dovgalyuk {
149c92079f4SPavel Dovgalyuk if (replay_file) {
150c92079f4SPavel Dovgalyuk *size = replay_get_dword();
151c92079f4SPavel Dovgalyuk *buf = g_malloc(*size);
152c92079f4SPavel Dovgalyuk if (fread(*buf, 1, *size, replay_file) != *size) {
1530b570077SPeter Maydell replay_read_error();
154c92079f4SPavel Dovgalyuk }
155c92079f4SPavel Dovgalyuk }
156c92079f4SPavel Dovgalyuk }
157c92079f4SPavel Dovgalyuk
replay_check_error(void)158c92079f4SPavel Dovgalyuk void replay_check_error(void)
159c92079f4SPavel Dovgalyuk {
160c92079f4SPavel Dovgalyuk if (replay_file) {
161c92079f4SPavel Dovgalyuk if (feof(replay_file)) {
162c92079f4SPavel Dovgalyuk error_report("replay file is over");
163c92079f4SPavel Dovgalyuk qemu_system_vmstop_request_prepare();
164c92079f4SPavel Dovgalyuk qemu_system_vmstop_request(RUN_STATE_PAUSED);
165c92079f4SPavel Dovgalyuk } else if (ferror(replay_file)) {
166c92079f4SPavel Dovgalyuk error_report("replay file is over or something goes wrong");
167c92079f4SPavel Dovgalyuk qemu_system_vmstop_request_prepare();
168c92079f4SPavel Dovgalyuk qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
169c92079f4SPavel Dovgalyuk }
170c92079f4SPavel Dovgalyuk }
171c92079f4SPavel Dovgalyuk }
172c92079f4SPavel Dovgalyuk
replay_fetch_data_kind(void)173c92079f4SPavel Dovgalyuk void replay_fetch_data_kind(void)
174c92079f4SPavel Dovgalyuk {
175c92079f4SPavel Dovgalyuk if (replay_file) {
176f186d64dSPavel Dovgalyuk if (!replay_state.has_unread_data) {
177f186d64dSPavel Dovgalyuk replay_state.data_kind = replay_get_byte();
178dcda7321SAlex Bennée replay_state.current_event++;
179f186d64dSPavel Dovgalyuk if (replay_state.data_kind == EVENT_INSTRUCTION) {
18013f26713SPavel Dovgalyuk replay_state.instruction_count = replay_get_dword();
18126bc60acSPavel Dovgalyuk }
182c92079f4SPavel Dovgalyuk replay_check_error();
1832b7a58b6SAlex Bennée replay_state.has_unread_data = true;
184f186d64dSPavel Dovgalyuk if (replay_state.data_kind >= EVENT_COUNT) {
185f186d64dSPavel Dovgalyuk error_report("Replay: unknown event kind %d",
186f186d64dSPavel Dovgalyuk replay_state.data_kind);
18726bc60acSPavel Dovgalyuk exit(1);
18826bc60acSPavel Dovgalyuk }
189c92079f4SPavel Dovgalyuk }
190c92079f4SPavel Dovgalyuk }
191c92079f4SPavel Dovgalyuk }
192c92079f4SPavel Dovgalyuk
replay_finish_event(void)193c92079f4SPavel Dovgalyuk void replay_finish_event(void)
194c92079f4SPavel Dovgalyuk {
1952b7a58b6SAlex Bennée replay_state.has_unread_data = false;
196c92079f4SPavel Dovgalyuk replay_fetch_data_kind();
197c92079f4SPavel Dovgalyuk }
198c16861efSPavel Dovgalyuk
199180d30beSAlex Bennée static __thread bool replay_locked;
200180d30beSAlex Bennée
replay_mutex_init(void)201c16861efSPavel Dovgalyuk void replay_mutex_init(void)
202c16861efSPavel Dovgalyuk {
203c16861efSPavel Dovgalyuk qemu_mutex_init(&lock);
204ddf63df7SPavel Dovgalyuk qemu_cond_init(&mutex_cond);
205d759c951SAlex Bennée /* Hold the mutex while we start-up */
206d759c951SAlex Bennée replay_locked = true;
207ddf63df7SPavel Dovgalyuk ++mutex_tail;
208c16861efSPavel Dovgalyuk }
209c16861efSPavel Dovgalyuk
replay_mutex_locked(void)210a36544d3SAlex Bennée bool replay_mutex_locked(void)
211180d30beSAlex Bennée {
212180d30beSAlex Bennée return replay_locked;
213180d30beSAlex Bennée }
214180d30beSAlex Bennée
215d759c951SAlex Bennée /* Ordering constraints, replay_lock must be taken before BQL */
replay_mutex_lock(void)216c16861efSPavel Dovgalyuk void replay_mutex_lock(void)
217c16861efSPavel Dovgalyuk {
218d759c951SAlex Bennée if (replay_mode != REPLAY_MODE_NONE) {
219ddf63df7SPavel Dovgalyuk unsigned long id;
220*195801d7SStefan Hajnoczi g_assert(!bql_locked());
221180d30beSAlex Bennée g_assert(!replay_mutex_locked());
222c16861efSPavel Dovgalyuk qemu_mutex_lock(&lock);
223ddf63df7SPavel Dovgalyuk id = mutex_tail++;
224ddf63df7SPavel Dovgalyuk while (id != mutex_head) {
225ddf63df7SPavel Dovgalyuk qemu_cond_wait(&mutex_cond, &lock);
226ddf63df7SPavel Dovgalyuk }
227180d30beSAlex Bennée replay_locked = true;
228ddf63df7SPavel Dovgalyuk qemu_mutex_unlock(&lock);
229c16861efSPavel Dovgalyuk }
230d759c951SAlex Bennée }
231c16861efSPavel Dovgalyuk
replay_mutex_unlock(void)232c16861efSPavel Dovgalyuk void replay_mutex_unlock(void)
233c16861efSPavel Dovgalyuk {
234d759c951SAlex Bennée if (replay_mode != REPLAY_MODE_NONE) {
235180d30beSAlex Bennée g_assert(replay_mutex_locked());
236ddf63df7SPavel Dovgalyuk qemu_mutex_lock(&lock);
237ddf63df7SPavel Dovgalyuk ++mutex_head;
238180d30beSAlex Bennée replay_locked = false;
239ddf63df7SPavel Dovgalyuk qemu_cond_broadcast(&mutex_cond);
240c16861efSPavel Dovgalyuk qemu_mutex_unlock(&lock);
241c16861efSPavel Dovgalyuk }
242d759c951SAlex Bennée }
24326bc60acSPavel Dovgalyuk
replay_advance_current_icount(uint64_t current_icount)24413f26713SPavel Dovgalyuk void replay_advance_current_icount(uint64_t current_icount)
24526bc60acSPavel Dovgalyuk {
24613f26713SPavel Dovgalyuk int diff = (int)(current_icount - replay_state.current_icount);
247982263ceSAlex Bennée
248982263ceSAlex Bennée /* Time can only go forward */
249982263ceSAlex Bennée assert(diff >= 0);
250982263ceSAlex Bennée
251366a85e4SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) {
25226bc60acSPavel Dovgalyuk if (diff > 0) {
25326bc60acSPavel Dovgalyuk replay_put_event(EVENT_INSTRUCTION);
25426bc60acSPavel Dovgalyuk replay_put_dword(diff);
25513f26713SPavel Dovgalyuk replay_state.current_icount += diff;
25626bc60acSPavel Dovgalyuk }
257366a85e4SPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_PLAY) {
258366a85e4SPavel Dovgalyuk if (diff > 0) {
259366a85e4SPavel Dovgalyuk replay_state.instruction_count -= diff;
260366a85e4SPavel Dovgalyuk replay_state.current_icount += diff;
261366a85e4SPavel Dovgalyuk if (replay_state.instruction_count == 0) {
262366a85e4SPavel Dovgalyuk assert(replay_state.data_kind == EVENT_INSTRUCTION);
263366a85e4SPavel Dovgalyuk replay_finish_event();
264366a85e4SPavel Dovgalyuk /* Wake up iothread. This is required because
265366a85e4SPavel Dovgalyuk timers will not expire until clock counters
266366a85e4SPavel Dovgalyuk will be read from the log. */
267366a85e4SPavel Dovgalyuk qemu_notify_event();
268366a85e4SPavel Dovgalyuk }
269366a85e4SPavel Dovgalyuk }
270366a85e4SPavel Dovgalyuk /* Execution reached the break step */
271366a85e4SPavel Dovgalyuk if (replay_break_icount == replay_state.current_icount) {
272366a85e4SPavel Dovgalyuk /* Cannot make callback directly from the vCPU thread */
273366a85e4SPavel Dovgalyuk timer_mod_ns(replay_break_timer,
274366a85e4SPavel Dovgalyuk qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
275366a85e4SPavel Dovgalyuk }
276366a85e4SPavel Dovgalyuk }
27726bc60acSPavel Dovgalyuk }
27874c0b816SPaolo Bonzini
27974c0b816SPaolo Bonzini /*! Saves cached instructions. */
replay_save_instructions(void)28074c0b816SPaolo Bonzini void replay_save_instructions(void)
28174c0b816SPaolo Bonzini {
28274c0b816SPaolo Bonzini if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
28374c0b816SPaolo Bonzini g_assert(replay_mutex_locked());
28413f26713SPavel Dovgalyuk replay_advance_current_icount(replay_get_current_icount());
28574c0b816SPaolo Bonzini }
28626bc60acSPavel Dovgalyuk }
287