diff --git a/docs/replay.txt b/docs/replay.txt index ce97c3f72f..f4619a62a3 100644 --- a/docs/replay.txt +++ b/docs/replay.txt @@ -67,6 +67,7 @@ Modifications of qemu include: * network filter for recording and replaying the packets * block driver for making block layer deterministic * serial port input record and replay + * recording of random numbers obtained from the external sources Locking and thread synchronisation ---------------------------------- diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 8df517298c..5471bb514d 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -117,6 +117,13 @@ int64_t replay_read_clock(ReplayClockKind kind); ? replay_save_clock((clock), (value), cpu_get_icount_raw_locked()) \ : (value)) +/* Processing data from random generators */ + +/* Saves the values from the random number generator */ +void replay_save_random(int ret, void *buf, size_t len); +/* Loads the saved values for the random number generator */ +int replay_read_random(void *buf, size_t len); + /* Events */ /*! Called when qemu shutdown is requested. */ diff --git a/replay/Makefile.objs b/replay/Makefile.objs index cee6539a23..939be964a9 100644 --- a/replay/Makefile.objs +++ b/replay/Makefile.objs @@ -6,4 +6,5 @@ common-obj-y += replay-input.o common-obj-y += replay-char.o common-obj-y += replay-snapshot.o common-obj-y += replay-net.o -common-obj-y += replay-audio.o \ No newline at end of file +common-obj-y += replay-audio.o +common-obj-y += replay-random.o diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 55fca1ac6b..33ac551e78 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -34,6 +34,8 @@ enum ReplayEvents { EVENT_AUDIO_OUT, /* for audio in event */ EVENT_AUDIO_IN, + /* for random number generator */ + EVENT_RANDOM, /* for clock read/writes */ /* some of greater codes are reserved for clocks */ EVENT_CLOCK, diff --git a/replay/replay-random.c b/replay/replay-random.c new file mode 100644 index 0000000000..afc7a0fccc --- /dev/null +++ b/replay/replay-random.c @@ -0,0 +1,44 @@ +/* + * replay-random.c + * + * Copyright (c) 2010-2020 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 "qemu/osdep.h" +#include "qemu/error-report.h" +#include "sysemu/replay.h" +#include "replay-internal.h" + +void replay_save_random(int ret, void *buf, size_t len) +{ + g_assert(replay_mutex_locked()); + + replay_save_instructions(); + replay_put_event(EVENT_RANDOM); + replay_put_dword(ret); + replay_put_array(buf, len); +} + +int replay_read_random(void *buf, size_t len) +{ + int ret = 0; + g_assert(replay_mutex_locked()); + + replay_account_executed_instructions(); + if (replay_next_event_is(EVENT_RANDOM)) { + size_t buf_size = 0; + ret = replay_get_dword(); + replay_get_array(buf, &buf_size); + replay_finish_event(); + g_assert(buf_size == len); + } else { + error_report("Missing random event in the replay log"); + exit(1); + } + return ret; +} diff --git a/replay/replay.c b/replay/replay.c index 5cc25bd2f8..706c7b4f4b 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -22,7 +22,7 @@ /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe02008 +#define REPLAY_VERSION 0xe02009 /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) diff --git a/stubs/replay.c b/stubs/replay.c index 10b3925e2f..5974ec1f50 100644 --- a/stubs/replay.c +++ b/stubs/replay.c @@ -79,3 +79,12 @@ void replay_mutex_lock(void) void replay_mutex_unlock(void) { } + +void replay_save_random(int ret, void *buf, size_t len) +{ +} + +int replay_read_random(void *buf, size_t len) +{ + return 0; +} diff --git a/util/guest-random.c b/util/guest-random.c index 9453968bd7..086115bd67 100644 --- a/util/guest-random.c +++ b/util/guest-random.c @@ -14,6 +14,7 @@ #include "qapi/error.h" #include "qemu/guest-random.h" #include "crypto/random.h" +#include "sysemu/replay.h" static __thread GRand *thread_rand; @@ -44,13 +45,21 @@ static int glib_random_bytes(void *buf, size_t len) int qemu_guest_getrandom(void *buf, size_t len, Error **errp) { + int ret; + if (replay_mode == REPLAY_MODE_PLAY) { + return replay_read_random(buf, len); + } if (unlikely(deterministic)) { /* Deterministic implementation using Glib's Mersenne Twister. */ - return glib_random_bytes(buf, len); + ret = glib_random_bytes(buf, len); } else { /* Non-deterministic implementation using crypto routines. */ - return qcrypto_random_bytes(buf, len, errp); + ret = qcrypto_random_bytes(buf, len, errp); } + if (replay_mode == REPLAY_MODE_RECORD) { + replay_save_random(ret, buf, len); + } + return ret; } void qemu_guest_getrandom_nofail(void *buf, size_t len)