xref: /openbmc/qemu/replay/replay.c (revision 8bd7f71d)
1 /*
2  * replay.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-common.h"
13 #include "sysemu/replay.h"
14 #include "replay-internal.h"
15 #include "qemu/timer.h"
16 #include "qemu/main-loop.h"
17 #include "sysemu/sysemu.h"
18 
19 ReplayMode replay_mode = REPLAY_MODE_NONE;
20 
21 ReplayState replay_state;
22 
23 bool replay_next_event_is(int event)
24 {
25     bool res = false;
26 
27     /* nothing to skip - not all instructions used */
28     if (replay_state.instructions_count != 0) {
29         assert(replay_data_kind == EVENT_INSTRUCTION);
30         return event == EVENT_INSTRUCTION;
31     }
32 
33     while (true) {
34         if (event == replay_data_kind) {
35             res = true;
36         }
37         switch (replay_data_kind) {
38         case EVENT_SHUTDOWN:
39             replay_finish_event();
40             qemu_system_shutdown_request();
41             break;
42         default:
43             /* clock, time_t, checkpoint and other events */
44             return res;
45         }
46     }
47     return res;
48 }
49 
50 uint64_t replay_get_current_step(void)
51 {
52     return cpu_get_icount_raw();
53 }
54 
55 int replay_get_instructions(void)
56 {
57     int res = 0;
58     replay_mutex_lock();
59     if (replay_next_event_is(EVENT_INSTRUCTION)) {
60         res = replay_state.instructions_count;
61     }
62     replay_mutex_unlock();
63     return res;
64 }
65 
66 void replay_account_executed_instructions(void)
67 {
68     if (replay_mode == REPLAY_MODE_PLAY) {
69         replay_mutex_lock();
70         if (replay_state.instructions_count > 0) {
71             int count = (int)(replay_get_current_step()
72                               - replay_state.current_step);
73             replay_state.instructions_count -= count;
74             replay_state.current_step += count;
75             if (replay_state.instructions_count == 0) {
76                 assert(replay_data_kind == EVENT_INSTRUCTION);
77                 replay_finish_event();
78                 /* Wake up iothread. This is required because
79                    timers will not expire until clock counters
80                    will be read from the log. */
81                 qemu_notify_event();
82             }
83         }
84         replay_mutex_unlock();
85     }
86 }
87 
88 bool replay_exception(void)
89 {
90     if (replay_mode == REPLAY_MODE_RECORD) {
91         replay_save_instructions();
92         replay_mutex_lock();
93         replay_put_event(EVENT_EXCEPTION);
94         replay_mutex_unlock();
95         return true;
96     } else if (replay_mode == REPLAY_MODE_PLAY) {
97         bool res = replay_has_exception();
98         if (res) {
99             replay_mutex_lock();
100             replay_finish_event();
101             replay_mutex_unlock();
102         }
103         return res;
104     }
105 
106     return true;
107 }
108 
109 bool replay_has_exception(void)
110 {
111     bool res = false;
112     if (replay_mode == REPLAY_MODE_PLAY) {
113         replay_account_executed_instructions();
114         replay_mutex_lock();
115         res = replay_next_event_is(EVENT_EXCEPTION);
116         replay_mutex_unlock();
117     }
118 
119     return res;
120 }
121 
122 bool replay_interrupt(void)
123 {
124     if (replay_mode == REPLAY_MODE_RECORD) {
125         replay_save_instructions();
126         replay_mutex_lock();
127         replay_put_event(EVENT_INTERRUPT);
128         replay_mutex_unlock();
129         return true;
130     } else if (replay_mode == REPLAY_MODE_PLAY) {
131         bool res = replay_has_interrupt();
132         if (res) {
133             replay_mutex_lock();
134             replay_finish_event();
135             replay_mutex_unlock();
136         }
137         return res;
138     }
139 
140     return true;
141 }
142 
143 bool replay_has_interrupt(void)
144 {
145     bool res = false;
146     if (replay_mode == REPLAY_MODE_PLAY) {
147         replay_account_executed_instructions();
148         replay_mutex_lock();
149         res = replay_next_event_is(EVENT_INTERRUPT);
150         replay_mutex_unlock();
151     }
152     return res;
153 }
154 
155 void replay_shutdown_request(void)
156 {
157     if (replay_mode == REPLAY_MODE_RECORD) {
158         replay_mutex_lock();
159         replay_put_event(EVENT_SHUTDOWN);
160         replay_mutex_unlock();
161     }
162 }
163 
164 bool replay_checkpoint(ReplayCheckpoint checkpoint)
165 {
166     bool res = false;
167     assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
168     replay_save_instructions();
169 
170     if (!replay_file) {
171         return true;
172     }
173 
174     replay_mutex_lock();
175 
176     if (replay_mode == REPLAY_MODE_PLAY) {
177         if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
178             replay_finish_event();
179         } else if (replay_data_kind != EVENT_ASYNC) {
180             res = false;
181             goto out;
182         }
183         replay_read_events(checkpoint);
184         /* replay_read_events may leave some unread events.
185            Return false if not all of the events associated with
186            checkpoint were processed */
187         res = replay_data_kind != EVENT_ASYNC;
188     } else if (replay_mode == REPLAY_MODE_RECORD) {
189         replay_put_event(EVENT_CHECKPOINT + checkpoint);
190         replay_save_events(checkpoint);
191         res = true;
192     }
193 out:
194     replay_mutex_unlock();
195     return res;
196 }
197