replay: record and replay random number sources
Record/replay feature of icount allows deterministic running of execution scenarios. Some CPUs and peripheral devices read random numbers from external sources making deterministic execution impossible. This patch adds recording and replaying of random read operations into guest-random module, which is used by the virtual hardware. Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> Message-Id: <157675984852.14505.15709141760677102489.stgit@pasha-Precision-3630-Tower> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
fc6b2dbac1
commit
878ec29b9c
@ -67,6 +67,7 @@ Modifications of qemu include:
|
|||||||
* network filter for recording and replaying the packets
|
* network filter for recording and replaying the packets
|
||||||
* block driver for making block layer deterministic
|
* block driver for making block layer deterministic
|
||||||
* serial port input record and replay
|
* serial port input record and replay
|
||||||
|
* recording of random numbers obtained from the external sources
|
||||||
|
|
||||||
Locking and thread synchronisation
|
Locking and thread synchronisation
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
@ -117,6 +117,13 @@ int64_t replay_read_clock(ReplayClockKind kind);
|
|||||||
? replay_save_clock((clock), (value), cpu_get_icount_raw_locked()) \
|
? replay_save_clock((clock), (value), cpu_get_icount_raw_locked()) \
|
||||||
: (value))
|
: (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 */
|
/* Events */
|
||||||
|
|
||||||
/*! Called when qemu shutdown is requested. */
|
/*! Called when qemu shutdown is requested. */
|
||||||
|
@ -6,4 +6,5 @@ common-obj-y += replay-input.o
|
|||||||
common-obj-y += replay-char.o
|
common-obj-y += replay-char.o
|
||||||
common-obj-y += replay-snapshot.o
|
common-obj-y += replay-snapshot.o
|
||||||
common-obj-y += replay-net.o
|
common-obj-y += replay-net.o
|
||||||
common-obj-y += replay-audio.o
|
common-obj-y += replay-audio.o
|
||||||
|
common-obj-y += replay-random.o
|
||||||
|
@ -34,6 +34,8 @@ enum ReplayEvents {
|
|||||||
EVENT_AUDIO_OUT,
|
EVENT_AUDIO_OUT,
|
||||||
/* for audio in event */
|
/* for audio in event */
|
||||||
EVENT_AUDIO_IN,
|
EVENT_AUDIO_IN,
|
||||||
|
/* for random number generator */
|
||||||
|
EVENT_RANDOM,
|
||||||
/* for clock read/writes */
|
/* for clock read/writes */
|
||||||
/* some of greater codes are reserved for clocks */
|
/* some of greater codes are reserved for clocks */
|
||||||
EVENT_CLOCK,
|
EVENT_CLOCK,
|
||||||
|
44
replay/replay-random.c
Normal file
44
replay/replay-random.c
Normal file
@ -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;
|
||||||
|
}
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
/* Current version of the replay mechanism.
|
/* Current version of the replay mechanism.
|
||||||
Increase it when file format changes. */
|
Increase it when file format changes. */
|
||||||
#define REPLAY_VERSION 0xe02008
|
#define REPLAY_VERSION 0xe02009
|
||||||
/* Size of replay log header */
|
/* Size of replay log header */
|
||||||
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
||||||
|
|
||||||
|
@ -79,3 +79,12 @@ void replay_mutex_lock(void)
|
|||||||
void replay_mutex_unlock(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;
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "crypto/random.h"
|
#include "crypto/random.h"
|
||||||
|
#include "sysemu/replay.h"
|
||||||
|
|
||||||
|
|
||||||
static __thread GRand *thread_rand;
|
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 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)) {
|
if (unlikely(deterministic)) {
|
||||||
/* Deterministic implementation using Glib's Mersenne Twister. */
|
/* Deterministic implementation using Glib's Mersenne Twister. */
|
||||||
return glib_random_bytes(buf, len);
|
ret = glib_random_bytes(buf, len);
|
||||||
} else {
|
} else {
|
||||||
/* Non-deterministic implementation using crypto routines. */
|
/* 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)
|
void qemu_guest_getrandom_nofail(void *buf, size_t len)
|
||||||
|
Loading…
Reference in New Issue
Block a user