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" 168228e353SMarc-André Lureau #include "chardev/char.h" 1733577b47SPavel Dovgalyuk 1833577b47SPavel Dovgalyuk /* Char drivers that generate qemu_chr_be_write events 1933577b47SPavel Dovgalyuk that should be saved into the log. */ 200ec7b3e7SMarc-André Lureau static Chardev **char_drivers; 2133577b47SPavel Dovgalyuk static int drivers_count; 2233577b47SPavel Dovgalyuk 2333577b47SPavel Dovgalyuk /* Char event attributes. */ 2433577b47SPavel Dovgalyuk typedef struct CharEvent { 2533577b47SPavel Dovgalyuk int id; 2633577b47SPavel Dovgalyuk uint8_t *buf; 2733577b47SPavel Dovgalyuk size_t len; 2833577b47SPavel Dovgalyuk } CharEvent; 2933577b47SPavel Dovgalyuk 300ec7b3e7SMarc-André Lureau static int find_char_driver(Chardev *chr) 3133577b47SPavel Dovgalyuk { 3233577b47SPavel Dovgalyuk int i = 0; 3333577b47SPavel Dovgalyuk for ( ; i < drivers_count ; ++i) { 3433577b47SPavel Dovgalyuk if (char_drivers[i] == chr) { 3533577b47SPavel Dovgalyuk return i; 3633577b47SPavel Dovgalyuk } 3733577b47SPavel Dovgalyuk } 3833577b47SPavel Dovgalyuk return -1; 3933577b47SPavel Dovgalyuk } 4033577b47SPavel Dovgalyuk 410ec7b3e7SMarc-André Lureau void replay_register_char_driver(Chardev *chr) 4233577b47SPavel Dovgalyuk { 4333577b47SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_NONE) { 4433577b47SPavel Dovgalyuk return; 4533577b47SPavel Dovgalyuk } 4633577b47SPavel Dovgalyuk char_drivers = g_realloc(char_drivers, 4733577b47SPavel Dovgalyuk sizeof(*char_drivers) * (drivers_count + 1)); 4833577b47SPavel Dovgalyuk char_drivers[drivers_count++] = chr; 4933577b47SPavel Dovgalyuk } 5033577b47SPavel Dovgalyuk 510ec7b3e7SMarc-André Lureau void replay_chr_be_write(Chardev *s, uint8_t *buf, int len) 5233577b47SPavel Dovgalyuk { 53*b21e2380SMarkus Armbruster CharEvent *event = g_new0(CharEvent, 1); 5433577b47SPavel Dovgalyuk 5533577b47SPavel Dovgalyuk event->id = find_char_driver(s); 5633577b47SPavel Dovgalyuk if (event->id < 0) { 5733577b47SPavel Dovgalyuk fprintf(stderr, "Replay: cannot find char driver\n"); 5833577b47SPavel Dovgalyuk exit(1); 5933577b47SPavel Dovgalyuk } 6033577b47SPavel Dovgalyuk event->buf = g_malloc(len); 6133577b47SPavel Dovgalyuk memcpy(event->buf, buf, len); 6233577b47SPavel Dovgalyuk event->len = len; 6333577b47SPavel Dovgalyuk 6433577b47SPavel Dovgalyuk replay_add_event(REPLAY_ASYNC_EVENT_CHAR_READ, event, NULL, 0); 6533577b47SPavel Dovgalyuk } 6633577b47SPavel Dovgalyuk 6733577b47SPavel Dovgalyuk void replay_event_char_read_run(void *opaque) 6833577b47SPavel Dovgalyuk { 6933577b47SPavel Dovgalyuk CharEvent *event = (CharEvent *)opaque; 7033577b47SPavel Dovgalyuk 7133577b47SPavel Dovgalyuk qemu_chr_be_write_impl(char_drivers[event->id], event->buf, 7233577b47SPavel Dovgalyuk (int)event->len); 7333577b47SPavel Dovgalyuk 7433577b47SPavel Dovgalyuk g_free(event->buf); 7533577b47SPavel Dovgalyuk g_free(event); 7633577b47SPavel Dovgalyuk } 7733577b47SPavel Dovgalyuk 7833577b47SPavel Dovgalyuk void replay_event_char_read_save(void *opaque) 7933577b47SPavel Dovgalyuk { 8033577b47SPavel Dovgalyuk CharEvent *event = (CharEvent *)opaque; 8133577b47SPavel Dovgalyuk 8233577b47SPavel Dovgalyuk replay_put_byte(event->id); 8333577b47SPavel Dovgalyuk replay_put_array(event->buf, event->len); 8433577b47SPavel Dovgalyuk } 8533577b47SPavel Dovgalyuk 8633577b47SPavel Dovgalyuk void *replay_event_char_read_load(void) 8733577b47SPavel Dovgalyuk { 88*b21e2380SMarkus Armbruster CharEvent *event = g_new0(CharEvent, 1); 8933577b47SPavel Dovgalyuk 9033577b47SPavel Dovgalyuk event->id = replay_get_byte(); 9133577b47SPavel Dovgalyuk replay_get_array_alloc(&event->buf, &event->len); 9233577b47SPavel Dovgalyuk 9333577b47SPavel Dovgalyuk return event; 9433577b47SPavel Dovgalyuk } 9533577b47SPavel Dovgalyuk 9633577b47SPavel Dovgalyuk void replay_char_write_event_save(int res, int offset) 9733577b47SPavel Dovgalyuk { 98d759c951SAlex Bennée g_assert(replay_mutex_locked()); 99d759c951SAlex Bennée 10033577b47SPavel Dovgalyuk replay_save_instructions(); 10133577b47SPavel Dovgalyuk replay_put_event(EVENT_CHAR_WRITE); 10233577b47SPavel Dovgalyuk replay_put_dword(res); 10333577b47SPavel Dovgalyuk replay_put_dword(offset); 10433577b47SPavel Dovgalyuk } 10533577b47SPavel Dovgalyuk 10633577b47SPavel Dovgalyuk void replay_char_write_event_load(int *res, int *offset) 10733577b47SPavel Dovgalyuk { 108d759c951SAlex Bennée g_assert(replay_mutex_locked()); 109d759c951SAlex Bennée 11033577b47SPavel Dovgalyuk replay_account_executed_instructions(); 11133577b47SPavel Dovgalyuk if (replay_next_event_is(EVENT_CHAR_WRITE)) { 11233577b47SPavel Dovgalyuk *res = replay_get_dword(); 11333577b47SPavel Dovgalyuk *offset = replay_get_dword(); 11433577b47SPavel Dovgalyuk replay_finish_event(); 11533577b47SPavel Dovgalyuk } else { 11633577b47SPavel Dovgalyuk error_report("Missing character write event in the replay log"); 11733577b47SPavel Dovgalyuk exit(1); 11833577b47SPavel Dovgalyuk } 11933577b47SPavel Dovgalyuk } 12033577b47SPavel Dovgalyuk 12133577b47SPavel Dovgalyuk int replay_char_read_all_load(uint8_t *buf) 12233577b47SPavel Dovgalyuk { 123d759c951SAlex Bennée g_assert(replay_mutex_locked()); 124d759c951SAlex Bennée 12533577b47SPavel Dovgalyuk if (replay_next_event_is(EVENT_CHAR_READ_ALL)) { 12633577b47SPavel Dovgalyuk size_t size; 12733577b47SPavel Dovgalyuk int res; 12833577b47SPavel Dovgalyuk replay_get_array(buf, &size); 12933577b47SPavel Dovgalyuk replay_finish_event(); 13033577b47SPavel Dovgalyuk res = (int)size; 13133577b47SPavel Dovgalyuk assert(res >= 0); 13233577b47SPavel Dovgalyuk return res; 13333577b47SPavel Dovgalyuk } else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) { 13433577b47SPavel Dovgalyuk int res = replay_get_dword(); 13533577b47SPavel Dovgalyuk replay_finish_event(); 13633577b47SPavel Dovgalyuk return res; 13733577b47SPavel Dovgalyuk } else { 13833577b47SPavel Dovgalyuk error_report("Missing character read all event in the replay log"); 13933577b47SPavel Dovgalyuk exit(1); 14033577b47SPavel Dovgalyuk } 14133577b47SPavel Dovgalyuk } 14233577b47SPavel Dovgalyuk 14333577b47SPavel Dovgalyuk void replay_char_read_all_save_error(int res) 14433577b47SPavel Dovgalyuk { 145d759c951SAlex Bennée g_assert(replay_mutex_locked()); 14633577b47SPavel Dovgalyuk assert(res < 0); 14733577b47SPavel Dovgalyuk replay_save_instructions(); 14833577b47SPavel Dovgalyuk replay_put_event(EVENT_CHAR_READ_ALL_ERROR); 14933577b47SPavel Dovgalyuk replay_put_dword(res); 15033577b47SPavel Dovgalyuk } 15133577b47SPavel Dovgalyuk 15233577b47SPavel Dovgalyuk void replay_char_read_all_save_buf(uint8_t *buf, int offset) 15333577b47SPavel Dovgalyuk { 154d759c951SAlex Bennée g_assert(replay_mutex_locked()); 15533577b47SPavel Dovgalyuk replay_save_instructions(); 15633577b47SPavel Dovgalyuk replay_put_event(EVENT_CHAR_READ_ALL); 15733577b47SPavel Dovgalyuk replay_put_array(buf, offset); 15833577b47SPavel Dovgalyuk } 159