diff options
Diffstat (limited to 'replay')
-rw-r--r-- | replay/Makefile.objs | 1 | ||||
-rwxr-xr-x | replay/replay-char.c | 168 | ||||
-rw-r--r-- | replay/replay-events.c | 17 | ||||
-rw-r--r-- | replay/replay-internal.h | 18 | ||||
-rw-r--r-- | replay/replay.c | 2 |
5 files changed, 202 insertions, 4 deletions
diff --git a/replay/Makefile.objs b/replay/Makefile.objs index 232193a24b..fcb3f74d60 100644 --- a/replay/Makefile.objs +++ b/replay/Makefile.objs @@ -3,3 +3,4 @@ common-obj-y += replay-internal.o common-obj-y += replay-events.o common-obj-y += replay-time.o common-obj-y += replay-input.o +common-obj-y += replay-char.o diff --git a/replay/replay-char.c b/replay/replay-char.c new file mode 100755 index 0000000000..23b6922977 --- /dev/null +++ b/replay/replay-char.c @@ -0,0 +1,168 @@ +/* + * replay-char.c + * + * Copyright (c) 2010-2016 Institute for System Programming + * of the Russian Academy of Sciences. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "sysemu/replay.h" +#include "replay-internal.h" +#include "sysemu/sysemu.h" +#include "sysemu/char.h" + +/* Char drivers that generate qemu_chr_be_write events + that should be saved into the log. */ +static CharDriverState **char_drivers; +static int drivers_count; + +/* Char event attributes. */ +typedef struct CharEvent { + int id; + uint8_t *buf; + size_t len; +} CharEvent; + +static int find_char_driver(CharDriverState *chr) +{ + int i = 0; + for ( ; i < drivers_count ; ++i) { + if (char_drivers[i] == chr) { + return i; + } + } + return -1; +} + +void replay_register_char_driver(CharDriverState *chr) +{ + if (replay_mode == REPLAY_MODE_NONE) { + return; + } + char_drivers = g_realloc(char_drivers, + sizeof(*char_drivers) * (drivers_count + 1)); + char_drivers[drivers_count++] = chr; +} + +void replay_chr_be_write(CharDriverState *s, uint8_t *buf, int len) +{ + CharEvent *event = g_malloc0(sizeof(CharEvent)); + + event->id = find_char_driver(s); + if (event->id < 0) { + fprintf(stderr, "Replay: cannot find char driver\n"); + exit(1); + } + event->buf = g_malloc(len); + memcpy(event->buf, buf, len); + event->len = len; + + replay_add_event(REPLAY_ASYNC_EVENT_CHAR_READ, event, NULL, 0); +} + +void replay_event_char_read_run(void *opaque) +{ + CharEvent *event = (CharEvent *)opaque; + + qemu_chr_be_write_impl(char_drivers[event->id], event->buf, + (int)event->len); + + g_free(event->buf); + g_free(event); +} + +void replay_event_char_read_save(void *opaque) +{ + CharEvent *event = (CharEvent *)opaque; + + replay_put_byte(event->id); + replay_put_array(event->buf, event->len); +} + +void *replay_event_char_read_load(void) +{ + CharEvent *event = g_malloc0(sizeof(CharEvent)); + + event->id = replay_get_byte(); + replay_get_array_alloc(&event->buf, &event->len); + + return event; +} + +void replay_char_write_event_save(int res, int offset) +{ + replay_save_instructions(); + replay_mutex_lock(); + replay_put_event(EVENT_CHAR_WRITE); + replay_put_dword(res); + replay_put_dword(offset); + replay_mutex_unlock(); +} + +void replay_char_write_event_load(int *res, int *offset) +{ + replay_account_executed_instructions(); + replay_mutex_lock(); + if (replay_next_event_is(EVENT_CHAR_WRITE)) { + *res = replay_get_dword(); + *offset = replay_get_dword(); + replay_finish_event(); + replay_mutex_unlock(); + } else { + replay_mutex_unlock(); + error_report("Missing character write event in the replay log"); + exit(1); + } +} + +int replay_char_read_all_load(uint8_t *buf) +{ + replay_mutex_lock(); + if (replay_next_event_is(EVENT_CHAR_READ_ALL)) { + size_t size; + int res; + replay_get_array(buf, &size); + replay_finish_event(); + replay_mutex_unlock(); + res = (int)size; + assert(res >= 0); + return res; + } else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) { + int res = replay_get_dword(); + replay_finish_event(); + replay_mutex_unlock(); + return res; + } else { + replay_mutex_unlock(); + error_report("Missing character read all event in the replay log"); + exit(1); + } +} + +void replay_char_read_all_save_error(int res) +{ + assert(res < 0); + replay_save_instructions(); + replay_mutex_lock(); + replay_put_event(EVENT_CHAR_READ_ALL_ERROR); + replay_put_dword(res); + replay_mutex_unlock(); +} + +void replay_char_read_all_save_buf(uint8_t *buf, int offset) +{ + replay_save_instructions(); + replay_mutex_lock(); + replay_put_event(EVENT_CHAR_READ_ALL); + replay_put_array(buf, offset); + replay_mutex_unlock(); +} diff --git a/replay/replay-events.c b/replay/replay-events.c index 2628109ed8..ca940f70e7 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -48,6 +48,9 @@ static void replay_run_event(Event *event) case REPLAY_ASYNC_EVENT_INPUT_SYNC: qemu_input_event_sync_impl(); break; + case REPLAY_ASYNC_EVENT_CHAR_READ: + replay_event_char_read_run(event->opaque); + break; default: error_report("Replay: invalid async event ID (%d) in the queue", event->event_kind); @@ -102,9 +105,9 @@ void replay_clear_events(void) } /*! Adds specified async event to the queue */ -static void replay_add_event(ReplayAsyncEventKind event_kind, - void *opaque, - void *opaque2, uint64_t id) +void replay_add_event(ReplayAsyncEventKind event_kind, + void *opaque, + void *opaque2, uint64_t id) { assert(event_kind < REPLAY_ASYNC_COUNT); @@ -168,6 +171,9 @@ static void replay_save_event(Event *event, int checkpoint) break; case REPLAY_ASYNC_EVENT_INPUT_SYNC: break; + case REPLAY_ASYNC_EVENT_CHAR_READ: + replay_event_char_read_save(event->opaque); + break; default: error_report("Unknown ID %d of replay event", read_event_kind); exit(1); @@ -221,6 +227,11 @@ static Event *replay_read_event(int checkpoint) event->event_kind = read_event_kind; event->opaque = 0; return event; + case REPLAY_ASYNC_EVENT_CHAR_READ: + event = g_malloc0(sizeof(Event)); + event->event_kind = read_event_kind; + event->opaque = replay_event_char_read_load(); + return event; default: error_report("Unknown ID %d of replay event", read_event_kind); exit(1); diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 5438ebdb9c..11f9a85f3e 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -24,6 +24,11 @@ enum ReplayEvents { EVENT_ASYNC, /* for shutdown request */ EVENT_SHUTDOWN, + /* for character device write event */ + EVENT_CHAR_WRITE, + /* for character device read all event */ + EVENT_CHAR_READ_ALL, + EVENT_CHAR_READ_ALL_ERROR, /* for clock read/writes */ /* some of greater codes are reserved for clocks */ EVENT_CLOCK, @@ -43,6 +48,7 @@ enum ReplayAsyncEventKind { REPLAY_ASYNC_EVENT_BH, REPLAY_ASYNC_EVENT_INPUT, REPLAY_ASYNC_EVENT_INPUT_SYNC, + REPLAY_ASYNC_EVENT_CHAR_READ, REPLAY_ASYNC_COUNT }; @@ -124,6 +130,9 @@ bool replay_has_events(void); void replay_save_events(int checkpoint); /*! Read events from the file into the input queue */ void replay_read_events(int checkpoint); +/*! Adds specified async event to the queue */ +void replay_add_event(ReplayAsyncEventKind event_kind, void *opaque, + void *opaque2, uint64_t id); /* Input events */ @@ -136,4 +145,13 @@ void replay_add_input_event(struct InputEvent *event); /*! Adds input sync event to the queue */ void replay_add_input_sync_event(void); +/* Character devices */ + +/*! Called to run char device read event. */ +void replay_event_char_read_run(void *opaque); +/*! Writes char read event to the file. */ +void replay_event_char_read_save(void *opaque); +/*! Reads char event read from the file. */ +void *replay_event_char_read_load(void); + #endif diff --git a/replay/replay.c b/replay/replay.c index f8739c26c8..fcfde4fc93 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -20,7 +20,7 @@ /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe02002 +#define REPLAY_VERSION 0xe02003 /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) |