cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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. */
     24static QemuMutex lock;
     25/* Condition and queue for fair ordering of mutex lock requests. */
     26static QemuCond mutex_cond;
     27static unsigned long mutex_head, mutex_tail;
     28
     29/* File for replay writing */
     30static bool write_error;
     31FILE *replay_file;
     32
     33static void replay_write_error(void)
     34{
     35    if (!write_error) {
     36        error_report("replay write error");
     37        write_error = true;
     38    }
     39}
     40
     41static void replay_read_error(void)
     42{
     43    error_report("error reading the replay data");
     44    exit(1);
     45}
     46
     47void 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
     56void replay_put_event(uint8_t event)
     57{
     58    assert(event < EVENT_COUNT);
     59    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);
     85        if (fwrite(buf, 1, size, replay_file) != size) {
     86            replay_write_error();
     87        }
     88    }
     89}
     90
     91uint8_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
    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) {
    142            replay_read_error();
    143        }
    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) {
    153            replay_read_error();
    154        }
    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) {
    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
    192void replay_finish_event(void)
    193{
    194    replay_state.has_unread_data = 0;
    195    replay_fetch_data_kind();
    196}
    197
    198static __thread bool replay_locked;
    199
    200void 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
    209bool replay_mutex_locked(void)
    210{
    211    return replay_locked;
    212}
    213
    214/* Ordering constraints, replay_lock must be taken before BQL */
    215void 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
    231void 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
    243void 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. */
    279void 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}