X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/dfebfcf02f74ed47b61841037d7eda1baffb4d6e..6575c289f8c9820a7a0d2de2b0c3c58b13d9abc8:/monitor.c diff --git a/monitor.c b/monitor.c index 8f460317ee..eeef32e38b 100644 --- a/monitor.c +++ b/monitor.c @@ -66,6 +66,7 @@ #include "memory.h" #include "qmp-commands.h" #include "hmp.h" +#include "qemu-thread.h" /* for pic/irq_info */ #if defined(TARGET_SPARC) @@ -89,8 +90,8 @@ * TODO lift the restriction * 'i' 32 bit integer * 'l' target long (32 or 64 bit) - * 'M' just like 'l', except in user mode the value is - * multiplied by 2^20 (think Mebibyte) + * 'M' Non-negative target long (32 or 64 bit), in user mode the + * value is multiplied by 2^20 (think Mebibyte) * 'o' octets (aka bytes) * user mode accepts an optional T, t, G, g, M, m, K, k * suffix, which multiplies the value by 2^40 for @@ -128,7 +129,6 @@ typedef struct mon_cmd_t { int (*cmd_async)(Monitor *mon, const QDict *params, MonitorCompletion *cb, void *opaque); } mhandler; - bool qapi; int flags; } mon_cmd_t; @@ -140,12 +140,43 @@ struct mon_fd_t { QLIST_ENTRY(mon_fd_t) next; }; +/* file descriptor associated with a file descriptor set */ +typedef struct MonFdsetFd MonFdsetFd; +struct MonFdsetFd { + int fd; + bool removed; + char *opaque; + QLIST_ENTRY(MonFdsetFd) next; +}; + +/* file descriptor set containing fds passed via SCM_RIGHTS */ +typedef struct MonFdset MonFdset; +struct MonFdset { + int64_t id; + QLIST_HEAD(, MonFdsetFd) fds; + QLIST_HEAD(, MonFdsetFd) dup_fds; + QLIST_ENTRY(MonFdset) next; +}; + typedef struct MonitorControl { QObject *id; JSONMessageParser parser; int command_mode; } MonitorControl; +/* + * To prevent flooding clients, events can be throttled. The + * throttling is calculated globally, rather than per-Monitor + * instance. + */ +typedef struct MonitorEventState { + MonitorEvent event; /* Event being tracked */ + int64_t rate; /* Period over which to throttle. 0 to disable */ + int64_t last; /* Time at which event was last emitted */ + QEMUTimer *timer; /* Timer for handling delayed events */ + QObject *data; /* Event pending delayed dispatch */ +} MonitorEventState; + struct Monitor { CharDriverState *chr; int mux_out; @@ -159,45 +190,17 @@ struct Monitor { CPUArchState *mon_cpu; BlockDriverCompletionFunc *password_completion_cb; void *password_opaque; -#ifdef CONFIG_DEBUG_MONITOR - int print_calls_nr; -#endif QError *error; QLIST_HEAD(,mon_fd_t) fds; QLIST_ENTRY(Monitor) entry; }; -#ifdef CONFIG_DEBUG_MONITOR -#define MON_DEBUG(fmt, ...) do { \ - fprintf(stderr, "Monitor: "); \ - fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) - -static inline void mon_print_count_inc(Monitor *mon) -{ - mon->print_calls_nr++; -} - -static inline void mon_print_count_init(Monitor *mon) -{ - mon->print_calls_nr = 0; -} - -static inline int mon_print_count_get(const Monitor *mon) -{ - return mon->print_calls_nr; -} - -#else /* !CONFIG_DEBUG_MONITOR */ -#define MON_DEBUG(fmt, ...) do { } while (0) -static inline void mon_print_count_inc(Monitor *mon) { } -static inline void mon_print_count_init(Monitor *mon) { } -static inline int mon_print_count_get(const Monitor *mon) { return 0; } -#endif /* CONFIG_DEBUG_MONITOR */ - /* QMP checker flags */ #define QMP_ACCEPT_UNKNOWNS 1 static QLIST_HEAD(mon_list, Monitor) mon_list; +static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets; +static int mon_refcount; static mon_cmd_t mon_cmds[]; static mon_cmd_t info_cmds[]; @@ -286,8 +289,6 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) if (!mon) return; - mon_print_count_inc(mon); - if (monitor_ctrl_mode(mon)) { return; } @@ -372,16 +373,26 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data) QDECREF(json); } +static QDict *build_qmp_error_dict(const QError *err) +{ + QObject *obj; + + obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }", + ErrorClass_lookup[err->err_class], + qerror_human(err)); + + return qobject_to_qdict(obj); +} + static void monitor_protocol_emitter(Monitor *mon, QObject *data) { QDict *qmp; trace_monitor_protocol_emitter(mon); - qmp = qdict_new(); - if (!monitor_has_error(mon)) { /* success response */ + qmp = qdict_new(); if (data) { qobject_incref(data); qdict_put_obj(qmp, "return", data); @@ -391,9 +402,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data) } } else { /* error response */ - qdict_put(mon->error->error, "desc", qerror_human(mon->error)); - qdict_put(qmp, "error", mon->error->error); - QINCREF(mon->error->error); + qmp = build_qmp_error_dict(mon->error); QDECREF(mon->error); mon->error = NULL; } @@ -423,6 +432,170 @@ static void timestamp_put(QDict *qdict) qdict_put_obj(qdict, "timestamp", obj); } + +static const char *monitor_event_names[] = { + [QEVENT_SHUTDOWN] = "SHUTDOWN", + [QEVENT_RESET] = "RESET", + [QEVENT_POWERDOWN] = "POWERDOWN", + [QEVENT_STOP] = "STOP", + [QEVENT_RESUME] = "RESUME", + [QEVENT_VNC_CONNECTED] = "VNC_CONNECTED", + [QEVENT_VNC_INITIALIZED] = "VNC_INITIALIZED", + [QEVENT_VNC_DISCONNECTED] = "VNC_DISCONNECTED", + [QEVENT_BLOCK_IO_ERROR] = "BLOCK_IO_ERROR", + [QEVENT_RTC_CHANGE] = "RTC_CHANGE", + [QEVENT_WATCHDOG] = "WATCHDOG", + [QEVENT_SPICE_CONNECTED] = "SPICE_CONNECTED", + [QEVENT_SPICE_INITIALIZED] = "SPICE_INITIALIZED", + [QEVENT_SPICE_DISCONNECTED] = "SPICE_DISCONNECTED", + [QEVENT_BLOCK_JOB_COMPLETED] = "BLOCK_JOB_COMPLETED", + [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED", + [QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR", + [QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY", + [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED", + [QEVENT_SUSPEND] = "SUSPEND", + [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK", + [QEVENT_WAKEUP] = "WAKEUP", + [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE", + [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED", +}; +QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) + +MonitorEventState monitor_event_state[QEVENT_MAX]; +QemuMutex monitor_event_state_lock; + +/* + * Emits the event to every monitor instance + */ +static void +monitor_protocol_event_emit(MonitorEvent event, + QObject *data) +{ + Monitor *mon; + + trace_monitor_protocol_event_emit(event, data); + QLIST_FOREACH(mon, &mon_list, entry) { + if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) { + monitor_json_emitter(mon, data); + } + } +} + + +/* + * Queue a new event for emission to Monitor instances, + * applying any rate limiting if required. + */ +static void +monitor_protocol_event_queue(MonitorEvent event, + QObject *data) +{ + MonitorEventState *evstate; + int64_t now = qemu_get_clock_ns(rt_clock); + assert(event < QEVENT_MAX); + + qemu_mutex_lock(&monitor_event_state_lock); + evstate = &(monitor_event_state[event]); + trace_monitor_protocol_event_queue(event, + data, + evstate->rate, + evstate->last, + now); + + /* Rate limit of 0 indicates no throttling */ + if (!evstate->rate) { + monitor_protocol_event_emit(event, data); + evstate->last = now; + } else { + int64_t delta = now - evstate->last; + if (evstate->data || + delta < evstate->rate) { + /* If there's an existing event pending, replace + * it with the new event, otherwise schedule a + * timer for delayed emission + */ + if (evstate->data) { + qobject_decref(evstate->data); + } else { + int64_t then = evstate->last + evstate->rate; + qemu_mod_timer_ns(evstate->timer, then); + } + evstate->data = data; + qobject_incref(evstate->data); + } else { + monitor_protocol_event_emit(event, data); + evstate->last = now; + } + } + qemu_mutex_unlock(&monitor_event_state_lock); +} + + +/* + * The callback invoked by QemuTimer when a delayed + * event is ready to be emitted + */ +static void monitor_protocol_event_handler(void *opaque) +{ + MonitorEventState *evstate = opaque; + int64_t now = qemu_get_clock_ns(rt_clock); + + qemu_mutex_lock(&monitor_event_state_lock); + + trace_monitor_protocol_event_handler(evstate->event, + evstate->data, + evstate->last, + now); + if (evstate->data) { + monitor_protocol_event_emit(evstate->event, evstate->data); + qobject_decref(evstate->data); + evstate->data = NULL; + } + evstate->last = now; + qemu_mutex_unlock(&monitor_event_state_lock); +} + + +/* + * @event: the event ID to be limited + * @rate: the rate limit in milliseconds + * + * Sets a rate limit on a particular event, so no + * more than 1 event will be emitted within @rate + * milliseconds + */ +static void +monitor_protocol_event_throttle(MonitorEvent event, + int64_t rate) +{ + MonitorEventState *evstate; + assert(event < QEVENT_MAX); + + evstate = &(monitor_event_state[event]); + + trace_monitor_protocol_event_throttle(event, rate); + evstate->event = event; + evstate->rate = rate * SCALE_MS; + evstate->timer = qemu_new_timer(rt_clock, + SCALE_MS, + monitor_protocol_event_handler, + evstate); + evstate->last = 0; + evstate->data = NULL; +} + + +/* Global, one-time initializer to configure the rate limiting + * and initialize state */ +static void monitor_protocol_event_init(void) +{ + qemu_mutex_init(&monitor_event_state_lock); + /* Limit RTC & BALLOON events to 1 per second */ + monitor_protocol_event_throttle(QEVENT_RTC_CHANGE, 1000); + monitor_protocol_event_throttle(QEVENT_BALLOON_CHANGE, 1000); + monitor_protocol_event_throttle(QEVENT_WATCHDOG, 1000); +} + /** * monitor_protocol_event(): Generate a Monitor event * @@ -432,72 +605,11 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) { QDict *qmp; const char *event_name; - Monitor *mon; assert(event < QEVENT_MAX); - switch (event) { - case QEVENT_SHUTDOWN: - event_name = "SHUTDOWN"; - break; - case QEVENT_RESET: - event_name = "RESET"; - break; - case QEVENT_POWERDOWN: - event_name = "POWERDOWN"; - break; - case QEVENT_STOP: - event_name = "STOP"; - break; - case QEVENT_RESUME: - event_name = "RESUME"; - break; - case QEVENT_VNC_CONNECTED: - event_name = "VNC_CONNECTED"; - break; - case QEVENT_VNC_INITIALIZED: - event_name = "VNC_INITIALIZED"; - break; - case QEVENT_VNC_DISCONNECTED: - event_name = "VNC_DISCONNECTED"; - break; - case QEVENT_BLOCK_IO_ERROR: - event_name = "BLOCK_IO_ERROR"; - break; - case QEVENT_RTC_CHANGE: - event_name = "RTC_CHANGE"; - break; - case QEVENT_WATCHDOG: - event_name = "WATCHDOG"; - break; - case QEVENT_SPICE_CONNECTED: - event_name = "SPICE_CONNECTED"; - break; - case QEVENT_SPICE_INITIALIZED: - event_name = "SPICE_INITIALIZED"; - break; - case QEVENT_SPICE_DISCONNECTED: - event_name = "SPICE_DISCONNECTED"; - break; - case QEVENT_BLOCK_JOB_COMPLETED: - event_name = "BLOCK_JOB_COMPLETED"; - break; - case QEVENT_BLOCK_JOB_CANCELLED: - event_name = "BLOCK_JOB_CANCELLED"; - break; - case QEVENT_DEVICE_TRAY_MOVED: - event_name = "DEVICE_TRAY_MOVED"; - break; - case QEVENT_SUSPEND: - event_name = "SUSPEND"; - break; - case QEVENT_WAKEUP: - event_name = "WAKEUP"; - break; - default: - abort(); - break; - } + event_name = monitor_event_names[event]; + assert(event_name != NULL); qmp = qdict_new(); timestamp_put(qmp); @@ -507,11 +619,8 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) qdict_put_obj(qmp, "data", data); } - QLIST_FOREACH(mon, &mon_list, entry) { - if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) { - monitor_json_emitter(mon, QOBJECT(qmp)); - } - } + trace_monitor_protocol_event(event, event_name, qmp); + monitor_protocol_event_queue(event, QOBJECT(qmp)); QDECREF(qmp); } @@ -739,6 +848,25 @@ CommandInfoList *qmp_query_commands(Error **errp) return cmd_list; } +EventInfoList *qmp_query_events(Error **errp) +{ + EventInfoList *info, *ev_list = NULL; + MonitorEvent e; + + for (e = 0 ; e < QEVENT_MAX ; e++) { + const char *event_name = monitor_event_names[e]; + assert(event_name != NULL); + info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + info->value->name = g_strdup(event_name); + + info->next = ev_list; + ev_list = info; + } + + return ev_list; +} + /* set the current CPU defined by the user */ int monitor_set_cpu(int cpu_index) { @@ -771,13 +899,7 @@ static void do_info_registers(Monitor *mon) { CPUArchState *env; env = mon_get_cpu(); -#ifdef TARGET_I386 - cpu_dump_state(env, (FILE *)mon, monitor_fprintf, - X86_DUMP_FPU); -#else - cpu_dump_state(env, (FILE *)mon, monitor_fprintf, - 0); -#endif + cpu_dump_state(env, (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU); } static void do_info_jit(Monitor *mon) @@ -813,57 +935,11 @@ static void do_info_cpu_stats(Monitor *mon) } #endif -#if defined(CONFIG_TRACE_SIMPLE) -static void do_info_trace(Monitor *mon) -{ - st_print_trace((FILE *)mon, &monitor_fprintf); -} -#endif - static void do_trace_print_events(Monitor *mon) { trace_print_events((FILE *)mon, &monitor_fprintf); } -static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - const char *protocol = qdict_get_str(qdict, "protocol"); - const char *fdname = qdict_get_str(qdict, "fdname"); - CharDriverState *s; - - if (strcmp(protocol, "spice") == 0) { - int fd = monitor_get_fd(mon, fdname); - int skipauth = qdict_get_try_bool(qdict, "skipauth", 0); - int tls = qdict_get_try_bool(qdict, "tls", 0); - if (!using_spice) { - /* correct one? spice isn't a device ,,, */ - qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); - return -1; - } - if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) { - close(fd); - } - return 0; -#ifdef CONFIG_VNC - } else if (strcmp(protocol, "vnc") == 0) { - int fd = monitor_get_fd(mon, fdname); - int skipauth = qdict_get_try_bool(qdict, "skipauth", 0); - vnc_display_add_client(NULL, fd, skipauth); - return 0; -#endif - } else if ((s = qemu_chr_find(protocol)) != NULL) { - int fd = monitor_get_fd(mon, fdname); - if (qemu_chr_add_client(s, fd) < 0) { - qerror_report(QERR_ADD_CLIENT_FAILED); - return -1; - } - return 0; - } - - qerror_report(QERR_INVALID_PARAMETER, "protocol"); - return -1; -} - static int client_migrate_info(Monitor *mon, const QDict *qdict, MonitorCompletion cb, void *opaque) { @@ -898,12 +974,6 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, return -1; } -static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - vga_hw_screen_dump(qdict_get_str(qdict, "filename")); - return 0; -} - static void do_logfile(Monitor *mon, const QDict *qdict) { cpu_set_log_filename(qdict_get_str(qdict, "filename")); @@ -990,7 +1060,7 @@ static void monitor_printc(Monitor *mon, int c) } static void memory_dump(Monitor *mon, int count, int format, int wsize, - target_phys_addr_t addr, int is_physical) + hwaddr addr, int is_physical) { CPUArchState *env; int l, line_size, i, max_digits, len; @@ -1124,7 +1194,7 @@ static void do_physical_memory_dump(Monitor *mon, const QDict *qdict) int count = qdict_get_int(qdict, "count"); int format = qdict_get_int(qdict, "format"); int size = qdict_get_int(qdict, "size"); - target_phys_addr_t addr = qdict_get_int(qdict, "addr"); + hwaddr addr = qdict_get_int(qdict, "addr"); memory_dump(mon, count, format, size, addr, 1); } @@ -1132,47 +1202,26 @@ static void do_physical_memory_dump(Monitor *mon, const QDict *qdict) static void do_print(Monitor *mon, const QDict *qdict) { int format = qdict_get_int(qdict, "format"); - target_phys_addr_t val = qdict_get_int(qdict, "val"); + hwaddr val = qdict_get_int(qdict, "val"); -#if TARGET_PHYS_ADDR_BITS == 32 switch(format) { case 'o': - monitor_printf(mon, "%#o", val); + monitor_printf(mon, "%#" HWADDR_PRIo, val); break; case 'x': - monitor_printf(mon, "%#x", val); + monitor_printf(mon, "%#" HWADDR_PRIx, val); break; case 'u': - monitor_printf(mon, "%u", val); + monitor_printf(mon, "%" HWADDR_PRIu, val); break; default: case 'd': - monitor_printf(mon, "%d", val); + monitor_printf(mon, "%" HWADDR_PRId, val); break; case 'c': monitor_printc(mon, val); break; } -#else - switch(format) { - case 'o': - monitor_printf(mon, "%#" PRIo64, val); - break; - case 'x': - monitor_printf(mon, "%#" PRIx64, val); - break; - case 'u': - monitor_printf(mon, "%" PRIu64, val); - break; - default: - case 'd': - monitor_printf(mon, "%" PRId64, val); - break; - case 'c': - monitor_printc(mon, val); - break; - } -#endif monitor_printf(mon, "\n"); } @@ -1193,245 +1242,6 @@ static void do_sum(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%05d\n", sum); } -typedef struct { - int keycode; - const char *name; -} KeyDef; - -static const KeyDef key_defs[] = { - { 0x2a, "shift" }, - { 0x36, "shift_r" }, - - { 0x38, "alt" }, - { 0xb8, "alt_r" }, - { 0x64, "altgr" }, - { 0xe4, "altgr_r" }, - { 0x1d, "ctrl" }, - { 0x9d, "ctrl_r" }, - - { 0xdd, "menu" }, - - { 0x01, "esc" }, - - { 0x02, "1" }, - { 0x03, "2" }, - { 0x04, "3" }, - { 0x05, "4" }, - { 0x06, "5" }, - { 0x07, "6" }, - { 0x08, "7" }, - { 0x09, "8" }, - { 0x0a, "9" }, - { 0x0b, "0" }, - { 0x0c, "minus" }, - { 0x0d, "equal" }, - { 0x0e, "backspace" }, - - { 0x0f, "tab" }, - { 0x10, "q" }, - { 0x11, "w" }, - { 0x12, "e" }, - { 0x13, "r" }, - { 0x14, "t" }, - { 0x15, "y" }, - { 0x16, "u" }, - { 0x17, "i" }, - { 0x18, "o" }, - { 0x19, "p" }, - { 0x1a, "bracket_left" }, - { 0x1b, "bracket_right" }, - { 0x1c, "ret" }, - - { 0x1e, "a" }, - { 0x1f, "s" }, - { 0x20, "d" }, - { 0x21, "f" }, - { 0x22, "g" }, - { 0x23, "h" }, - { 0x24, "j" }, - { 0x25, "k" }, - { 0x26, "l" }, - { 0x27, "semicolon" }, - { 0x28, "apostrophe" }, - { 0x29, "grave_accent" }, - - { 0x2b, "backslash" }, - { 0x2c, "z" }, - { 0x2d, "x" }, - { 0x2e, "c" }, - { 0x2f, "v" }, - { 0x30, "b" }, - { 0x31, "n" }, - { 0x32, "m" }, - { 0x33, "comma" }, - { 0x34, "dot" }, - { 0x35, "slash" }, - - { 0x37, "asterisk" }, - - { 0x39, "spc" }, - { 0x3a, "caps_lock" }, - { 0x3b, "f1" }, - { 0x3c, "f2" }, - { 0x3d, "f3" }, - { 0x3e, "f4" }, - { 0x3f, "f5" }, - { 0x40, "f6" }, - { 0x41, "f7" }, - { 0x42, "f8" }, - { 0x43, "f9" }, - { 0x44, "f10" }, - { 0x45, "num_lock" }, - { 0x46, "scroll_lock" }, - - { 0xb5, "kp_divide" }, - { 0x37, "kp_multiply" }, - { 0x4a, "kp_subtract" }, - { 0x4e, "kp_add" }, - { 0x9c, "kp_enter" }, - { 0x53, "kp_decimal" }, - { 0x54, "sysrq" }, - - { 0x52, "kp_0" }, - { 0x4f, "kp_1" }, - { 0x50, "kp_2" }, - { 0x51, "kp_3" }, - { 0x4b, "kp_4" }, - { 0x4c, "kp_5" }, - { 0x4d, "kp_6" }, - { 0x47, "kp_7" }, - { 0x48, "kp_8" }, - { 0x49, "kp_9" }, - - { 0x56, "<" }, - - { 0x57, "f11" }, - { 0x58, "f12" }, - - { 0xb7, "print" }, - - { 0xc7, "home" }, - { 0xc9, "pgup" }, - { 0xd1, "pgdn" }, - { 0xcf, "end" }, - - { 0xcb, "left" }, - { 0xc8, "up" }, - { 0xd0, "down" }, - { 0xcd, "right" }, - - { 0xd2, "insert" }, - { 0xd3, "delete" }, -#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) - { 0xf0, "stop" }, - { 0xf1, "again" }, - { 0xf2, "props" }, - { 0xf3, "undo" }, - { 0xf4, "front" }, - { 0xf5, "copy" }, - { 0xf6, "open" }, - { 0xf7, "paste" }, - { 0xf8, "find" }, - { 0xf9, "cut" }, - { 0xfa, "lf" }, - { 0xfb, "help" }, - { 0xfc, "meta_l" }, - { 0xfd, "meta_r" }, - { 0xfe, "compose" }, -#endif - { 0, NULL }, -}; - -static int get_keycode(const char *key) -{ - const KeyDef *p; - char *endp; - int ret; - - for(p = key_defs; p->name != NULL; p++) { - if (!strcmp(key, p->name)) - return p->keycode; - } - if (strstart(key, "0x", NULL)) { - ret = strtoul(key, &endp, 0); - if (*endp == '\0' && ret >= 0x01 && ret <= 0xff) - return ret; - } - return -1; -} - -#define MAX_KEYCODES 16 -static uint8_t keycodes[MAX_KEYCODES]; -static int nb_pending_keycodes; -static QEMUTimer *key_timer; - -static void release_keys(void *opaque) -{ - int keycode; - - while (nb_pending_keycodes > 0) { - nb_pending_keycodes--; - keycode = keycodes[nb_pending_keycodes]; - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); - } -} - -static void do_sendkey(Monitor *mon, const QDict *qdict) -{ - char keyname_buf[16]; - char *separator; - int keyname_len, keycode, i; - const char *string = qdict_get_str(qdict, "string"); - int has_hold_time = qdict_haskey(qdict, "hold_time"); - int hold_time = qdict_get_try_int(qdict, "hold_time", -1); - - if (nb_pending_keycodes > 0) { - qemu_del_timer(key_timer); - release_keys(NULL); - } - if (!has_hold_time) - hold_time = 100; - i = 0; - while (1) { - separator = strchr(string, '-'); - keyname_len = separator ? separator - string : strlen(string); - if (keyname_len > 0) { - pstrcpy(keyname_buf, sizeof(keyname_buf), string); - if (keyname_len > sizeof(keyname_buf) - 1) { - monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf); - return; - } - if (i == MAX_KEYCODES) { - monitor_printf(mon, "too many keys\n"); - return; - } - keyname_buf[keyname_len] = 0; - keycode = get_keycode(keyname_buf); - if (keycode < 0) { - monitor_printf(mon, "unknown key: '%s'\n", keyname_buf); - return; - } - keycodes[i++] = keycode; - } - if (!separator) - break; - string = separator + 1; - } - nb_pending_keycodes = i; - /* key down events */ - for (i = 0; i < nb_pending_keycodes; i++) { - keycode = keycodes[i]; - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode & 0x7f); - } - /* delayed key up events */ - qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + - muldiv64(get_ticks_per_sec(), hold_time, 1000)); -} - static int mouse_button_state; static void do_mouse_move(Monitor *mon, const QDict *qdict) @@ -1528,9 +1338,9 @@ static void do_boot_set(Monitor *mon, const QDict *qdict) } #if defined(TARGET_I386) -static void print_pte(Monitor *mon, target_phys_addr_t addr, - target_phys_addr_t pte, - target_phys_addr_t mask) +static void print_pte(Monitor *mon, hwaddr addr, + hwaddr pte, + hwaddr mask) { #ifdef TARGET_X86_64 if (addr & (1ULL << 47)) { @@ -1599,7 +1409,7 @@ static void tlb_info_pae32(Monitor *mon, CPUArchState *env) if (pde & PG_PSE_MASK) { /* 2M pages with PAE, CR4.PSE is ignored */ print_pte(mon, (l1 << 30 ) + (l2 << 21), pde, - ~((target_phys_addr_t)(1 << 20) - 1)); + ~((hwaddr)(1 << 20) - 1)); } else { pt_addr = pde & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { @@ -1609,7 +1419,7 @@ static void tlb_info_pae32(Monitor *mon, CPUArchState *env) print_pte(mon, (l1 << 30 ) + (l2 << 21) + (l3 << 12), pte & ~PG_PSE_MASK, - ~(target_phys_addr_t)0xfff); + ~(hwaddr)0xfff); } } } @@ -1701,9 +1511,9 @@ static void tlb_info(Monitor *mon) } } -static void mem_print(Monitor *mon, target_phys_addr_t *pstart, +static void mem_print(Monitor *mon, hwaddr *pstart, int *plast_prot, - target_phys_addr_t end, int prot) + hwaddr end, int prot) { int prot1; prot1 = *plast_prot; @@ -1729,7 +1539,7 @@ static void mem_info_32(Monitor *mon, CPUArchState *env) unsigned int l1, l2; int prot, last_prot; uint32_t pgd, pde, pte; - target_phys_addr_t start, end; + hwaddr start, end; pgd = env->cr[3] & ~0xfff; last_prot = 0; @@ -1762,7 +1572,7 @@ static void mem_info_32(Monitor *mon, CPUArchState *env) } } /* Flush last range */ - mem_print(mon, &start, &last_prot, (target_phys_addr_t)1 << 32, 0); + mem_print(mon, &start, &last_prot, (hwaddr)1 << 32, 0); } static void mem_info_pae32(Monitor *mon, CPUArchState *env) @@ -1771,7 +1581,7 @@ static void mem_info_pae32(Monitor *mon, CPUArchState *env) int prot, last_prot; uint64_t pdpe, pde, pte; uint64_t pdp_addr, pd_addr, pt_addr; - target_phys_addr_t start, end; + hwaddr start, end; pdp_addr = env->cr[3] & ~0x1f; last_prot = 0; @@ -1817,7 +1627,7 @@ static void mem_info_pae32(Monitor *mon, CPUArchState *env) } } /* Flush last range */ - mem_print(mon, &start, &last_prot, (target_phys_addr_t)1 << 32, 0); + mem_print(mon, &start, &last_prot, (hwaddr)1 << 32, 0); } @@ -1896,7 +1706,7 @@ static void mem_info_64(Monitor *mon, CPUArchState *env) } } /* Flush last range */ - mem_print(mon, &start, &last_prot, (target_phys_addr_t)1 << 48, 0); + mem_print(mon, &start, &last_prot, (hwaddr)1 << 48, 0); } #endif @@ -2200,48 +2010,45 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict) } #endif -static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data) +void qmp_getfd(const char *fdname, Error **errp) { - const char *fdname = qdict_get_str(qdict, "fdname"); mon_fd_t *monfd; int fd; - fd = qemu_chr_fe_get_msgfd(mon->chr); + fd = qemu_chr_fe_get_msgfd(cur_mon->chr); if (fd == -1) { - qerror_report(QERR_FD_NOT_SUPPLIED); - return -1; + error_set(errp, QERR_FD_NOT_SUPPLIED); + return; } if (qemu_isdigit(fdname[0])) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "fdname", - "a name not starting with a digit"); - return -1; + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "fdname", + "a name not starting with a digit"); + return; } - QLIST_FOREACH(monfd, &mon->fds, next) { + QLIST_FOREACH(monfd, &cur_mon->fds, next) { if (strcmp(monfd->name, fdname) != 0) { continue; } close(monfd->fd); monfd->fd = fd; - return 0; + return; } monfd = g_malloc0(sizeof(mon_fd_t)); monfd->name = g_strdup(fdname); monfd->fd = fd; - QLIST_INSERT_HEAD(&mon->fds, monfd, next); - return 0; + QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next); } -static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data) +void qmp_closefd(const char *fdname, Error **errp) { - const char *fdname = qdict_get_str(qdict, "fdname"); mon_fd_t *monfd; - QLIST_FOREACH(monfd, &mon->fds, next) { + QLIST_FOREACH(monfd, &cur_mon->fds, next) { if (strcmp(monfd->name, fdname) != 0) { continue; } @@ -2250,11 +2057,10 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data) close(monfd->fd); g_free(monfd->name); g_free(monfd); - return 0; + return; } - qerror_report(QERR_FD_NOT_FOUND, fdname); - return -1; + error_set(errp, QERR_FD_NOT_FOUND, fdname); } static void do_loadvm(Monitor *mon, const QDict *qdict) @@ -2269,7 +2075,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict) } } -int monitor_get_fd(Monitor *mon, const char *fdname) +int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) { mon_fd_t *monfd; @@ -2290,9 +2096,329 @@ int monitor_get_fd(Monitor *mon, const char *fdname) return fd; } + error_setg(errp, "File descriptor named '%s' has not been found", fdname); + return -1; +} + +static void monitor_fdset_cleanup(MonFdset *mon_fdset) +{ + MonFdsetFd *mon_fdset_fd; + MonFdsetFd *mon_fdset_fd_next; + + QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) { + if ((mon_fdset_fd->removed || + (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) && + runstate_is_running()) { + close(mon_fdset_fd->fd); + g_free(mon_fdset_fd->opaque); + QLIST_REMOVE(mon_fdset_fd, next); + g_free(mon_fdset_fd); + } + } + + if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) { + QLIST_REMOVE(mon_fdset, next); + g_free(mon_fdset); + } +} + +static void monitor_fdsets_cleanup(void) +{ + MonFdset *mon_fdset; + MonFdset *mon_fdset_next; + + QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) { + monitor_fdset_cleanup(mon_fdset); + } +} + +AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque, + const char *opaque, Error **errp) +{ + int fd; + Monitor *mon = cur_mon; + AddfdInfo *fdinfo; + + fd = qemu_chr_fe_get_msgfd(mon->chr); + if (fd == -1) { + error_set(errp, QERR_FD_NOT_SUPPLIED); + goto error; + } + + fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, + has_opaque, opaque, errp); + if (fdinfo) { + return fdinfo; + } + +error: + if (fd != -1) { + close(fd); + } + return NULL; +} + +void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp) +{ + MonFdset *mon_fdset; + MonFdsetFd *mon_fdset_fd; + char fd_str[60]; + + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + if (mon_fdset->id != fdset_id) { + continue; + } + QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { + if (has_fd) { + if (mon_fdset_fd->fd != fd) { + continue; + } + mon_fdset_fd->removed = true; + break; + } else { + mon_fdset_fd->removed = true; + } + } + if (has_fd && !mon_fdset_fd) { + goto error; + } + monitor_fdset_cleanup(mon_fdset); + return; + } + +error: + if (has_fd) { + snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64, + fdset_id, fd); + } else { + snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id); + } + error_set(errp, QERR_FD_NOT_FOUND, fd_str); +} + +FdsetInfoList *qmp_query_fdsets(Error **errp) +{ + MonFdset *mon_fdset; + MonFdsetFd *mon_fdset_fd; + FdsetInfoList *fdset_list = NULL; + + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + FdsetInfoList *fdset_info = g_malloc0(sizeof(*fdset_info)); + FdsetFdInfoList *fdsetfd_list = NULL; + + fdset_info->value = g_malloc0(sizeof(*fdset_info->value)); + fdset_info->value->fdset_id = mon_fdset->id; + + QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { + FdsetFdInfoList *fdsetfd_info; + + fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info)); + fdsetfd_info->value = g_malloc0(sizeof(*fdsetfd_info->value)); + fdsetfd_info->value->fd = mon_fdset_fd->fd; + if (mon_fdset_fd->opaque) { + fdsetfd_info->value->has_opaque = true; + fdsetfd_info->value->opaque = g_strdup(mon_fdset_fd->opaque); + } else { + fdsetfd_info->value->has_opaque = false; + } + + fdsetfd_info->next = fdsetfd_list; + fdsetfd_list = fdsetfd_info; + } + + fdset_info->value->fds = fdsetfd_list; + + fdset_info->next = fdset_list; + fdset_list = fdset_info; + } + + return fdset_list; +} + +AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, + bool has_opaque, const char *opaque, + Error **errp) +{ + MonFdset *mon_fdset = NULL; + MonFdsetFd *mon_fdset_fd; + AddfdInfo *fdinfo; + + if (has_fdset_id) { + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + /* Break if match found or match impossible due to ordering by ID */ + if (fdset_id <= mon_fdset->id) { + if (fdset_id < mon_fdset->id) { + mon_fdset = NULL; + } + break; + } + } + } + + if (mon_fdset == NULL) { + int64_t fdset_id_prev = -1; + MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets); + + if (has_fdset_id) { + if (fdset_id < 0) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id", + "a non-negative value"); + return NULL; + } + /* Use specified fdset ID */ + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + mon_fdset_cur = mon_fdset; + if (fdset_id < mon_fdset_cur->id) { + break; + } + } + } else { + /* Use first available fdset ID */ + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + mon_fdset_cur = mon_fdset; + if (fdset_id_prev == mon_fdset_cur->id - 1) { + fdset_id_prev = mon_fdset_cur->id; + continue; + } + break; + } + } + + mon_fdset = g_malloc0(sizeof(*mon_fdset)); + if (has_fdset_id) { + mon_fdset->id = fdset_id; + } else { + mon_fdset->id = fdset_id_prev + 1; + } + + /* The fdset list is ordered by fdset ID */ + if (!mon_fdset_cur) { + QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next); + } else if (mon_fdset->id < mon_fdset_cur->id) { + QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next); + } else { + QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next); + } + } + + mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd)); + mon_fdset_fd->fd = fd; + mon_fdset_fd->removed = false; + if (has_opaque) { + mon_fdset_fd->opaque = g_strdup(opaque); + } + QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next); + + fdinfo = g_malloc0(sizeof(*fdinfo)); + fdinfo->fdset_id = mon_fdset->id; + fdinfo->fd = mon_fdset_fd->fd; + + return fdinfo; +} + +int monitor_fdset_get_fd(int64_t fdset_id, int flags) +{ +#ifndef _WIN32 + MonFdset *mon_fdset; + MonFdsetFd *mon_fdset_fd; + int mon_fd_flags; + + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + if (mon_fdset->id != fdset_id) { + continue; + } + QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { + mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); + if (mon_fd_flags == -1) { + return -1; + } + + if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { + return mon_fdset_fd->fd; + } + } + errno = EACCES; + return -1; + } +#endif + + errno = ENOENT; return -1; } +int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd) +{ + MonFdset *mon_fdset; + MonFdsetFd *mon_fdset_fd_dup; + + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + if (mon_fdset->id != fdset_id) { + continue; + } + QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { + if (mon_fdset_fd_dup->fd == dup_fd) { + return -1; + } + } + mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup)); + mon_fdset_fd_dup->fd = dup_fd; + QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next); + return 0; + } + return -1; +} + +static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) +{ + MonFdset *mon_fdset; + MonFdsetFd *mon_fdset_fd_dup; + + QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { + if (mon_fdset_fd_dup->fd == dup_fd) { + if (remove) { + QLIST_REMOVE(mon_fdset_fd_dup, next); + if (QLIST_EMPTY(&mon_fdset->dup_fds)) { + monitor_fdset_cleanup(mon_fdset); + } + } + return mon_fdset->id; + } + } + } + return -1; +} + +int monitor_fdset_dup_fd_find(int dup_fd) +{ + return monitor_fdset_dup_fd_find_remove(dup_fd, false); +} + +int monitor_fdset_dup_fd_remove(int dup_fd) +{ + return monitor_fdset_dup_fd_find_remove(dup_fd, true); +} + +int monitor_handle_fd_param(Monitor *mon, const char *fdname) +{ + int fd; + Error *local_err = NULL; + + if (!qemu_isdigit(fdname[0]) && mon) { + + fd = monitor_get_fd(mon, fdname, &local_err); + if (fd == -1) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + } else { + fd = qemu_parse_fd(fdname); + } + + return fd; +} + /* mon_cmds and info_cmds would be sorted at runtime */ static mon_cmd_t mon_cmds[] = { #include "hmp-commands.h" @@ -2558,6 +2684,20 @@ static mon_cmd_t info_cmds[] = { .help = "show migration status", .mhandler.info = hmp_info_migrate, }, + { + .name = "migrate_capabilities", + .args_type = "", + .params = "", + .help = "show current migration capabilities", + .mhandler.info = hmp_info_migrate_capabilities, + }, + { + .name = "migrate_cache_size", + .args_type = "", + .params = "", + .help = "show current migration xbzrle cache size", + .mhandler.info = hmp_info_migrate_cache_size, + }, { .name = "balloon", .args_type = "", @@ -2586,15 +2726,6 @@ static mon_cmd_t info_cmds[] = { .help = "show roms", .mhandler.info = do_info_roms, }, -#if defined(CONFIG_TRACE_SIMPLE) - { - .name = "trace", - .args_type = "", - .params = "", - .help = "show current contents of trace buffer", - .mhandler.info = do_info_trace, - }, -#endif { .name = "trace-events", .args_type = "", @@ -3121,11 +3252,11 @@ static int64_t expr_unary(Monitor *mon) n = 0; break; default: -#if TARGET_PHYS_ADDR_BITS > 32 + errno = 0; n = strtoull(pch, &p, 0); -#else - n = strtoul(pch, &p, 0); -#endif + if (errno == ERANGE) { + expr_error(mon, "number too large"); + } if (pch == p) { expr_error(mon, "invalid char in expression"); } @@ -3619,6 +3750,10 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, monitor_printf(mon, "integer is for 32-bit values\n"); goto fail; } else if (c == 'M') { + if (val < 0) { + monitor_printf(mon, "enter a positive value\n"); + goto fail; + } val <<= 20; } qdict_put(qdict, key, qint_from_int(val)); @@ -3765,8 +3900,6 @@ void monitor_set_error(Monitor *mon, QError *qerror) if (!mon->error) { mon->error = qerror; } else { - MON_DEBUG("Additional error report at %s:%d\n", - qerror->file, qerror->linenr); QDECREF(qerror); } } @@ -3780,36 +3913,7 @@ static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret) * Action: Report an internal error to the client if in QMP. */ qerror_report(QERR_UNDEFINED_ERROR); - MON_DEBUG("command '%s' returned failure but did not pass an error\n", - cmd->name); - } - -#ifdef CONFIG_DEBUG_MONITOR - if (!ret && monitor_has_error(mon)) { - /* - * If it returns success, it must not have passed an error. - * - * Action: Report the passed error to the client. - */ - MON_DEBUG("command '%s' returned success but passed an error\n", - cmd->name); - } - - if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) { - /* - * Handlers should not call Monitor print functions. - * - * Action: Ignore them in QMP. - * - * (XXX: we don't check any 'info' or 'query' command here - * because the user print function _is_ called by do_info(), hence - * we will trigger this check. This problem will go away when we - * make 'query' commands real and kill do_info()) - */ - MON_DEBUG("command '%s' called print functions %d time(s)\n", - cmd->name, mon_print_count_get(mon)); } -#endif } static void handle_user_command(Monitor *mon, const char *cmdline) @@ -3975,7 +4079,6 @@ static void monitor_find_completion(const char *cmdline) int nb_args, i, len; const char *ptype, *str; const mon_cmd_t *cmd; - const KeyDef *key; parse_cmdline(cmdline, &nb_args, args); #ifdef DEBUG_COMPLETION @@ -4049,8 +4152,8 @@ static void monitor_find_completion(const char *cmdline) if (sep) str = sep + 1; readline_set_completion_index(cur_mon->rs, strlen(str)); - for(key = key_defs; key->name != NULL; key++) { - cmd_completion(str, key->name); + for (i = 0; i < Q_KEY_CODE_MAX; i++) { + cmd_completion(str, QKeyCode_lookup[i]); } } else if (!strcmp(cmd->name, "help|?")) { readline_set_completion_index(cur_mon->rs, strlen(str)); @@ -4158,6 +4261,9 @@ static int check_client_args_type(const QDict *client_args, case 'O': assert(flags & QMP_ACCEPT_UNKNOWNS); break; + case 'q': + /* Any QObject can be passed. */ + break; case '/': case '.': /* @@ -4335,8 +4441,6 @@ static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd, int ret; QObject *data = NULL; - mon_print_count_init(mon); - ret = cmd->mhandler.cmd_new(mon, params, &data); handler_audit(mon, cmd, ret); monitor_protocol_emitter(mon, data); @@ -4491,13 +4595,16 @@ static void monitor_control_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: mon->mc->command_mode = 0; - json_message_parser_init(&mon->mc->parser, handle_qmp_command); data = get_qmp_greeting(); monitor_json_emitter(mon, data); qobject_decref(data); + mon_refcount++; break; case CHR_EVENT_CLOSED: json_message_parser_destroy(&mon->mc->parser); + json_message_parser_init(&mon->mc->parser, handle_qmp_command); + mon_refcount--; + monitor_fdsets_cleanup(); break; } } @@ -4538,6 +4645,12 @@ static void monitor_event(void *opaque, int event) readline_show_prompt(mon->rs); } mon->reset_seen = 1; + mon_refcount++; + break; + + case CHR_EVENT_CLOSED: + mon_refcount--; + monitor_fdsets_cleanup(); break; } } @@ -4576,7 +4689,7 @@ void monitor_init(CharDriverState *chr, int flags) Monitor *mon; if (is_first_init) { - key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); + monitor_protocol_event_init(); is_first_init = 0; } @@ -4595,6 +4708,8 @@ void monitor_init(CharDriverState *chr, int flags) qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read, monitor_control_event, mon); qemu_chr_fe_set_echo(chr, true); + + json_message_parser_init(&mon->mc->parser, handle_qmp_command); } else { qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, monitor_event, mon);