qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

replay-internal.c (7051B)


      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 }