]>
Commit | Line | Data |
---|---|---|
33577b47 PD |
1 | /* |
2 | * replay-char.c | |
3 | * | |
4 | * Copyright (c) 2010-2016 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 | ||
33577b47 PD |
12 | #include "qemu/osdep.h" |
13 | #include "qemu/error-report.h" | |
14 | #include "sysemu/replay.h" | |
15 | #include "replay-internal.h" | |
16 | #include "sysemu/sysemu.h" | |
17 | #include "sysemu/char.h" | |
18 | ||
19 | /* Char drivers that generate qemu_chr_be_write events | |
20 | that should be saved into the log. */ | |
21 | static CharDriverState **char_drivers; | |
22 | static int drivers_count; | |
23 | ||
24 | /* Char event attributes. */ | |
25 | typedef struct CharEvent { | |
26 | int id; | |
27 | uint8_t *buf; | |
28 | size_t len; | |
29 | } CharEvent; | |
30 | ||
31 | static int find_char_driver(CharDriverState *chr) | |
32 | { | |
33 | int i = 0; | |
34 | for ( ; i < drivers_count ; ++i) { | |
35 | if (char_drivers[i] == chr) { | |
36 | return i; | |
37 | } | |
38 | } | |
39 | return -1; | |
40 | } | |
41 | ||
42 | void replay_register_char_driver(CharDriverState *chr) | |
43 | { | |
44 | if (replay_mode == REPLAY_MODE_NONE) { | |
45 | return; | |
46 | } | |
47 | char_drivers = g_realloc(char_drivers, | |
48 | sizeof(*char_drivers) * (drivers_count + 1)); | |
49 | char_drivers[drivers_count++] = chr; | |
50 | } | |
51 | ||
52 | void replay_chr_be_write(CharDriverState *s, uint8_t *buf, int len) | |
53 | { | |
54 | CharEvent *event = g_malloc0(sizeof(CharEvent)); | |
55 | ||
56 | event->id = find_char_driver(s); | |
57 | if (event->id < 0) { | |
58 | fprintf(stderr, "Replay: cannot find char driver\n"); | |
59 | exit(1); | |
60 | } | |
61 | event->buf = g_malloc(len); | |
62 | memcpy(event->buf, buf, len); | |
63 | event->len = len; | |
64 | ||
65 | replay_add_event(REPLAY_ASYNC_EVENT_CHAR_READ, event, NULL, 0); | |
66 | } | |
67 | ||
68 | void replay_event_char_read_run(void *opaque) | |
69 | { | |
70 | CharEvent *event = (CharEvent *)opaque; | |
71 | ||
72 | qemu_chr_be_write_impl(char_drivers[event->id], event->buf, | |
73 | (int)event->len); | |
74 | ||
75 | g_free(event->buf); | |
76 | g_free(event); | |
77 | } | |
78 | ||
79 | void replay_event_char_read_save(void *opaque) | |
80 | { | |
81 | CharEvent *event = (CharEvent *)opaque; | |
82 | ||
83 | replay_put_byte(event->id); | |
84 | replay_put_array(event->buf, event->len); | |
85 | } | |
86 | ||
87 | void *replay_event_char_read_load(void) | |
88 | { | |
89 | CharEvent *event = g_malloc0(sizeof(CharEvent)); | |
90 | ||
91 | event->id = replay_get_byte(); | |
92 | replay_get_array_alloc(&event->buf, &event->len); | |
93 | ||
94 | return event; | |
95 | } | |
96 | ||
97 | void replay_char_write_event_save(int res, int offset) | |
98 | { | |
99 | replay_save_instructions(); | |
100 | replay_mutex_lock(); | |
101 | replay_put_event(EVENT_CHAR_WRITE); | |
102 | replay_put_dword(res); | |
103 | replay_put_dword(offset); | |
104 | replay_mutex_unlock(); | |
105 | } | |
106 | ||
107 | void replay_char_write_event_load(int *res, int *offset) | |
108 | { | |
109 | replay_account_executed_instructions(); | |
110 | replay_mutex_lock(); | |
111 | if (replay_next_event_is(EVENT_CHAR_WRITE)) { | |
112 | *res = replay_get_dword(); | |
113 | *offset = replay_get_dword(); | |
114 | replay_finish_event(); | |
115 | replay_mutex_unlock(); | |
116 | } else { | |
117 | replay_mutex_unlock(); | |
118 | error_report("Missing character write event in the replay log"); | |
119 | exit(1); | |
120 | } | |
121 | } | |
122 | ||
123 | int replay_char_read_all_load(uint8_t *buf) | |
124 | { | |
125 | replay_mutex_lock(); | |
126 | if (replay_next_event_is(EVENT_CHAR_READ_ALL)) { | |
127 | size_t size; | |
128 | int res; | |
129 | replay_get_array(buf, &size); | |
130 | replay_finish_event(); | |
131 | replay_mutex_unlock(); | |
132 | res = (int)size; | |
133 | assert(res >= 0); | |
134 | return res; | |
135 | } else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) { | |
136 | int res = replay_get_dword(); | |
137 | replay_finish_event(); | |
138 | replay_mutex_unlock(); | |
139 | return res; | |
140 | } else { | |
141 | replay_mutex_unlock(); | |
142 | error_report("Missing character read all event in the replay log"); | |
143 | exit(1); | |
144 | } | |
145 | } | |
146 | ||
147 | void replay_char_read_all_save_error(int res) | |
148 | { | |
149 | assert(res < 0); | |
150 | replay_save_instructions(); | |
151 | replay_mutex_lock(); | |
152 | replay_put_event(EVENT_CHAR_READ_ALL_ERROR); | |
153 | replay_put_dword(res); | |
154 | replay_mutex_unlock(); | |
155 | } | |
156 | ||
157 | void replay_char_read_all_save_buf(uint8_t *buf, int offset) | |
158 | { | |
159 | replay_save_instructions(); | |
160 | replay_mutex_lock(); | |
161 | replay_put_event(EVENT_CHAR_READ_ALL); | |
162 | replay_put_array(buf, offset); | |
163 | replay_mutex_unlock(); | |
164 | } |