xref: /openbmc/qemu/replay/replay-internal.c (revision 61b9251a)
1 /*
2  * replay-internal.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/error-report.h"
16 #include "sysemu/sysemu.h"
17 
18 unsigned int replay_data_kind = -1;
19 static unsigned int replay_has_unread_data;
20 
21 /* Mutex to protect reading and writing events to the log.
22    replay_data_kind and replay_has_unread_data are also protected
23    by this mutex.
24    It also protects replay events queue which stores events to be
25    written or read to the log. */
26 static QemuMutex lock;
27 
28 /* File for replay writing */
29 FILE *replay_file;
30 
31 void replay_put_byte(uint8_t byte)
32 {
33     if (replay_file) {
34         putc(byte, replay_file);
35     }
36 }
37 
38 void replay_put_event(uint8_t event)
39 {
40     assert(event < EVENT_COUNT);
41     replay_put_byte(event);
42 }
43 
44 
45 void replay_put_word(uint16_t word)
46 {
47     replay_put_byte(word >> 8);
48     replay_put_byte(word);
49 }
50 
51 void replay_put_dword(uint32_t dword)
52 {
53     replay_put_word(dword >> 16);
54     replay_put_word(dword);
55 }
56 
57 void replay_put_qword(int64_t qword)
58 {
59     replay_put_dword(qword >> 32);
60     replay_put_dword(qword);
61 }
62 
63 void replay_put_array(const uint8_t *buf, size_t size)
64 {
65     if (replay_file) {
66         replay_put_dword(size);
67         fwrite(buf, 1, size, replay_file);
68     }
69 }
70 
71 uint8_t replay_get_byte(void)
72 {
73     uint8_t byte = 0;
74     if (replay_file) {
75         byte = getc(replay_file);
76     }
77     return byte;
78 }
79 
80 uint16_t replay_get_word(void)
81 {
82     uint16_t word = 0;
83     if (replay_file) {
84         word = replay_get_byte();
85         word = (word << 8) + replay_get_byte();
86     }
87 
88     return word;
89 }
90 
91 uint32_t replay_get_dword(void)
92 {
93     uint32_t dword = 0;
94     if (replay_file) {
95         dword = replay_get_word();
96         dword = (dword << 16) + replay_get_word();
97     }
98 
99     return dword;
100 }
101 
102 int64_t replay_get_qword(void)
103 {
104     int64_t qword = 0;
105     if (replay_file) {
106         qword = replay_get_dword();
107         qword = (qword << 32) + replay_get_dword();
108     }
109 
110     return qword;
111 }
112 
113 void replay_get_array(uint8_t *buf, size_t *size)
114 {
115     if (replay_file) {
116         *size = replay_get_dword();
117         if (fread(buf, 1, *size, replay_file) != *size) {
118             error_report("replay read error");
119         }
120     }
121 }
122 
123 void replay_get_array_alloc(uint8_t **buf, size_t *size)
124 {
125     if (replay_file) {
126         *size = replay_get_dword();
127         *buf = g_malloc(*size);
128         if (fread(*buf, 1, *size, replay_file) != *size) {
129             error_report("replay read error");
130         }
131     }
132 }
133 
134 void replay_check_error(void)
135 {
136     if (replay_file) {
137         if (feof(replay_file)) {
138             error_report("replay file is over");
139             qemu_system_vmstop_request_prepare();
140             qemu_system_vmstop_request(RUN_STATE_PAUSED);
141         } else if (ferror(replay_file)) {
142             error_report("replay file is over or something goes wrong");
143             qemu_system_vmstop_request_prepare();
144             qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
145         }
146     }
147 }
148 
149 void replay_fetch_data_kind(void)
150 {
151     if (replay_file) {
152         if (!replay_has_unread_data) {
153             replay_data_kind = replay_get_byte();
154             if (replay_data_kind == EVENT_INSTRUCTION) {
155                 replay_state.instructions_count = replay_get_dword();
156             }
157             replay_check_error();
158             replay_has_unread_data = 1;
159             if (replay_data_kind >= EVENT_COUNT) {
160                 error_report("Replay: unknown event kind %d", replay_data_kind);
161                 exit(1);
162             }
163         }
164     }
165 }
166 
167 void replay_finish_event(void)
168 {
169     replay_has_unread_data = 0;
170     replay_fetch_data_kind();
171 }
172 
173 void replay_mutex_init(void)
174 {
175     qemu_mutex_init(&lock);
176 }
177 
178 void replay_mutex_destroy(void)
179 {
180     qemu_mutex_destroy(&lock);
181 }
182 
183 void replay_mutex_lock(void)
184 {
185     qemu_mutex_lock(&lock);
186 }
187 
188 void replay_mutex_unlock(void)
189 {
190     qemu_mutex_unlock(&lock);
191 }
192 
193 /*! Saves cached instructions. */
194 void replay_save_instructions(void)
195 {
196     if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
197         replay_mutex_lock();
198         int diff = (int)(replay_get_current_step() - replay_state.current_step);
199         if (diff > 0) {
200             replay_put_event(EVENT_INSTRUCTION);
201             replay_put_dword(diff);
202             replay_state.current_step += diff;
203         }
204         replay_mutex_unlock();
205     }
206 }
207