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" 14c92079f4SPavel Dovgalyuk #include "replay-internal.h" 15c92079f4SPavel Dovgalyuk #include "qemu/error-report.h" 16*db725815SMarkus Armbruster #include "qemu/main-loop.h" 17c92079f4SPavel Dovgalyuk #include "sysemu/sysemu.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; 25c16861efSPavel Dovgalyuk 26c92079f4SPavel Dovgalyuk /* File for replay writing */ 276dc0f529SPavel Dovgalyuk static bool write_error; 28c92079f4SPavel Dovgalyuk FILE *replay_file; 29c92079f4SPavel Dovgalyuk 306dc0f529SPavel Dovgalyuk static void replay_write_error(void) 316dc0f529SPavel Dovgalyuk { 326dc0f529SPavel Dovgalyuk if (!write_error) { 336dc0f529SPavel Dovgalyuk error_report("replay write error"); 346dc0f529SPavel Dovgalyuk write_error = true; 356dc0f529SPavel Dovgalyuk } 366dc0f529SPavel Dovgalyuk } 376dc0f529SPavel Dovgalyuk 380b570077SPeter Maydell static void replay_read_error(void) 390b570077SPeter Maydell { 400b570077SPeter Maydell error_report("error reading the replay data"); 410b570077SPeter Maydell exit(1); 420b570077SPeter Maydell } 430b570077SPeter Maydell 44c92079f4SPavel Dovgalyuk void replay_put_byte(uint8_t byte) 45c92079f4SPavel Dovgalyuk { 46c92079f4SPavel Dovgalyuk if (replay_file) { 476dc0f529SPavel Dovgalyuk if (putc(byte, replay_file) == EOF) { 486dc0f529SPavel Dovgalyuk replay_write_error(); 496dc0f529SPavel Dovgalyuk } 50c92079f4SPavel Dovgalyuk } 51c92079f4SPavel Dovgalyuk } 52c92079f4SPavel Dovgalyuk 53c92079f4SPavel Dovgalyuk void replay_put_event(uint8_t event) 54c92079f4SPavel Dovgalyuk { 5526bc60acSPavel Dovgalyuk assert(event < EVENT_COUNT); 56c92079f4SPavel Dovgalyuk replay_put_byte(event); 57c92079f4SPavel Dovgalyuk } 58c92079f4SPavel Dovgalyuk 59c92079f4SPavel Dovgalyuk 60c92079f4SPavel Dovgalyuk void replay_put_word(uint16_t word) 61c92079f4SPavel Dovgalyuk { 62c92079f4SPavel Dovgalyuk replay_put_byte(word >> 8); 63c92079f4SPavel Dovgalyuk replay_put_byte(word); 64c92079f4SPavel Dovgalyuk } 65c92079f4SPavel Dovgalyuk 66c92079f4SPavel Dovgalyuk void replay_put_dword(uint32_t dword) 67c92079f4SPavel Dovgalyuk { 68c92079f4SPavel Dovgalyuk replay_put_word(dword >> 16); 69c92079f4SPavel Dovgalyuk replay_put_word(dword); 70c92079f4SPavel Dovgalyuk } 71c92079f4SPavel Dovgalyuk 72c92079f4SPavel Dovgalyuk void replay_put_qword(int64_t qword) 73c92079f4SPavel Dovgalyuk { 74c92079f4SPavel Dovgalyuk replay_put_dword(qword >> 32); 75c92079f4SPavel Dovgalyuk replay_put_dword(qword); 76c92079f4SPavel Dovgalyuk } 77c92079f4SPavel Dovgalyuk 78c92079f4SPavel Dovgalyuk void replay_put_array(const uint8_t *buf, size_t size) 79c92079f4SPavel Dovgalyuk { 80c92079f4SPavel Dovgalyuk if (replay_file) { 81c92079f4SPavel Dovgalyuk replay_put_dword(size); 826dc0f529SPavel Dovgalyuk if (fwrite(buf, 1, size, replay_file) != size) { 836dc0f529SPavel Dovgalyuk replay_write_error(); 846dc0f529SPavel Dovgalyuk } 85c92079f4SPavel Dovgalyuk } 86c92079f4SPavel Dovgalyuk } 87c92079f4SPavel Dovgalyuk 88c92079f4SPavel Dovgalyuk uint8_t replay_get_byte(void) 89c92079f4SPavel Dovgalyuk { 90c92079f4SPavel Dovgalyuk uint8_t byte = 0; 91c92079f4SPavel Dovgalyuk if (replay_file) { 920b570077SPeter Maydell int r = getc(replay_file); 930b570077SPeter Maydell if (r == EOF) { 940b570077SPeter Maydell replay_read_error(); 950b570077SPeter Maydell } 960b570077SPeter Maydell byte = r; 97c92079f4SPavel Dovgalyuk } 98c92079f4SPavel Dovgalyuk return byte; 99c92079f4SPavel Dovgalyuk } 100c92079f4SPavel Dovgalyuk 101c92079f4SPavel Dovgalyuk uint16_t replay_get_word(void) 102c92079f4SPavel Dovgalyuk { 103c92079f4SPavel Dovgalyuk uint16_t word = 0; 104c92079f4SPavel Dovgalyuk if (replay_file) { 105c92079f4SPavel Dovgalyuk word = replay_get_byte(); 106c92079f4SPavel Dovgalyuk word = (word << 8) + replay_get_byte(); 107c92079f4SPavel Dovgalyuk } 108c92079f4SPavel Dovgalyuk 109c92079f4SPavel Dovgalyuk return word; 110c92079f4SPavel Dovgalyuk } 111c92079f4SPavel Dovgalyuk 112c92079f4SPavel Dovgalyuk uint32_t replay_get_dword(void) 113c92079f4SPavel Dovgalyuk { 114c92079f4SPavel Dovgalyuk uint32_t dword = 0; 115c92079f4SPavel Dovgalyuk if (replay_file) { 116c92079f4SPavel Dovgalyuk dword = replay_get_word(); 117c92079f4SPavel Dovgalyuk dword = (dword << 16) + replay_get_word(); 118c92079f4SPavel Dovgalyuk } 119c92079f4SPavel Dovgalyuk 120c92079f4SPavel Dovgalyuk return dword; 121c92079f4SPavel Dovgalyuk } 122c92079f4SPavel Dovgalyuk 123c92079f4SPavel Dovgalyuk int64_t replay_get_qword(void) 124c92079f4SPavel Dovgalyuk { 125c92079f4SPavel Dovgalyuk int64_t qword = 0; 126c92079f4SPavel Dovgalyuk if (replay_file) { 127c92079f4SPavel Dovgalyuk qword = replay_get_dword(); 128c92079f4SPavel Dovgalyuk qword = (qword << 32) + replay_get_dword(); 129c92079f4SPavel Dovgalyuk } 130c92079f4SPavel Dovgalyuk 131c92079f4SPavel Dovgalyuk return qword; 132c92079f4SPavel Dovgalyuk } 133c92079f4SPavel Dovgalyuk 134c92079f4SPavel Dovgalyuk void replay_get_array(uint8_t *buf, size_t *size) 135c92079f4SPavel Dovgalyuk { 136c92079f4SPavel Dovgalyuk if (replay_file) { 137c92079f4SPavel Dovgalyuk *size = replay_get_dword(); 138c92079f4SPavel Dovgalyuk if (fread(buf, 1, *size, replay_file) != *size) { 1390b570077SPeter Maydell replay_read_error(); 140c92079f4SPavel Dovgalyuk } 141c92079f4SPavel Dovgalyuk } 142c92079f4SPavel Dovgalyuk } 143c92079f4SPavel Dovgalyuk 144c92079f4SPavel Dovgalyuk void replay_get_array_alloc(uint8_t **buf, size_t *size) 145c92079f4SPavel Dovgalyuk { 146c92079f4SPavel Dovgalyuk if (replay_file) { 147c92079f4SPavel Dovgalyuk *size = replay_get_dword(); 148c92079f4SPavel Dovgalyuk *buf = g_malloc(*size); 149c92079f4SPavel Dovgalyuk if (fread(*buf, 1, *size, replay_file) != *size) { 1500b570077SPeter Maydell replay_read_error(); 151c92079f4SPavel Dovgalyuk } 152c92079f4SPavel Dovgalyuk } 153c92079f4SPavel Dovgalyuk } 154c92079f4SPavel Dovgalyuk 155c92079f4SPavel Dovgalyuk void replay_check_error(void) 156c92079f4SPavel Dovgalyuk { 157c92079f4SPavel Dovgalyuk if (replay_file) { 158c92079f4SPavel Dovgalyuk if (feof(replay_file)) { 159c92079f4SPavel Dovgalyuk error_report("replay file is over"); 160c92079f4SPavel Dovgalyuk qemu_system_vmstop_request_prepare(); 161c92079f4SPavel Dovgalyuk qemu_system_vmstop_request(RUN_STATE_PAUSED); 162c92079f4SPavel Dovgalyuk } else if (ferror(replay_file)) { 163c92079f4SPavel Dovgalyuk error_report("replay file is over or something goes wrong"); 164c92079f4SPavel Dovgalyuk qemu_system_vmstop_request_prepare(); 165c92079f4SPavel Dovgalyuk qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR); 166c92079f4SPavel Dovgalyuk } 167c92079f4SPavel Dovgalyuk } 168c92079f4SPavel Dovgalyuk } 169c92079f4SPavel Dovgalyuk 170c92079f4SPavel Dovgalyuk void replay_fetch_data_kind(void) 171c92079f4SPavel Dovgalyuk { 172c92079f4SPavel Dovgalyuk if (replay_file) { 173f186d64dSPavel Dovgalyuk if (!replay_state.has_unread_data) { 174f186d64dSPavel Dovgalyuk replay_state.data_kind = replay_get_byte(); 175f186d64dSPavel Dovgalyuk if (replay_state.data_kind == EVENT_INSTRUCTION) { 17626bc60acSPavel Dovgalyuk replay_state.instructions_count = replay_get_dword(); 17726bc60acSPavel Dovgalyuk } 178c92079f4SPavel Dovgalyuk replay_check_error(); 179f186d64dSPavel Dovgalyuk replay_state.has_unread_data = 1; 180f186d64dSPavel Dovgalyuk if (replay_state.data_kind >= EVENT_COUNT) { 181f186d64dSPavel Dovgalyuk error_report("Replay: unknown event kind %d", 182f186d64dSPavel Dovgalyuk replay_state.data_kind); 18326bc60acSPavel Dovgalyuk exit(1); 18426bc60acSPavel Dovgalyuk } 185c92079f4SPavel Dovgalyuk } 186c92079f4SPavel Dovgalyuk } 187c92079f4SPavel Dovgalyuk } 188c92079f4SPavel Dovgalyuk 189c92079f4SPavel Dovgalyuk void replay_finish_event(void) 190c92079f4SPavel Dovgalyuk { 191f186d64dSPavel Dovgalyuk replay_state.has_unread_data = 0; 192c92079f4SPavel Dovgalyuk replay_fetch_data_kind(); 193c92079f4SPavel Dovgalyuk } 194c16861efSPavel Dovgalyuk 195180d30beSAlex Bennée static __thread bool replay_locked; 196180d30beSAlex Bennée 197c16861efSPavel Dovgalyuk void replay_mutex_init(void) 198c16861efSPavel Dovgalyuk { 199c16861efSPavel Dovgalyuk qemu_mutex_init(&lock); 200d759c951SAlex Bennée /* Hold the mutex while we start-up */ 201d759c951SAlex Bennée qemu_mutex_lock(&lock); 202d759c951SAlex Bennée replay_locked = true; 203c16861efSPavel Dovgalyuk } 204c16861efSPavel Dovgalyuk 205a36544d3SAlex Bennée bool replay_mutex_locked(void) 206180d30beSAlex Bennée { 207180d30beSAlex Bennée return replay_locked; 208180d30beSAlex Bennée } 209180d30beSAlex Bennée 210d759c951SAlex Bennée /* Ordering constraints, replay_lock must be taken before BQL */ 211c16861efSPavel Dovgalyuk void replay_mutex_lock(void) 212c16861efSPavel Dovgalyuk { 213d759c951SAlex Bennée if (replay_mode != REPLAY_MODE_NONE) { 214d759c951SAlex Bennée g_assert(!qemu_mutex_iothread_locked()); 215180d30beSAlex Bennée g_assert(!replay_mutex_locked()); 216c16861efSPavel Dovgalyuk qemu_mutex_lock(&lock); 217180d30beSAlex Bennée replay_locked = true; 218c16861efSPavel Dovgalyuk } 219d759c951SAlex Bennée } 220c16861efSPavel Dovgalyuk 221c16861efSPavel Dovgalyuk void replay_mutex_unlock(void) 222c16861efSPavel Dovgalyuk { 223d759c951SAlex Bennée if (replay_mode != REPLAY_MODE_NONE) { 224180d30beSAlex Bennée g_assert(replay_mutex_locked()); 225180d30beSAlex Bennée replay_locked = false; 226c16861efSPavel Dovgalyuk qemu_mutex_unlock(&lock); 227c16861efSPavel Dovgalyuk } 228d759c951SAlex Bennée } 22926bc60acSPavel Dovgalyuk 23074c0b816SPaolo Bonzini void replay_advance_current_step(uint64_t current_step) 23126bc60acSPavel Dovgalyuk { 23226bc60acSPavel Dovgalyuk int diff = (int)(replay_get_current_step() - replay_state.current_step); 233982263ceSAlex Bennée 234982263ceSAlex Bennée /* Time can only go forward */ 235982263ceSAlex Bennée assert(diff >= 0); 236982263ceSAlex Bennée 23726bc60acSPavel Dovgalyuk if (diff > 0) { 23826bc60acSPavel Dovgalyuk replay_put_event(EVENT_INSTRUCTION); 23926bc60acSPavel Dovgalyuk replay_put_dword(diff); 24026bc60acSPavel Dovgalyuk replay_state.current_step += diff; 24126bc60acSPavel Dovgalyuk } 24226bc60acSPavel Dovgalyuk } 24374c0b816SPaolo Bonzini 24474c0b816SPaolo Bonzini /*! Saves cached instructions. */ 24574c0b816SPaolo Bonzini void replay_save_instructions(void) 24674c0b816SPaolo Bonzini { 24774c0b816SPaolo Bonzini if (replay_file && replay_mode == REPLAY_MODE_RECORD) { 24874c0b816SPaolo Bonzini g_assert(replay_mutex_locked()); 24974c0b816SPaolo Bonzini replay_advance_current_step(replay_get_current_step()); 25074c0b816SPaolo Bonzini } 25126bc60acSPavel Dovgalyuk } 252