133577b47SPavel Dovgalyuk /* 233577b47SPavel Dovgalyuk * replay-char.c 333577b47SPavel Dovgalyuk * 433577b47SPavel Dovgalyuk * Copyright (c) 2010-2016 Institute for System Programming 533577b47SPavel Dovgalyuk * of the Russian Academy of Sciences. 633577b47SPavel Dovgalyuk * 733577b47SPavel Dovgalyuk * This work is licensed under the terms of the GNU GPL, version 2 or later. 833577b47SPavel Dovgalyuk * See the COPYING file in the top-level directory. 933577b47SPavel Dovgalyuk * 1033577b47SPavel Dovgalyuk */ 1133577b47SPavel Dovgalyuk 1233577b47SPavel Dovgalyuk #include "qemu/osdep.h" 1333577b47SPavel Dovgalyuk #include "qemu/error-report.h" 1433577b47SPavel Dovgalyuk #include "sysemu/replay.h" 1533577b47SPavel Dovgalyuk #include "replay-internal.h" 1633577b47SPavel Dovgalyuk #include "sysemu/sysemu.h" 178228e353SMarc-André Lureau #include "chardev/char.h" 1833577b47SPavel Dovgalyuk 1933577b47SPavel Dovgalyuk /* Char drivers that generate qemu_chr_be_write events 2033577b47SPavel Dovgalyuk that should be saved into the log. */ 210ec7b3e7SMarc-André Lureau static Chardev **char_drivers; 2233577b47SPavel Dovgalyuk static int drivers_count; 2333577b47SPavel Dovgalyuk 2433577b47SPavel Dovgalyuk /* Char event attributes. */ 2533577b47SPavel Dovgalyuk typedef struct CharEvent { 2633577b47SPavel Dovgalyuk int id; 2733577b47SPavel Dovgalyuk uint8_t *buf; 2833577b47SPavel Dovgalyuk size_t len; 2933577b47SPavel Dovgalyuk } CharEvent; 3033577b47SPavel Dovgalyuk 310ec7b3e7SMarc-André Lureau static int find_char_driver(Chardev *chr) 3233577b47SPavel Dovgalyuk { 3333577b47SPavel Dovgalyuk int i = 0; 3433577b47SPavel Dovgalyuk for ( ; i < drivers_count ; ++i) { 3533577b47SPavel Dovgalyuk if (char_drivers[i] == chr) { 3633577b47SPavel Dovgalyuk return i; 3733577b47SPavel Dovgalyuk } 3833577b47SPavel Dovgalyuk } 3933577b47SPavel Dovgalyuk return -1; 4033577b47SPavel Dovgalyuk } 4133577b47SPavel Dovgalyuk 420ec7b3e7SMarc-André Lureau void replay_register_char_driver(Chardev *chr) 4333577b47SPavel Dovgalyuk { 4433577b47SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_NONE) { 4533577b47SPavel Dovgalyuk return; 4633577b47SPavel Dovgalyuk } 4733577b47SPavel Dovgalyuk char_drivers = g_realloc(char_drivers, 4833577b47SPavel Dovgalyuk sizeof(*char_drivers) * (drivers_count + 1)); 4933577b47SPavel Dovgalyuk char_drivers[drivers_count++] = chr; 5033577b47SPavel Dovgalyuk } 5133577b47SPavel Dovgalyuk 520ec7b3e7SMarc-André Lureau void replay_chr_be_write(Chardev *s, uint8_t *buf, int len) 5333577b47SPavel Dovgalyuk { 5433577b47SPavel Dovgalyuk CharEvent *event = g_malloc0(sizeof(CharEvent)); 5533577b47SPavel Dovgalyuk 5633577b47SPavel Dovgalyuk event->id = find_char_driver(s); 5733577b47SPavel Dovgalyuk if (event->id < 0) { 5833577b47SPavel Dovgalyuk fprintf(stderr, "Replay: cannot find char driver\n"); 5933577b47SPavel Dovgalyuk exit(1); 6033577b47SPavel Dovgalyuk } 6133577b47SPavel Dovgalyuk event->buf = g_malloc(len); 6233577b47SPavel Dovgalyuk memcpy(event->buf, buf, len); 6333577b47SPavel Dovgalyuk event->len = len; 6433577b47SPavel Dovgalyuk 6533577b47SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_CHAR_READ, event, NULL, 0); 6633577b47SPavel Dovgalyuk } 6733577b47SPavel Dovgalyuk 6833577b47SPavel Dovgalyuk void replay_event_char_read_run(void *opaque) 6933577b47SPavel Dovgalyuk { 7033577b47SPavel Dovgalyuk CharEvent *event = (CharEvent *)opaque; 7133577b47SPavel Dovgalyuk 7233577b47SPavel Dovgalyuk qemu_chr_be_write_impl(char_drivers[event->id], event->buf, 7333577b47SPavel Dovgalyuk (int)event->len); 7433577b47SPavel Dovgalyuk 7533577b47SPavel Dovgalyuk g_free(event->buf); 7633577b47SPavel Dovgalyuk g_free(event); 7733577b47SPavel Dovgalyuk } 7833577b47SPavel Dovgalyuk 7933577b47SPavel Dovgalyuk void replay_event_char_read_save(void *opaque) 8033577b47SPavel Dovgalyuk { 8133577b47SPavel Dovgalyuk CharEvent *event = (CharEvent *)opaque; 8233577b47SPavel Dovgalyuk 8333577b47SPavel Dovgalyuk replay_put_byte(event->id); 8433577b47SPavel Dovgalyuk replay_put_array(event->buf, event->len); 8533577b47SPavel Dovgalyuk } 8633577b47SPavel Dovgalyuk 8733577b47SPavel Dovgalyuk void *replay_event_char_read_load(void) 8833577b47SPavel Dovgalyuk { 8933577b47SPavel Dovgalyuk CharEvent *event = g_malloc0(sizeof(CharEvent)); 9033577b47SPavel Dovgalyuk 9133577b47SPavel Dovgalyuk event->id = replay_get_byte(); 9233577b47SPavel Dovgalyuk replay_get_array_alloc(&event->buf, &event->len); 9333577b47SPavel Dovgalyuk 9433577b47SPavel Dovgalyuk return event; 9533577b47SPavel Dovgalyuk } 9633577b47SPavel Dovgalyuk 9733577b47SPavel Dovgalyuk void replay_char_write_event_save(int res, int offset) 9833577b47SPavel Dovgalyuk { 99*d759c951SAlex Bennée g_assert(replay_mutex_locked()); 100*d759c951SAlex Bennée 10133577b47SPavel Dovgalyuk replay_save_instructions(); 10233577b47SPavel Dovgalyuk replay_put_event(EVENT_CHAR_WRITE); 10333577b47SPavel Dovgalyuk replay_put_dword(res); 10433577b47SPavel Dovgalyuk replay_put_dword(offset); 10533577b47SPavel Dovgalyuk } 10633577b47SPavel Dovgalyuk 10733577b47SPavel Dovgalyuk void replay_char_write_event_load(int *res, int *offset) 10833577b47SPavel Dovgalyuk { 109*d759c951SAlex Bennée g_assert(replay_mutex_locked()); 110*d759c951SAlex Bennée 11133577b47SPavel Dovgalyuk replay_account_executed_instructions(); 11233577b47SPavel Dovgalyuk if (replay_next_event_is(EVENT_CHAR_WRITE)) { 11333577b47SPavel Dovgalyuk *res = replay_get_dword(); 11433577b47SPavel Dovgalyuk *offset = replay_get_dword(); 11533577b47SPavel Dovgalyuk replay_finish_event(); 11633577b47SPavel Dovgalyuk } else { 11733577b47SPavel Dovgalyuk error_report("Missing character write event in the replay log"); 11833577b47SPavel Dovgalyuk exit(1); 11933577b47SPavel Dovgalyuk } 12033577b47SPavel Dovgalyuk } 12133577b47SPavel Dovgalyuk 12233577b47SPavel Dovgalyuk int replay_char_read_all_load(uint8_t *buf) 12333577b47SPavel Dovgalyuk { 124*d759c951SAlex Bennée g_assert(replay_mutex_locked()); 125*d759c951SAlex Bennée 12633577b47SPavel Dovgalyuk if (replay_next_event_is(EVENT_CHAR_READ_ALL)) { 12733577b47SPavel Dovgalyuk size_t size; 12833577b47SPavel Dovgalyuk int res; 12933577b47SPavel Dovgalyuk replay_get_array(buf, &size); 13033577b47SPavel Dovgalyuk replay_finish_event(); 13133577b47SPavel Dovgalyuk res = (int)size; 13233577b47SPavel Dovgalyuk assert(res >= 0); 13333577b47SPavel Dovgalyuk return res; 13433577b47SPavel Dovgalyuk } else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) { 13533577b47SPavel Dovgalyuk int res = replay_get_dword(); 13633577b47SPavel Dovgalyuk replay_finish_event(); 13733577b47SPavel Dovgalyuk return res; 13833577b47SPavel Dovgalyuk } else { 13933577b47SPavel Dovgalyuk error_report("Missing character read all event in the replay log"); 14033577b47SPavel Dovgalyuk exit(1); 14133577b47SPavel Dovgalyuk } 14233577b47SPavel Dovgalyuk } 14333577b47SPavel Dovgalyuk 14433577b47SPavel Dovgalyuk void replay_char_read_all_save_error(int res) 14533577b47SPavel Dovgalyuk { 146*d759c951SAlex Bennée g_assert(replay_mutex_locked()); 14733577b47SPavel Dovgalyuk assert(res < 0); 14833577b47SPavel Dovgalyuk replay_save_instructions(); 14933577b47SPavel Dovgalyuk replay_put_event(EVENT_CHAR_READ_ALL_ERROR); 15033577b47SPavel Dovgalyuk replay_put_dword(res); 15133577b47SPavel Dovgalyuk } 15233577b47SPavel Dovgalyuk 15333577b47SPavel Dovgalyuk void replay_char_read_all_save_buf(uint8_t *buf, int offset) 15433577b47SPavel Dovgalyuk { 155*d759c951SAlex Bennée g_assert(replay_mutex_locked()); 15633577b47SPavel Dovgalyuk replay_save_instructions(); 15733577b47SPavel Dovgalyuk replay_put_event(EVENT_CHAR_READ_ALL); 15833577b47SPavel Dovgalyuk replay_put_array(buf, offset); 15933577b47SPavel Dovgalyuk } 160