blob: 2e8a3e947a5b22faaae14ca8c1c85439dafce720 [file] [log] [blame]
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +03001/*
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
Peter Maydelld38ea872016-01-29 17:50:05 +000012#include "qemu/osdep.h"
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +030013#include "sysemu/replay.h"
Markus Armbruster54d31232019-08-12 07:23:59 +020014#include "sysemu/runstate.h"
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030015#include "replay-internal.h"
16#include "qemu/error-report.h"
Markus Armbrusterdb725812019-08-12 07:23:50 +020017#include "qemu/main-loop.h"
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030018
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +030019/* Mutex to protect reading and writing events to the log.
Pavel Dovgalyukf186d642016-09-26 11:08:04 +030020 data_kind and has_unread_data are also protected
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +030021 by this mutex.
22 It also protects replay events queue which stores events to be
23 written or read to the log. */
24static QemuMutex lock;
Pavel Dovgalyukddf63df2020-04-30 12:13:49 +030025/* Condition and queue for fair ordering of mutex lock requests. */
26static QemuCond mutex_cond;
27static unsigned long mutex_head, mutex_tail;
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +030028
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030029/* File for replay writing */
Pavel Dovgalyuk6dc0f522018-02-27 12:52:59 +030030static bool write_error;
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030031FILE *replay_file;
32
Pavel Dovgalyuk6dc0f522018-02-27 12:52:59 +030033static void replay_write_error(void)
34{
35 if (!write_error) {
36 error_report("replay write error");
37 write_error = true;
38 }
39}
40
Peter Maydell0b570072018-11-06 15:33:30 +000041static void replay_read_error(void)
42{
43 error_report("error reading the replay data");
44 exit(1);
45}
46
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030047void replay_put_byte(uint8_t byte)
48{
49 if (replay_file) {
Pavel Dovgalyuk6dc0f522018-02-27 12:52:59 +030050 if (putc(byte, replay_file) == EOF) {
51 replay_write_error();
52 }
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030053 }
54}
55
56void replay_put_event(uint8_t event)
57{
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +030058 assert(event < EVENT_COUNT);
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030059 replay_put_byte(event);
60}
61
62
63void replay_put_word(uint16_t word)
64{
65 replay_put_byte(word >> 8);
66 replay_put_byte(word);
67}
68
69void replay_put_dword(uint32_t dword)
70{
71 replay_put_word(dword >> 16);
72 replay_put_word(dword);
73}
74
75void replay_put_qword(int64_t qword)
76{
77 replay_put_dword(qword >> 32);
78 replay_put_dword(qword);
79}
80
81void replay_put_array(const uint8_t *buf, size_t size)
82{
83 if (replay_file) {
84 replay_put_dword(size);
Pavel Dovgalyuk6dc0f522018-02-27 12:52:59 +030085 if (fwrite(buf, 1, size, replay_file) != size) {
86 replay_write_error();
87 }
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030088 }
89}
90
91uint8_t replay_get_byte(void)
92{
93 uint8_t byte = 0;
94 if (replay_file) {
Peter Maydell0b570072018-11-06 15:33:30 +000095 int r = getc(replay_file);
96 if (r == EOF) {
97 replay_read_error();
98 }
99 byte = r;
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300100 }
101 return byte;
102}
103
104uint16_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
115uint32_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
126int64_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
137void 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) {
Peter Maydell0b570072018-11-06 15:33:30 +0000142 replay_read_error();
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300143 }
144 }
145}
146
147void 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) {
Peter Maydell0b570072018-11-06 15:33:30 +0000153 replay_read_error();
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300154 }
155 }
156}
157
158void 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
173void replay_fetch_data_kind(void)
174{
175 if (replay_file) {
Pavel Dovgalyukf186d642016-09-26 11:08:04 +0300176 if (!replay_state.has_unread_data) {
177 replay_state.data_kind = replay_get_byte();
178 if (replay_state.data_kind == EVENT_INSTRUCTION) {
Pavel Dovgalyuk13f26712019-07-25 11:44:43 +0300179 replay_state.instruction_count = replay_get_dword();
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300180 }
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300181 replay_check_error();
Pavel Dovgalyukf186d642016-09-26 11:08:04 +0300182 replay_state.has_unread_data = 1;
183 if (replay_state.data_kind >= EVENT_COUNT) {
184 error_report("Replay: unknown event kind %d",
185 replay_state.data_kind);
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300186 exit(1);
187 }
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300188 }
189 }
190}
191
192void replay_finish_event(void)
193{
Pavel Dovgalyukf186d642016-09-26 11:08:04 +0300194 replay_state.has_unread_data = 0;
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300195 replay_fetch_data_kind();
196}
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300197
Alex Bennée180d30b2018-02-27 12:52:37 +0300198static __thread bool replay_locked;
199
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300200void replay_mutex_init(void)
201{
202 qemu_mutex_init(&lock);
Pavel Dovgalyukddf63df2020-04-30 12:13:49 +0300203 qemu_cond_init(&mutex_cond);
Alex Bennéed759c952018-02-27 12:52:48 +0300204 /* Hold the mutex while we start-up */
Alex Bennéed759c952018-02-27 12:52:48 +0300205 replay_locked = true;
Pavel Dovgalyukddf63df2020-04-30 12:13:49 +0300206 ++mutex_tail;
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300207}
208
Alex Bennéea36544d2018-02-27 12:52:42 +0300209bool replay_mutex_locked(void)
Alex Bennée180d30b2018-02-27 12:52:37 +0300210{
211 return replay_locked;
212}
213
Alex Bennéed759c952018-02-27 12:52:48 +0300214/* Ordering constraints, replay_lock must be taken before BQL */
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300215void replay_mutex_lock(void)
216{
Alex Bennéed759c952018-02-27 12:52:48 +0300217 if (replay_mode != REPLAY_MODE_NONE) {
Pavel Dovgalyukddf63df2020-04-30 12:13:49 +0300218 unsigned long id;
Alex Bennéed759c952018-02-27 12:52:48 +0300219 g_assert(!qemu_mutex_iothread_locked());
220 g_assert(!replay_mutex_locked());
221 qemu_mutex_lock(&lock);
Pavel Dovgalyukddf63df2020-04-30 12:13:49 +0300222 id = mutex_tail++;
223 while (id != mutex_head) {
224 qemu_cond_wait(&mutex_cond, &lock);
225 }
Alex Bennéed759c952018-02-27 12:52:48 +0300226 replay_locked = true;
Pavel Dovgalyukddf63df2020-04-30 12:13:49 +0300227 qemu_mutex_unlock(&lock);
Alex Bennéed759c952018-02-27 12:52:48 +0300228 }
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300229}
230
231void replay_mutex_unlock(void)
232{
Alex Bennéed759c952018-02-27 12:52:48 +0300233 if (replay_mode != REPLAY_MODE_NONE) {
234 g_assert(replay_mutex_locked());
Pavel Dovgalyukddf63df2020-04-30 12:13:49 +0300235 qemu_mutex_lock(&lock);
236 ++mutex_head;
Alex Bennéed759c952018-02-27 12:52:48 +0300237 replay_locked = false;
Pavel Dovgalyukddf63df2020-04-30 12:13:49 +0300238 qemu_cond_broadcast(&mutex_cond);
Alex Bennéed759c952018-02-27 12:52:48 +0300239 qemu_mutex_unlock(&lock);
240 }
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300241}
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300242
Pavel Dovgalyuk13f26712019-07-25 11:44:43 +0300243void replay_advance_current_icount(uint64_t current_icount)
Paolo Bonzini74c0b812018-10-08 13:24:14 +0200244{
Pavel Dovgalyuk13f26712019-07-25 11:44:43 +0300245 int diff = (int)(current_icount - replay_state.current_icount);
Paolo Bonzini74c0b812018-10-08 13:24:14 +0200246
247 /* Time can only go forward */
248 assert(diff >= 0);
249
250 if (diff > 0) {
251 replay_put_event(EVENT_INSTRUCTION);
252 replay_put_dword(diff);
Pavel Dovgalyuk13f26712019-07-25 11:44:43 +0300253 replay_state.current_icount += diff;
Paolo Bonzini74c0b812018-10-08 13:24:14 +0200254 }
255}
256
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300257/*! Saves cached instructions. */
258void replay_save_instructions(void)
259{
260 if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
Alex Bennéed759c952018-02-27 12:52:48 +0300261 g_assert(replay_mutex_locked());
Pavel Dovgalyuk13f26712019-07-25 11:44:43 +0300262 replay_advance_current_icount(replay_get_current_icount());
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300263 }
264}