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 "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 "chardev/char.h" 18 19 /* Char drivers that generate qemu_chr_be_write events 20 that should be saved into the log. */ 21 static Chardev **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(Chardev *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(Chardev *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(Chardev *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 } 165