]>
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" | |
8228e353 | 17 | #include "chardev/char.h" |
33577b47 PD |
18 | |
19 | /* Char drivers that generate qemu_chr_be_write events | |
20 | that should be saved into the log. */ | |
0ec7b3e7 | 21 | static Chardev **char_drivers; |
33577b47 PD |
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 | ||
0ec7b3e7 | 31 | static int find_char_driver(Chardev *chr) |
33577b47 PD |
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 | ||
0ec7b3e7 | 42 | void replay_register_char_driver(Chardev *chr) |
33577b47 PD |
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 | ||
0ec7b3e7 | 52 | void replay_chr_be_write(Chardev *s, uint8_t *buf, int len) |
33577b47 PD |
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 | { | |
d759c951 AB |
99 | g_assert(replay_mutex_locked()); |
100 | ||
33577b47 | 101 | replay_save_instructions(); |
33577b47 PD |
102 | replay_put_event(EVENT_CHAR_WRITE); |
103 | replay_put_dword(res); | |
104 | replay_put_dword(offset); | |
33577b47 PD |
105 | } |
106 | ||
107 | void replay_char_write_event_load(int *res, int *offset) | |
108 | { | |
d759c951 AB |
109 | g_assert(replay_mutex_locked()); |
110 | ||
33577b47 | 111 | replay_account_executed_instructions(); |
33577b47 PD |
112 | if (replay_next_event_is(EVENT_CHAR_WRITE)) { |
113 | *res = replay_get_dword(); | |
114 | *offset = replay_get_dword(); | |
115 | replay_finish_event(); | |
33577b47 | 116 | } else { |
33577b47 PD |
117 | error_report("Missing character write event in the replay log"); |
118 | exit(1); | |
119 | } | |
120 | } | |
121 | ||
122 | int replay_char_read_all_load(uint8_t *buf) | |
123 | { | |
d759c951 AB |
124 | g_assert(replay_mutex_locked()); |
125 | ||
33577b47 PD |
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(); | |
33577b47 PD |
131 | res = (int)size; |
132 | assert(res >= 0); | |
133 | return res; | |
134 | } else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) { | |
135 | int res = replay_get_dword(); | |
136 | replay_finish_event(); | |
33577b47 PD |
137 | return res; |
138 | } else { | |
33577b47 PD |
139 | error_report("Missing character read all event in the replay log"); |
140 | exit(1); | |
141 | } | |
142 | } | |
143 | ||
144 | void replay_char_read_all_save_error(int res) | |
145 | { | |
d759c951 | 146 | g_assert(replay_mutex_locked()); |
33577b47 PD |
147 | assert(res < 0); |
148 | replay_save_instructions(); | |
33577b47 PD |
149 | replay_put_event(EVENT_CHAR_READ_ALL_ERROR); |
150 | replay_put_dword(res); | |
33577b47 PD |
151 | } |
152 | ||
153 | void replay_char_read_all_save_buf(uint8_t *buf, int offset) | |
154 | { | |
d759c951 | 155 | g_assert(replay_mutex_locked()); |
33577b47 | 156 | replay_save_instructions(); |
33577b47 PD |
157 | replay_put_event(EVENT_CHAR_READ_ALL); |
158 | replay_put_array(buf, offset); | |
33577b47 | 159 | } |