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 if (replay_state.data_kind == EVENT_INSTRUCTION) { 179 replay_state.instruction_count = replay_get_dword(); 180 } 181 replay_check_error(); 182 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); 186 exit(1); 187 } 188 } 189 } 190 } 191 192 void replay_finish_event(void) 193 { 194 replay_state.has_unread_data = 0; 195 replay_fetch_data_kind(); 196 } 197 198 static __thread bool replay_locked; 199 200 void replay_mutex_init(void) 201 { 202 qemu_mutex_init(&lock); 203 qemu_cond_init(&mutex_cond); 204 /* Hold the mutex while we start-up */ 205 replay_locked = true; 206 ++mutex_tail; 207 } 208 209 bool replay_mutex_locked(void) 210 { 211 return replay_locked; 212 } 213 214 /* Ordering constraints, replay_lock must be taken before BQL */ 215 void replay_mutex_lock(void) 216 { 217 if (replay_mode != REPLAY_MODE_NONE) { 218 unsigned long id; 219 g_assert(!qemu_mutex_iothread_locked()); 220 g_assert(!replay_mutex_locked()); 221 qemu_mutex_lock(&lock); 222 id = mutex_tail++; 223 while (id != mutex_head) { 224 qemu_cond_wait(&mutex_cond, &lock); 225 } 226 replay_locked = true; 227 qemu_mutex_unlock(&lock); 228 } 229 } 230 231 void replay_mutex_unlock(void) 232 { 233 if (replay_mode != REPLAY_MODE_NONE) { 234 g_assert(replay_mutex_locked()); 235 qemu_mutex_lock(&lock); 236 ++mutex_head; 237 replay_locked = false; 238 qemu_cond_broadcast(&mutex_cond); 239 qemu_mutex_unlock(&lock); 240 } 241 } 242 243 void replay_advance_current_icount(uint64_t current_icount) 244 { 245 int diff = (int)(current_icount - replay_state.current_icount); 246 247 /* Time can only go forward */ 248 assert(diff >= 0); 249 250 if (replay_mode == REPLAY_MODE_RECORD) { 251 if (diff > 0) { 252 replay_put_event(EVENT_INSTRUCTION); 253 replay_put_dword(diff); 254 replay_state.current_icount += diff; 255 } 256 } else if (replay_mode == REPLAY_MODE_PLAY) { 257 if (diff > 0) { 258 replay_state.instruction_count -= diff; 259 replay_state.current_icount += diff; 260 if (replay_state.instruction_count == 0) { 261 assert(replay_state.data_kind == EVENT_INSTRUCTION); 262 replay_finish_event(); 263 /* Wake up iothread. This is required because 264 timers will not expire until clock counters 265 will be read from the log. */ 266 qemu_notify_event(); 267 } 268 } 269 /* Execution reached the break step */ 270 if (replay_break_icount == replay_state.current_icount) { 271 /* Cannot make callback directly from the vCPU thread */ 272 timer_mod_ns(replay_break_timer, 273 qemu_clock_get_ns(QEMU_CLOCK_REALTIME)); 274 } 275 } 276 } 277 278 /*! Saves cached instructions. */ 279 void replay_save_instructions(void) 280 { 281 if (replay_file && replay_mode == REPLAY_MODE_RECORD) { 282 g_assert(replay_mutex_locked()); 283 replay_advance_current_icount(replay_get_current_icount()); 284 } 285 } 286