This patch adds deterministic replay for hardware periodic countdown timers.
Signed-off-by: Pavel Dovgalyuk <pavel.dovga...@ispras.ru> --- hw/core/ptimer.c | 7 ++++++- replay/replay-events.c | 17 +++++++++++++++++ replay/replay-internal.h | 1 + replay/replay.h | 2 ++ 4 files changed, 26 insertions(+), 1 deletions(-) diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 8437bd6..c56078d 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -9,6 +9,7 @@ #include "qemu/timer.h" #include "hw/ptimer.h" #include "qemu/host-utils.h" +#include "replay/replay.h" struct ptimer_state { @@ -27,7 +28,11 @@ struct ptimer_state static void ptimer_trigger(ptimer_state *s) { if (s->bh) { - qemu_bh_schedule(s->bh); + if (replay_mode != REPLAY_MODE_NONE) { + replay_add_ptimer_event(s->bh, replay_get_current_step()); + } else { + qemu_bh_schedule(s->bh); + } } } diff --git a/replay/replay-events.c b/replay/replay-events.c index 409c9ad..1e14cce 100755 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -13,6 +13,7 @@ #include "qemu/error-report.h" #include "replay.h" #include "replay-internal.h" +#include "block/aio.h" typedef struct Event { ReplayAsyncEventKind event_kind; @@ -35,6 +36,9 @@ static bool events_enabled = false; static void replay_run_event(Event *event) { switch (event->event_kind) { + case REPLAY_ASYNC_EVENT_PTIMER: + aio_bh_call(event->opaque); + break; default: error_report("Replay: invalid async event ID (%d) in the queue", event->event_kind); @@ -123,6 +127,11 @@ void replay_add_event(ReplayAsyncEventKind event_kind, void *opaque) replay_add_event_internal(event_kind, opaque, NULL, 0); } +void replay_add_ptimer_event(void *bh, uint64_t id) +{ + replay_add_event_internal(REPLAY_ASYNC_EVENT_PTIMER, bh, NULL, id); +} + static void replay_save_event(Event *event, int checkpoint) { if (replay_mode != REPLAY_MODE_PLAY) { @@ -133,6 +142,9 @@ static void replay_save_event(Event *event, int checkpoint) /* save event-specific data */ switch (event->event_kind) { + case REPLAY_ASYNC_EVENT_PTIMER: + replay_put_qword(event->id); + break; } } } @@ -168,6 +180,11 @@ static Event *replay_read_event(int checkpoint) /* Events that has not to be in the queue */ switch (read_event_kind) { + case REPLAY_ASYNC_EVENT_PTIMER: + if (read_id == -1) { + read_id = replay_get_qword(); + } + break; 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 f758371..4ae451f 100755 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -39,6 +39,7 @@ enum ReplayEvents { /* Asynchronous events IDs */ enum ReplayAsyncEventKind { + REPLAY_ASYNC_EVENT_PTIMER, REPLAY_ASYNC_COUNT }; diff --git a/replay/replay.h b/replay/replay.h index b6c4a8d..e97b87c 100755 --- a/replay/replay.h +++ b/replay/replay.h @@ -96,5 +96,7 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint); void replay_disable_events(void); /*! Returns true when saving events is enabled */ bool replay_events_enabled(void); +/*! Adds ptimer event to the queue */ +void replay_add_ptimer_event(void *bh, uint64_t id); #endif