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