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