X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=monitor.c;h=1b8ba2c1fa284175262d6017d3fec083624bdf18;hb=ff5acedd8f472a39b2e11d0fad79d0e9b6c140c2;hp=612ee5675da834a787107b0c6857e3e8c1c1bd03;hpb=2e061a7c86d77c599676d89c3461f8efe9c275b1;p=qemu.git diff --git a/monitor.c b/monitor.c index 612ee5675..1b8ba2c1f 100644 --- a/monitor.c +++ b/monitor.c @@ -34,6 +34,7 @@ #include "net.h" #include "net/slirp.h" #include "qemu-char.h" +#include "ui/qemu-spice.h" #include "sysemu.h" #include "monitor.h" #include "readline.h" @@ -55,10 +56,11 @@ #include "json-streamer.h" #include "json-parser.h" #include "osdep.h" -#include "exec-all.h" +#include "cpu.h" #ifdef CONFIG_SIMPLE_TRACE #include "trace.h" #endif +#include "ui/qemu-spice.h" //#define DEBUG //#define DEBUG_COMPLETION @@ -78,10 +80,11 @@ * 'l' target long (32 or 64 bit) * 'M' just like 'l', except in user mode the value is * multiplied by 2^20 (think Mebibyte) - * 'f' double - * user mode accepts an optional G, g, M, m, K, k suffix, - * which multiplies the value by 2^30 for suffixes G and - * g, 2^20 for M and m, 2^10 for K and k + * '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 + * suffixes T and t, 2^30 for suffixes G and g, 2^20 for + * M and m, 2^10 for K and k * 'T' double * user mode accepts an optional ms, us, ns suffix, * which divides the value by 1e3, 1e6, 1e9, respectively @@ -319,7 +322,8 @@ void monitor_print_filename(Monitor *mon, const char *filename) } } -static int monitor_fprintf(FILE *stream, const char *fmt, ...) +static int GCC_FMT_ATTR(2, 3) monitor_fprintf(FILE *stream, + const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -330,21 +334,16 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...) static void monitor_user_noop(Monitor *mon, const QObject *data) { } -static inline int monitor_handler_ported(const mon_cmd_t *cmd) +static inline int handler_is_qobject(const mon_cmd_t *cmd) { return cmd->user_print != NULL; } -static inline bool monitor_handler_is_async(const mon_cmd_t *cmd) +static inline bool handler_is_async(const mon_cmd_t *cmd) { return cmd->flags & MONITOR_CMD_ASYNC; } -static inline bool monitor_cmd_user_only(const mon_cmd_t *cmd) -{ - return (cmd->flags & MONITOR_CMD_USER_ONLY); -} - static inline int monitor_has_error(const Monitor *mon) { return mon->error != NULL; @@ -354,10 +353,8 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data) { QString *json; - if (mon->flags & MONITOR_USE_PRETTY) - json = qobject_to_json_pretty(data); - else - json = qobject_to_json(data); + json = mon->flags & MONITOR_USE_PRETTY ? qobject_to_json_pretty(data) : + qobject_to_json(data); assert(json != NULL); qstring_append_chr(json, '\n'); @@ -462,6 +459,15 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) 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; default: abort(); break; @@ -494,6 +500,44 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params, return 0; } +static int mon_set_cpu(int cpu_index); +static void handle_user_command(Monitor *mon, const char *cmdline); + +static int do_hmp_passthrough(Monitor *mon, const QDict *params, + QObject **ret_data) +{ + int ret = 0; + Monitor *old_mon, hmp; + CharDriverState mchar; + + memset(&hmp, 0, sizeof(hmp)); + qemu_chr_init_mem(&mchar); + hmp.chr = &mchar; + + old_mon = cur_mon; + cur_mon = &hmp; + + if (qdict_haskey(params, "cpu-index")) { + ret = mon_set_cpu(qdict_get_int(params, "cpu-index")); + if (ret < 0) { + cur_mon = old_mon; + qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number"); + goto out; + } + } + + handle_user_command(&hmp, qdict_get_str(params, "command-line")); + cur_mon = old_mon; + + if (qemu_chr_mem_osize(hmp.chr) > 0) { + *ret_data = QOBJECT(qemu_chr_mem_to_qs(hmp.chr)); + } + +out: + qemu_chr_close_mem(hmp.chr); + return ret; +} + static int compare_cmd(const char *name, const char *list) { const char *p, *pstart; @@ -553,7 +597,11 @@ static void do_change_trace_event_state(Monitor *mon, const QDict *qdict) { const char *tp_name = qdict_get_str(qdict, "name"); bool new_state = qdict_get_bool(qdict, "option"); - st_change_trace_event_state(tp_name, new_state); + int ret = st_change_trace_event_state(tp_name, new_state); + + if (!ret) { + monitor_printf(mon, "unknown event name \"%s\"\n", tp_name); + } } static void do_trace_file(Monitor *mon, const QDict *qdict) @@ -657,9 +705,9 @@ static void do_info(Monitor *mon, const QDict *qdict) goto help; } - if (monitor_handler_is_async(cmd)) { + if (handler_is_async(cmd)) { user_async_info_handler(mon, cmd); - } else if (monitor_handler_ported(cmd)) { + } else if (handler_is_qobject(cmd)) { QObject *info_data = NULL; cmd->mhandler.info_new(mon, &info_data); @@ -849,6 +897,9 @@ static void print_cpu_iter(QObject *obj, void *opaque) monitor_printf(mon, " (halted)"); } + monitor_printf(mon, " thread_id=%" PRId64 " ", + qdict_get_int(cpu, "thread_id")); + monitor_printf(mon, "\n"); } @@ -893,6 +944,7 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data) #elif defined(TARGET_MIPS) qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC)); #endif + qdict_put(cpu, "thread_id", qint_from_int(env->thread_id)); qlist_append(cpu_list, cpu); } @@ -968,8 +1020,17 @@ static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data) return 0; } +#ifdef CONFIG_VNC static int change_vnc_password(const char *password) { + if (!password || !password[0]) { + if (vnc_display_disable_login(NULL)) { + qerror_report(QERR_SET_PASSWD_FAILED); + return -1; + } + return 0; + } + if (vnc_display_password(NULL, password) < 0) { qerror_report(QERR_SET_PASSWD_FAILED); return -1; @@ -1006,6 +1067,13 @@ static int do_change_vnc(Monitor *mon, const char *target, const char *arg) return 0; } +#else +static int do_change_vnc(Monitor *mon, const char *target, const char *arg) +{ + qerror_report(QERR_FEATURE_DISABLED, "vnc"); + return -ENODEV; +} +#endif /** * do_change(): Change a removable medium, or VNC configuration @@ -1026,6 +1094,158 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data) return ret; } +static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *protocol = qdict_get_str(qdict, "protocol"); + const char *password = qdict_get_str(qdict, "password"); + const char *connected = qdict_get_try_str(qdict, "connected"); + int disconnect_if_connected = 0; + int fail_if_connected = 0; + int rc; + + if (connected) { + if (strcmp(connected, "fail") == 0) { + fail_if_connected = 1; + } else if (strcmp(connected, "disconnect") == 0) { + disconnect_if_connected = 1; + } else if (strcmp(connected, "keep") == 0) { + /* nothing */ + } else { + qerror_report(QERR_INVALID_PARAMETER, "connected"); + return -1; + } + } + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); + return -1; + } + rc = qemu_spice_set_passwd(password, fail_if_connected, + disconnect_if_connected); + if (rc != 0) { + qerror_report(QERR_SET_PASSWD_FAILED); + return -1; + } + return 0; + } + + if (strcmp(protocol, "vnc") == 0) { + if (fail_if_connected || disconnect_if_connected) { + /* vnc supports "connected=keep" only */ + qerror_report(QERR_INVALID_PARAMETER, "connected"); + return -1; + } + /* Note that setting an empty password will not disable login through + * this interface. */ + return vnc_display_password(NULL, password); + } + + qerror_report(QERR_INVALID_PARAMETER, "protocol"); + return -1; +} + +static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *protocol = qdict_get_str(qdict, "protocol"); + const char *whenstr = qdict_get_str(qdict, "time"); + time_t when; + int rc; + + if (strcmp(whenstr, "now") == 0) { + when = 0; + } else if (strcmp(whenstr, "never") == 0) { + when = TIME_MAX; + } else if (whenstr[0] == '+') { + when = time(NULL) + strtoull(whenstr+1, NULL, 10); + } else { + when = strtoull(whenstr, NULL, 10); + } + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); + return -1; + } + rc = qemu_spice_set_pw_expire(when); + if (rc != 0) { + qerror_report(QERR_SET_PASSWD_FAILED); + return -1; + } + return 0; + } + + if (strcmp(protocol, "vnc") == 0) { + return vnc_display_pw_expire(NULL, when); + } + + qerror_report(QERR_INVALID_PARAMETER, "protocol"); + return -1; +} + +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"); + int skipauth = qdict_get_try_bool(qdict, "skipauth", 0); + CharDriverState *s; + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); + return -1; + } + qerror_report(QERR_ADD_CLIENT_FAILED); + return -1; +#ifdef CONFIG_VNC + } else if (strcmp(protocol, "vnc") == 0) { + int fd = monitor_get_fd(mon, fdname); + 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, QObject **ret_data) +{ + const char *protocol = qdict_get_str(qdict, "protocol"); + const char *hostname = qdict_get_str(qdict, "hostname"); + const char *subject = qdict_get_try_str(qdict, "cert-subject"); + int port = qdict_get_try_int(qdict, "port", -1); + int tls_port = qdict_get_try_int(qdict, "tls-port", -1); + int ret; + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); + return -1; + } + + ret = qemu_spice_migrate_info(hostname, port, tls_port, subject); + if (ret != 0) { + qerror_report(QERR_UNDEFINED_ERROR); + return -1; + } + return 0; + } + + qerror_report(QERR_INVALID_PARAMETER, "protocol"); + return -1; +} + static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data) { vga_hw_screen_dump(qdict_get_str(qdict, "filename")); @@ -1071,7 +1291,7 @@ static void do_singlestep(Monitor *mon, const QDict *qdict) */ static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data) { - vm_stop(EXCP_INTERRUPT); + vm_stop(VMSTOP_USER); return 0; } @@ -1243,7 +1463,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize, if (l > line_size) l = line_size; if (is_physical) { - cpu_physical_memory_rw(addr, buf, l, 0); + cpu_physical_memory_read(addr, buf, l); } else { env = mon_get_cpu(); if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) { @@ -1419,7 +1639,7 @@ static int do_physical_memory_save(Monitor *mon, const QDict *qdict, l = sizeof(buf); if (l > size) l = size; - cpu_physical_memory_rw(addr, buf, l, 0); + cpu_physical_memory_read(addr, buf, l); if (fwrite(buf, 1, l, f) != l) { monitor_printf(mon, "fwrite() error in do_physical_memory_save\n"); goto exit; @@ -1439,17 +1659,16 @@ exit: static void do_sum(Monitor *mon, const QDict *qdict) { uint32_t addr; - uint8_t buf[1]; uint16_t sum; uint32_t start = qdict_get_int(qdict, "start"); uint32_t size = qdict_get_int(qdict, "size"); sum = 0; for(addr = start; addr < (start + size); addr++) { - cpu_physical_memory_rw(addr, buf, 1, 0); + uint8_t val = ldub_phys(addr); /* BSD sum algorithm ('sum' Unix command) */ sum = (sum >> 1) | (sum << 15); - sum += buf[0]; + sum += val; } monitor_printf(mon, "%05d\n", sum); } @@ -1689,7 +1908,7 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) kbd_put_keycode(keycode & 0x7f); } /* delayed key up events */ - qemu_mod_timer(key_timer, qemu_get_clock(vm_clock) + + qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + muldiv64(get_ticks_per_sec(), hold_time, 1000)); } @@ -1809,11 +2028,20 @@ static int do_system_powerdown(Monitor *mon, const QDict *qdict, } #if defined(TARGET_I386) -static void print_pte(Monitor *mon, uint32_t addr, uint32_t pte, uint32_t mask) +static void print_pte(Monitor *mon, target_phys_addr_t addr, + target_phys_addr_t pte, + target_phys_addr_t mask) { - monitor_printf(mon, "%08x: %08x %c%c%c%c%c%c%c%c\n", +#ifdef TARGET_X86_64 + if (addr & (1ULL << 47)) { + addr |= -1LL << 48; + } +#endif + monitor_printf(mon, TARGET_FMT_plx ": " TARGET_FMT_plx + " %c%c%c%c%c%c%c%c%c\n", addr, pte & mask, + pte & PG_NX_MASK ? 'X' : '-', pte & PG_GLOBAL_MASK ? 'G' : '-', pte & PG_PSE_MASK ? 'P' : '-', pte & PG_DIRTY_MASK ? 'D' : '-', @@ -1824,29 +2052,22 @@ static void print_pte(Monitor *mon, uint32_t addr, uint32_t pte, uint32_t mask) pte & PG_RW_MASK ? 'W' : '-'); } -static void tlb_info(Monitor *mon) +static void tlb_info_32(Monitor *mon, CPUState *env) { - CPUState *env; int l1, l2; uint32_t pgd, pde, pte; - env = mon_get_cpu(); - - if (!(env->cr[0] & CR0_PG_MASK)) { - monitor_printf(mon, "PG disabled\n"); - return; - } pgd = env->cr[3] & ~0xfff; for(l1 = 0; l1 < 1024; l1++) { - cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + cpu_physical_memory_read(pgd + l1 * 4, &pde, 4); pde = le32_to_cpu(pde); if (pde & PG_PRESENT_MASK) { if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - print_pte(mon, (l1 << 22), pde, ~((1 << 20) - 1)); + /* 4M pages */ + print_pte(mon, (l1 << 22), pde, ~((1 << 21) - 1)); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, - (uint8_t *)&pte, 4); + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4); pte = le32_to_cpu(pte); if (pte & PG_PRESENT_MASK) { print_pte(mon, (l1 << 22) + (l2 << 12), @@ -1859,14 +2080,137 @@ static void tlb_info(Monitor *mon) } } -static void mem_print(Monitor *mon, uint32_t *pstart, int *plast_prot, - uint32_t end, int prot) +static void tlb_info_pae32(Monitor *mon, CPUState *env) +{ + int l1, l2, l3; + uint64_t pdpe, pde, pte; + uint64_t pdp_addr, pd_addr, pt_addr; + + pdp_addr = env->cr[3] & ~0x1f; + for (l1 = 0; l1 < 4; l1++) { + cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8); + pdpe = le64_to_cpu(pdpe); + if (pdpe & PG_PRESENT_MASK) { + pd_addr = pdpe & 0x3fffffffff000ULL; + for (l2 = 0; l2 < 512; l2++) { + cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8); + pde = le64_to_cpu(pde); + if (pde & PG_PRESENT_MASK) { + 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)); + } else { + pt_addr = pde & 0x3fffffffff000ULL; + for (l3 = 0; l3 < 512; l3++) { + cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8); + pte = le64_to_cpu(pte); + if (pte & PG_PRESENT_MASK) { + print_pte(mon, (l1 << 30 ) + (l2 << 21) + + (l3 << 12), + pte & ~PG_PSE_MASK, + ~(target_phys_addr_t)0xfff); + } + } + } + } + } + } + } +} + +#ifdef TARGET_X86_64 +static void tlb_info_64(Monitor *mon, CPUState *env) +{ + uint64_t l1, l2, l3, l4; + uint64_t pml4e, pdpe, pde, pte; + uint64_t pml4_addr, pdp_addr, pd_addr, pt_addr; + + pml4_addr = env->cr[3] & 0x3fffffffff000ULL; + for (l1 = 0; l1 < 512; l1++) { + cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8); + pml4e = le64_to_cpu(pml4e); + if (pml4e & PG_PRESENT_MASK) { + pdp_addr = pml4e & 0x3fffffffff000ULL; + for (l2 = 0; l2 < 512; l2++) { + cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); + pdpe = le64_to_cpu(pdpe); + if (pdpe & PG_PRESENT_MASK) { + if (pdpe & PG_PSE_MASK) { + /* 1G pages, CR4.PSE is ignored */ + print_pte(mon, (l1 << 39) + (l2 << 30), pdpe, + 0x3ffffc0000000ULL); + } else { + pd_addr = pdpe & 0x3fffffffff000ULL; + for (l3 = 0; l3 < 512; l3++) { + cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); + pde = le64_to_cpu(pde); + if (pde & PG_PRESENT_MASK) { + if (pde & PG_PSE_MASK) { + /* 2M pages, CR4.PSE is ignored */ + print_pte(mon, (l1 << 39) + (l2 << 30) + + (l3 << 21), pde, + 0x3ffffffe00000ULL); + } else { + pt_addr = pde & 0x3fffffffff000ULL; + for (l4 = 0; l4 < 512; l4++) { + cpu_physical_memory_read(pt_addr + + l4 * 8, + &pte, 8); + pte = le64_to_cpu(pte); + if (pte & PG_PRESENT_MASK) { + print_pte(mon, (l1 << 39) + + (l2 << 30) + + (l3 << 21) + (l4 << 12), + pte & ~PG_PSE_MASK, + 0x3fffffffff000ULL); + } + } + } + } + } + } + } + } + } + } +} +#endif + +static void tlb_info(Monitor *mon) +{ + CPUState *env; + + env = mon_get_cpu(); + + if (!(env->cr[0] & CR0_PG_MASK)) { + monitor_printf(mon, "PG disabled\n"); + return; + } + if (env->cr[4] & CR4_PAE_MASK) { +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + tlb_info_64(mon, env); + } else +#endif + { + tlb_info_pae32(mon, env); + } + } else { + tlb_info_32(mon, env); + } +} + +static void mem_print(Monitor *mon, target_phys_addr_t *pstart, + int *plast_prot, + target_phys_addr_t end, int prot) { int prot1; prot1 = *plast_prot; if (prot != prot1) { if (*pstart != -1) { - monitor_printf(mon, "%08x-%08x %08x %c%c%c\n", + monitor_printf(mon, TARGET_FMT_plx "-" TARGET_FMT_plx " " + TARGET_FMT_plx " %c%c%c\n", *pstart, end, end - *pstart, prot1 & PG_USER_MASK ? 'u' : '-', 'r', @@ -1880,23 +2224,17 @@ static void mem_print(Monitor *mon, uint32_t *pstart, int *plast_prot, } } -static void mem_info(Monitor *mon) +static void mem_info_32(Monitor *mon, CPUState *env) { - CPUState *env; int l1, l2, prot, last_prot; - uint32_t pgd, pde, pte, start, end; - - env = mon_get_cpu(); + uint32_t pgd, pde, pte; + target_phys_addr_t start, end; - if (!(env->cr[0] & CR0_PG_MASK)) { - monitor_printf(mon, "PG disabled\n"); - return; - } pgd = env->cr[3] & ~0xfff; last_prot = 0; start = -1; for(l1 = 0; l1 < 1024; l1++) { - cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + cpu_physical_memory_read(pgd + l1 * 4, &pde, 4); pde = le32_to_cpu(pde); end = l1 << 22; if (pde & PG_PRESENT_MASK) { @@ -1905,8 +2243,7 @@ static void mem_info(Monitor *mon) mem_print(mon, &start, &last_prot, end, prot); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, - (uint8_t *)&pte, 4); + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4); pte = le32_to_cpu(pte); end = (l1 << 22) + (l2 << 12); if (pte & PG_PRESENT_MASK) { @@ -1923,6 +2260,157 @@ static void mem_info(Monitor *mon) } } } + +static void mem_info_pae32(Monitor *mon, CPUState *env) +{ + int l1, l2, l3, prot, last_prot; + uint64_t pdpe, pde, pte; + uint64_t pdp_addr, pd_addr, pt_addr; + target_phys_addr_t start, end; + + pdp_addr = env->cr[3] & ~0x1f; + last_prot = 0; + start = -1; + for (l1 = 0; l1 < 4; l1++) { + cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8); + pdpe = le64_to_cpu(pdpe); + end = l1 << 30; + if (pdpe & PG_PRESENT_MASK) { + pd_addr = pdpe & 0x3fffffffff000ULL; + for (l2 = 0; l2 < 512; l2++) { + cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8); + pde = le64_to_cpu(pde); + end = (l1 << 30) + (l2 << 21); + if (pde & PG_PRESENT_MASK) { + if (pde & PG_PSE_MASK) { + prot = pde & (PG_USER_MASK | PG_RW_MASK | + PG_PRESENT_MASK); + mem_print(mon, &start, &last_prot, end, prot); + } else { + pt_addr = pde & 0x3fffffffff000ULL; + for (l3 = 0; l3 < 512; l3++) { + cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8); + pte = le64_to_cpu(pte); + end = (l1 << 30) + (l2 << 21) + (l3 << 12); + if (pte & PG_PRESENT_MASK) { + prot = pte & (PG_USER_MASK | PG_RW_MASK | + PG_PRESENT_MASK); + } else { + prot = 0; + } + mem_print(mon, &start, &last_prot, end, prot); + } + } + } else { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + } + } + } else { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + } + } +} + + +#ifdef TARGET_X86_64 +static void mem_info_64(Monitor *mon, CPUState *env) +{ + int prot, last_prot; + uint64_t l1, l2, l3, l4; + uint64_t pml4e, pdpe, pde, pte; + uint64_t pml4_addr, pdp_addr, pd_addr, pt_addr, start, end; + + pml4_addr = env->cr[3] & 0x3fffffffff000ULL; + last_prot = 0; + start = -1; + for (l1 = 0; l1 < 512; l1++) { + cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8); + pml4e = le64_to_cpu(pml4e); + end = l1 << 39; + if (pml4e & PG_PRESENT_MASK) { + pdp_addr = pml4e & 0x3fffffffff000ULL; + for (l2 = 0; l2 < 512; l2++) { + cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); + pdpe = le64_to_cpu(pdpe); + end = (l1 << 39) + (l2 << 30); + if (pdpe & PG_PRESENT_MASK) { + if (pdpe & PG_PSE_MASK) { + prot = pdpe & (PG_USER_MASK | PG_RW_MASK | + PG_PRESENT_MASK); + mem_print(mon, &start, &last_prot, end, prot); + } else { + pd_addr = pdpe & 0x3fffffffff000ULL; + for (l3 = 0; l3 < 512; l3++) { + cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); + pde = le64_to_cpu(pde); + end = (l1 << 39) + (l2 << 30) + (l3 << 21); + if (pde & PG_PRESENT_MASK) { + if (pde & PG_PSE_MASK) { + prot = pde & (PG_USER_MASK | PG_RW_MASK | + PG_PRESENT_MASK); + mem_print(mon, &start, &last_prot, end, prot); + } else { + pt_addr = pde & 0x3fffffffff000ULL; + for (l4 = 0; l4 < 512; l4++) { + cpu_physical_memory_read(pt_addr + + l4 * 8, + &pte, 8); + pte = le64_to_cpu(pte); + end = (l1 << 39) + (l2 << 30) + + (l3 << 21) + (l4 << 12); + if (pte & PG_PRESENT_MASK) { + prot = pte & (PG_USER_MASK | PG_RW_MASK | + PG_PRESENT_MASK); + } else { + prot = 0; + } + mem_print(mon, &start, &last_prot, end, prot); + } + } + } else { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + } + } + } + } else { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + } + } + } else { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + } + } +} +#endif + +static void mem_info(Monitor *mon) +{ + CPUState *env; + + env = mon_get_cpu(); + + if (!(env->cr[0] & CR0_PG_MASK)) { + monitor_printf(mon, "PG disabled\n"); + return; + } + if (env->cr[4] & CR4_PAE_MASK) { +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + mem_info_64(mon, env); + } else +#endif + { + mem_info_pae32(mon, env); + } + } else { + mem_info_32(mon, env); + } +} #endif #if defined(TARGET_SH4) @@ -1954,6 +2442,15 @@ static void tlb_info(Monitor *mon) #endif +#if defined(TARGET_SPARC) +static void tlb_info(Monitor *mon) +{ + CPUState *env1 = mon_get_cpu(); + + dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1); +} +#endif + static void do_info_kvm_print(Monitor *mon, const QObject *data) { QDict *qdict; @@ -2072,24 +2569,30 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict) nchannels = has_channels ? nchannels : 2; if (wav_start_capture (s, path, freq, bits, nchannels)) { - monitor_printf(mon, "Faied to add wave capture\n"); + monitor_printf(mon, "Failed to add wave capture\n"); qemu_free (s); + return; } QLIST_INSERT_HEAD (&capture_head, s, entries); } #endif #if defined(TARGET_I386) -static void do_inject_nmi(Monitor *mon, const QDict *qdict) +static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data) { CPUState *env; - int cpu_index = qdict_get_int(qdict, "cpu_index"); - for (env = first_cpu; env != NULL; env = env->next_cpu) - if (env->cpu_index == cpu_index) { - cpu_interrupt(env, CPU_INTERRUPT_NMI); - break; - } + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu_interrupt(env, CPU_INTERRUPT_NMI); + } + + return 0; +} +#else +static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + qerror_report(QERR_UNSUPPORTED); + return -1; } #endif @@ -2234,12 +2737,18 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict) uint64_t mcg_status = qdict_get_int(qdict, "mcg_status"); uint64_t addr = qdict_get_int(qdict, "addr"); uint64_t misc = qdict_get_int(qdict, "misc"); + int flags = MCE_INJECT_UNCOND_AO; - for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) - if (cenv->cpu_index == cpu_index && cenv->mcg_cap) { - cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc); + if (qdict_get_try_bool(qdict, "broadcast", 0)) { + flags |= MCE_INJECT_BROADCAST; + } + for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { + if (cenv->cpu_index == cpu_index) { + cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc, + flags); break; } + } } #endif @@ -2305,7 +2814,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict) int saved_vm_running = vm_running; const char *name = qdict_get_str(qdict, "name"); - vm_stop(0); + vm_stop(VMSTOP_LOADVM); if (load_vmstate(name) == 0 && saved_vm_running) { vm_start(); @@ -2337,11 +2846,11 @@ int monitor_get_fd(Monitor *mon, const char *fdname) } static const mon_cmd_t mon_cmds[] = { -#include "qemu-monitor.h" +#include "hmp-commands.h" { NULL, NULL, }, }; -/* Please update qemu-monitor.hx when adding or changing commands */ +/* Please update hmp-commands.hx when adding or changing commands */ static const mon_cmd_t info_cmds[] = { { .name = "version", @@ -2351,14 +2860,6 @@ static const mon_cmd_t info_cmds[] = { .user_print = do_info_version_print, .mhandler.info_new = do_info_version, }, - { - .name = "commands", - .args_type = "", - .params = "", - .help = "list QMP available commands", - .user_print = monitor_user_noop, - .mhandler.info_new = do_info_commands, - }, { .name = "network", .args_type = "", @@ -2434,7 +2935,7 @@ static const mon_cmd_t info_cmds[] = { .user_print = do_pci_info_print, .mhandler.info_new = do_pci_info, }, -#if defined(TARGET_I386) || defined(TARGET_SH4) +#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) { .name = "tlb", .args_type = "", @@ -2540,6 +3041,16 @@ static const mon_cmd_t info_cmds[] = { .user_print = do_info_vnc_print, .mhandler.info_new = do_info_vnc, }, +#if defined(CONFIG_SPICE) + { + .name = "spice", + .args_type = "", + .params = "", + .help = "show the spice server status", + .user_print = do_info_spice_print, + .mhandler.info_new = do_info_spice, + }, +#endif { .name = "name", .args_type = "", @@ -2727,6 +3238,16 @@ static const mon_cmd_t qmp_query_cmds[] = { .user_print = do_info_vnc_print, .mhandler.info_new = do_info_vnc, }, +#if defined(CONFIG_SPICE) + { + .name = "spice", + .args_type = "", + .params = "", + .help = "show the spice server status", + .user_print = do_info_spice_print, + .mhandler.info_new = do_info_spice, + }, +#endif { .name = "name", .args_type = "", @@ -2967,7 +3488,7 @@ static const MonitorDef monitor_defs[] = { { "asr", offsetof(CPUState, asr) }, #endif /* Segment registers */ - { "sdr1", offsetof(CPUState, sdr1) }, + { "sdr1", offsetof(CPUState, spr[SPR_SDR1]) }, { "sr0", offsetof(CPUState, sr[0]) }, { "sr1", offsetof(CPUState, sr[1]) }, { "sr2", offsetof(CPUState, sr[2]) }, @@ -2984,7 +3505,76 @@ static const MonitorDef monitor_defs[] = { { "sr13", offsetof(CPUState, sr[13]) }, { "sr14", offsetof(CPUState, sr[14]) }, { "sr15", offsetof(CPUState, sr[15]) }, - /* Too lazy to put BATs and SPRs ... */ + /* Too lazy to put BATs... */ + { "pvr", offsetof(CPUState, spr[SPR_PVR]) }, + + { "srr0", offsetof(CPUState, spr[SPR_SRR0]) }, + { "srr1", offsetof(CPUState, spr[SPR_SRR1]) }, + { "sprg0", offsetof(CPUState, spr[SPR_SPRG0]) }, + { "sprg1", offsetof(CPUState, spr[SPR_SPRG1]) }, + { "sprg2", offsetof(CPUState, spr[SPR_SPRG2]) }, + { "sprg3", offsetof(CPUState, spr[SPR_SPRG3]) }, + { "sprg4", offsetof(CPUState, spr[SPR_SPRG4]) }, + { "sprg5", offsetof(CPUState, spr[SPR_SPRG5]) }, + { "sprg6", offsetof(CPUState, spr[SPR_SPRG6]) }, + { "sprg7", offsetof(CPUState, spr[SPR_SPRG7]) }, + { "pid", offsetof(CPUState, spr[SPR_BOOKE_PID]) }, + { "csrr0", offsetof(CPUState, spr[SPR_BOOKE_CSRR0]) }, + { "csrr1", offsetof(CPUState, spr[SPR_BOOKE_CSRR1]) }, + { "esr", offsetof(CPUState, spr[SPR_BOOKE_ESR]) }, + { "dear", offsetof(CPUState, spr[SPR_BOOKE_DEAR]) }, + { "mcsr", offsetof(CPUState, spr[SPR_BOOKE_MCSR]) }, + { "tsr", offsetof(CPUState, spr[SPR_BOOKE_TSR]) }, + { "tcr", offsetof(CPUState, spr[SPR_BOOKE_TCR]) }, + { "vrsave", offsetof(CPUState, spr[SPR_VRSAVE]) }, + { "pir", offsetof(CPUState, spr[SPR_BOOKE_PIR]) }, + { "mcsrr0", offsetof(CPUState, spr[SPR_BOOKE_MCSRR0]) }, + { "mcsrr1", offsetof(CPUState, spr[SPR_BOOKE_MCSRR1]) }, + { "decar", offsetof(CPUState, spr[SPR_BOOKE_DECAR]) }, + { "ivpr", offsetof(CPUState, spr[SPR_BOOKE_IVPR]) }, + { "epcr", offsetof(CPUState, spr[SPR_BOOKE_EPCR]) }, + { "sprg8", offsetof(CPUState, spr[SPR_BOOKE_SPRG8]) }, + { "ivor0", offsetof(CPUState, spr[SPR_BOOKE_IVOR0]) }, + { "ivor1", offsetof(CPUState, spr[SPR_BOOKE_IVOR1]) }, + { "ivor2", offsetof(CPUState, spr[SPR_BOOKE_IVOR2]) }, + { "ivor3", offsetof(CPUState, spr[SPR_BOOKE_IVOR3]) }, + { "ivor4", offsetof(CPUState, spr[SPR_BOOKE_IVOR4]) }, + { "ivor5", offsetof(CPUState, spr[SPR_BOOKE_IVOR5]) }, + { "ivor6", offsetof(CPUState, spr[SPR_BOOKE_IVOR6]) }, + { "ivor7", offsetof(CPUState, spr[SPR_BOOKE_IVOR7]) }, + { "ivor8", offsetof(CPUState, spr[SPR_BOOKE_IVOR8]) }, + { "ivor9", offsetof(CPUState, spr[SPR_BOOKE_IVOR9]) }, + { "ivor10", offsetof(CPUState, spr[SPR_BOOKE_IVOR10]) }, + { "ivor11", offsetof(CPUState, spr[SPR_BOOKE_IVOR11]) }, + { "ivor12", offsetof(CPUState, spr[SPR_BOOKE_IVOR12]) }, + { "ivor13", offsetof(CPUState, spr[SPR_BOOKE_IVOR13]) }, + { "ivor14", offsetof(CPUState, spr[SPR_BOOKE_IVOR14]) }, + { "ivor15", offsetof(CPUState, spr[SPR_BOOKE_IVOR15]) }, + { "ivor32", offsetof(CPUState, spr[SPR_BOOKE_IVOR32]) }, + { "ivor33", offsetof(CPUState, spr[SPR_BOOKE_IVOR33]) }, + { "ivor34", offsetof(CPUState, spr[SPR_BOOKE_IVOR34]) }, + { "ivor35", offsetof(CPUState, spr[SPR_BOOKE_IVOR35]) }, + { "ivor36", offsetof(CPUState, spr[SPR_BOOKE_IVOR36]) }, + { "ivor37", offsetof(CPUState, spr[SPR_BOOKE_IVOR37]) }, + { "mas0", offsetof(CPUState, spr[SPR_BOOKE_MAS0]) }, + { "mas1", offsetof(CPUState, spr[SPR_BOOKE_MAS1]) }, + { "mas2", offsetof(CPUState, spr[SPR_BOOKE_MAS2]) }, + { "mas3", offsetof(CPUState, spr[SPR_BOOKE_MAS3]) }, + { "mas4", offsetof(CPUState, spr[SPR_BOOKE_MAS4]) }, + { "mas6", offsetof(CPUState, spr[SPR_BOOKE_MAS6]) }, + { "mas7", offsetof(CPUState, spr[SPR_BOOKE_MAS7]) }, + { "mmucfg", offsetof(CPUState, spr[SPR_MMUCFG]) }, + { "tlb0cfg", offsetof(CPUState, spr[SPR_BOOKE_TLB0CFG]) }, + { "tlb1cfg", offsetof(CPUState, spr[SPR_BOOKE_TLB1CFG]) }, + { "epr", offsetof(CPUState, spr[SPR_BOOKE_EPR]) }, + { "eplc", offsetof(CPUState, spr[SPR_BOOKE_EPLC]) }, + { "epsc", offsetof(CPUState, spr[SPR_BOOKE_EPSC]) }, + { "svr", offsetof(CPUState, spr[SPR_E500_SVR]) }, + { "mcar", offsetof(CPUState, spr[SPR_Exxx_MCAR]) }, + { "pid1", offsetof(CPUState, spr[SPR_BOOKE_PID1]) }, + { "pid2", offsetof(CPUState, spr[SPR_BOOKE_PID2]) }, + { "hid0", offsetof(CPUState, spr[SPR_HID0]) }, + #elif defined(TARGET_SPARC) { "g0", offsetof(CPUState, gregs[0]) }, { "g1", offsetof(CPUState, gregs[1]) }, @@ -3711,7 +4301,29 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, qdict_put(qdict, key, qint_from_int(val)); } break; - case 'f': + case 'o': + { + int64_t val; + char *end; + + while (qemu_isspace(*p)) { + p++; + } + if (*typestr == '?') { + typestr++; + if (*p == '\0') { + break; + } + } + val = strtosz(p, &end); + if (val < 0) { + monitor_printf(mon, "invalid size\n"); + goto fail; + } + qdict_put(qdict, key, qint_from_int(val)); + p = end; + } + break; case 'T': { double val; @@ -3727,17 +4339,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, if (get_double(mon, &val, &p) < 0) { goto fail; } - if (c == 'f' && *p) { - switch (*p) { - case 'K': case 'k': - val *= 1 << 10; p++; break; - case 'M': case 'm': - val *= 1 << 20; p++; break; - case 'G': case 'g': - val *= 1 << 30; p++; break; - } - } - if (c == 'T' && p[0] && p[1] == 's') { + if (p[0] && p[1] == 's') { switch (*p) { case 'm': val /= 1e3; p += 2; break; @@ -3848,72 +4450,43 @@ void monitor_set_error(Monitor *mon, QError *qerror) static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret) { - if (monitor_ctrl_mode(mon)) { - if (ret && !monitor_has_error(mon)) { - /* - * If it returns failure, it must have passed on error. - * - * 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 - } else { - assert(!monitor_has_error(mon)); - QDECREF(mon->error); - mon->error = NULL; + if (ret && !monitor_has_error(mon)) { + /* + * If it returns failure, it must have passed on error. + * + * 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); } -} - -static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd, - const QDict *params) -{ - int ret; - QObject *data = NULL; - - mon_print_count_init(mon); - - ret = cmd->mhandler.cmd_new(mon, params, &data); - handler_audit(mon, cmd, ret); - if (monitor_ctrl_mode(mon)) { - /* Monitor Protocol */ - monitor_protocol_emitter(mon, data); - } else { - /* User Protocol */ - if (data) - cmd->user_print(mon, data); +#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)); } - - qobject_decref(data); +#endif } static void handle_user_command(Monitor *mon, const char *cmdline) @@ -3927,10 +4500,18 @@ static void handle_user_command(Monitor *mon, const char *cmdline) if (!cmd) goto out; - if (monitor_handler_is_async(cmd)) { + if (handler_is_async(cmd)) { user_async_cmd_handler(mon, cmd, qdict); - } else if (monitor_handler_ported(cmd)) { - monitor_call_handler(mon, cmd, qdict); + } else if (handler_is_qobject(cmd)) { + QObject *data = NULL; + + /* XXX: ignores the error code */ + cmd->mhandler.cmd_new(mon, qdict, &data); + assert(!monitor_has_error(mon)); + if (data) { + cmd->user_print(mon, data); + qobject_decref(data); + } } else { cmd->mhandler.cmd(mon, qdict); } @@ -3999,6 +4580,11 @@ static void file_completion(const char *input) d = readdir(ffs); if (!d) break; + + if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) { + continue; + } + if (strstart(d->d_name, file_prefix, NULL)) { memcpy(file, input, input_path_len); if (input_path_len < sizeof(file)) @@ -4223,13 +4809,13 @@ static int check_client_args_type(const QDict *client_args, case 'i': case 'l': case 'M': + case 'o': if (qobject_type(client_arg) != QTYPE_QINT) { qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name, "int"); return -1; } break; - case 'f': case 'T': if (qobject_type(client_arg) != QTYPE_QINT && qobject_type(client_arg) != QTYPE_QFLOAT) { @@ -4424,20 +5010,32 @@ static void qmp_call_query_cmd(Monitor *mon, const mon_cmd_t *cmd) { QObject *ret_data = NULL; - if (monitor_handler_is_async(cmd)) { + if (handler_is_async(cmd)) { qmp_async_info_handler(mon, cmd); if (monitor_has_error(mon)) { monitor_protocol_emitter(mon, NULL); } } else { cmd->mhandler.info_new(mon, &ret_data); - if (ret_data) { - monitor_protocol_emitter(mon, ret_data); - qobject_decref(ret_data); - } + monitor_protocol_emitter(mon, ret_data); + qobject_decref(ret_data); } } +static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd, + const QDict *params) +{ + 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); + qobject_decref(data); +} + static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) { int err; @@ -4472,19 +5070,13 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) goto err_out; } - /* - * XXX: We need this special case until QMP has its own dispatch table - */ - if (compare_cmd(cmd_name, "info")) { - qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); - goto err_out; - } else if (strstart(cmd_name, "query-", &query_cmd)) { + if (strstart(cmd_name, "query-", &query_cmd)) { cmd = qmp_find_query_cmd(query_cmd); } else { cmd = qmp_find_cmd(cmd_name); } - if (!cmd || !monitor_handler_ported(cmd) || monitor_cmd_user_only(cmd)) { + if (!cmd) { qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_out; } @@ -4504,14 +5096,14 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) if (query_cmd) { qmp_call_query_cmd(mon, cmd); - } else if (monitor_handler_is_async(cmd)) { + } else if (handler_is_async(cmd)) { err = qmp_async_cmd_handler(mon, cmd, args); if (err) { /* emit the error response */ goto err_out; } } else { - monitor_call_handler(mon, cmd, args); + qmp_call_cmd(mon, cmd, args); } goto out; @@ -4665,7 +5257,7 @@ void monitor_init(CharDriverState *chr, int flags) Monitor *mon; if (is_first_init) { - key_timer = qemu_new_timer(vm_clock, release_keys, NULL); + key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); is_first_init = 0; } @@ -4683,6 +5275,7 @@ void monitor_init(CharDriverState *chr, int flags) /* Control mode requires special handlers */ qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read, monitor_control_event, mon); + qemu_chr_set_echo(chr, true); } else { qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, monitor_event, mon);