X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=monitor.c;h=f5f4d0e084c722e385f2bff2a388446d0c81973c;hb=7591c5c19951def341139c3874bdc7289f9813d1;hp=b323af94ba6a30f338658f45caf66c82b8455e95;hpb=bb9ea79e7a177acce6f8017eef794662ee219c97;p=qemu diff --git a/monitor.c b/monitor.c index b323af9..f5f4d0e 100644 --- a/monitor.c +++ b/monitor.c @@ -23,10 +23,12 @@ */ #include #include "hw/hw.h" +#include "hw/qdev.h" #include "hw/usb.h" #include "hw/pcmcia.h" #include "hw/pc.h" #include "hw/pci.h" +#include "hw/watchdog.h" #include "gdbstub.h" #include "net.h" #include "qemu-char.h" @@ -42,6 +44,9 @@ #include "migration.h" #include "kvm.h" #include "acl.h" +#include "qint.h" +#include "qdict.h" +#include "qstring.h" //#define DEBUG //#define DEBUG_COMPLETION @@ -56,7 +61,9 @@ * 'l' target long (32 or 64 bit) * '/' optional gdb-like print format (like "/10x") * - * '?' optional type (for 'F', 's' and 'i') + * '?' optional type (for all types, except '/') + * '.' other form of optional type (for 'i' and 'l') + * '-' optional parameter (eg. '-f') * */ @@ -68,6 +75,14 @@ typedef struct mon_cmd_t { const char *help; } mon_cmd_t; +/* file descriptors passed via SCM_RIGHTS */ +typedef struct mon_fd_t mon_fd_t; +struct mon_fd_t { + char *name; + int fd; + LIST_ENTRY(mon_fd_t) next; +}; + struct Monitor { CharDriverState *chr; int flags; @@ -78,6 +93,7 @@ struct Monitor { CPUState *mon_cpu; BlockDriverCompletionFunc *password_completion_cb; void *password_opaque; + LIST_HEAD(,mon_fd_t) fds; LIST_ENTRY(Monitor) entry; }; @@ -240,21 +256,30 @@ static void help_cmd(Monitor *mon, const char *name) } } -static void do_commit(Monitor *mon, const char *device) +static void do_help_cmd(Monitor *mon, const QDict *qdict) +{ + help_cmd(mon, qdict_get_try_str(qdict, "name")); +} + +static void do_commit(Monitor *mon, const QDict *qdict) { - int i, all_devices; + int all_devices; + DriveInfo *dinfo; + const char *device = qdict_get_str(qdict, "device"); all_devices = !strcmp(device, "all"); - for (i = 0; i < nb_drives; i++) { - if (all_devices || - !strcmp(bdrv_get_device_name(drives_table[i].bdrv), device)) - bdrv_commit(drives_table[i].bdrv); + TAILQ_FOREACH(dinfo, &drives, next) { + if (!all_devices) + if (strcmp(bdrv_get_device_name(dinfo->bdrv), device)) + continue; + bdrv_commit(dinfo->bdrv); } } -static void do_info(Monitor *mon, const char *item) +static void do_info(Monitor *mon, const QDict *qdict) { const mon_cmd_t *cmd; + const char *item = qdict_get_try_str(qdict, "item"); void (*handler)(Monitor *); if (!item) @@ -318,7 +343,7 @@ static CPUState *mon_get_cpu(void) if (!cur_mon->mon_cpu) { mon_set_cpu(0); } - cpu_synchronize_state(cur_mon->mon_cpu, 0); + cpu_synchronize_state(cur_mon->mon_cpu); return cur_mon->mon_cpu; } @@ -345,7 +370,7 @@ static void do_info_cpus(Monitor *mon) mon_get_cpu(); for(env = first_cpu; env != NULL; env = env->next_cpu) { - cpu_synchronize_state(env, 0); + cpu_synchronize_state(env); monitor_printf(mon, "%c CPU #%d:", (env == mon->mon_cpu) ? '*' : ' ', env->cpu_index); @@ -366,8 +391,9 @@ static void do_info_cpus(Monitor *mon) } } -static void do_cpu_set(Monitor *mon, int index) +static void do_cpu_set(Monitor *mon, const QDict *qdict) { + int index = qdict_get_int(qdict, "index"); if (mon_set_cpu(index) < 0) monitor_printf(mon, "Invalid CPU index\n"); } @@ -405,7 +431,7 @@ static void do_info_cpu_stats(Monitor *mon) } #endif -static void do_quit(Monitor *mon) +static void do_quit(Monitor *mon, const QDict *qdict) { exit(0); } @@ -428,9 +454,11 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force) return 0; } -static void do_eject(Monitor *mon, int force, const char *filename) +static void do_eject(Monitor *mon, const QDict *qdict) { BlockDriverState *bs; + int force = qdict_get_int(qdict, "force"); + const char *filename = qdict_get_str(qdict, "filename"); bs = bdrv_find(filename); if (!bs) { @@ -491,9 +519,11 @@ static void do_change_vnc(Monitor *mon, const char *target, const char *arg) } } -static void do_change(Monitor *mon, const char *device, const char *target, - const char *arg) +static void do_change(Monitor *mon, const QDict *qdict) { + const char *device = qdict_get_str(qdict, "device"); + const char *target = qdict_get_str(qdict, "target"); + const char *arg = qdict_get_try_str(qdict, "arg"); if (strcmp(device, "vnc") == 0) { do_change_vnc(mon, target, arg); } else { @@ -501,19 +531,20 @@ static void do_change(Monitor *mon, const char *device, const char *target, } } -static void do_screen_dump(Monitor *mon, const char *filename) +static void do_screen_dump(Monitor *mon, const QDict *qdict) { - vga_hw_screen_dump(filename); + vga_hw_screen_dump(qdict_get_str(qdict, "filename")); } -static void do_logfile(Monitor *mon, const char *filename) +static void do_logfile(Monitor *mon, const QDict *qdict) { - cpu_set_log_filename(filename); + cpu_set_log_filename(qdict_get_str(qdict, "filename")); } -static void do_log(Monitor *mon, const char *items) +static void do_log(Monitor *mon, const QDict *qdict) { int mask; + const char *items = qdict_get_str(qdict, "items"); if (!strcmp(items, "none")) { mask = 0; @@ -527,8 +558,9 @@ static void do_log(Monitor *mon, const char *items) cpu_set_log(mask); } -static void do_singlestep(Monitor *mon, const char *option) +static void do_singlestep(Monitor *mon, const QDict *qdict) { + const char *option = qdict_get_try_str(qdict, "option"); if (!option || !strcmp(option, "on")) { singlestep = 1; } else if (!strcmp(option, "off")) { @@ -538,7 +570,7 @@ static void do_singlestep(Monitor *mon, const char *option) } } -static void do_stop(Monitor *mon) +static void do_stop(Monitor *mon, const QDict *qdict) { vm_stop(EXCP_INTERRUPT); } @@ -550,7 +582,7 @@ struct bdrv_iterate_context { int err; }; -static void do_cont(Monitor *mon) +static void do_cont(Monitor *mon, const QDict *qdict) { struct bdrv_iterate_context context = { mon, 0 }; @@ -566,7 +598,7 @@ static void bdrv_key_cb(void *opaque, int err) /* another key was set successfully, retry to continue */ if (!err) - do_cont(mon); + do_cont(mon, NULL); } static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs) @@ -580,9 +612,9 @@ static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs) } } -#ifdef CONFIG_GDBSTUB -static void do_gdbserver(Monitor *mon, const char *device) +static void do_gdbserver(Monitor *mon, const QDict *qdict) { + const char *device = qdict_get_try_str(qdict, "device"); if (!device) device = "tcp::" DEFAULT_GDBSTUB_PORT; if (gdbserver_start(device) < 0) { @@ -595,7 +627,14 @@ static void do_gdbserver(Monitor *mon, const char *device) device); } } -#endif + +static void do_watchdog_action(Monitor *mon, const QDict *qdict) +{ + const char *action = qdict_get_str(qdict, "action"); + if (select_watchdog_action(action) == -1) { + monitor_printf(mon, "Unknown watchdog action '%s'\n", action); + } +} static void monitor_printc(Monitor *mon, int c) { @@ -749,37 +788,31 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize, } } -#if TARGET_LONG_BITS == 64 -#define GET_TLONG(h, l) (((uint64_t)(h) << 32) | (l)) -#else -#define GET_TLONG(h, l) (l) -#endif - -static void do_memory_dump(Monitor *mon, int count, int format, int size, - uint32_t addrh, uint32_t addrl) +static void do_memory_dump(Monitor *mon, const QDict *qdict) { - target_long addr = GET_TLONG(addrh, addrl); + int count = qdict_get_int(qdict, "count"); + int format = qdict_get_int(qdict, "format"); + int size = qdict_get_int(qdict, "size"); + target_long addr = qdict_get_int(qdict, "addr"); + memory_dump(mon, count, format, size, addr, 0); } -#if TARGET_PHYS_ADDR_BITS > 32 -#define GET_TPHYSADDR(h, l) (((uint64_t)(h) << 32) | (l)) -#else -#define GET_TPHYSADDR(h, l) (l) -#endif - -static void do_physical_memory_dump(Monitor *mon, int count, int format, - int size, uint32_t addrh, uint32_t addrl) - +static void do_physical_memory_dump(Monitor *mon, const QDict *qdict) { - target_phys_addr_t addr = GET_TPHYSADDR(addrh, addrl); + 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"); + memory_dump(mon, count, format, size, addr, 1); } -static void do_print(Monitor *mon, int count, int format, int size, - unsigned int valh, unsigned int vall) +static void do_print(Monitor *mon, const QDict *qdict) { - target_phys_addr_t val = GET_TPHYSADDR(valh, vall); + int format = qdict_get_int(qdict, "format"); + target_phys_addr_t val = qdict_get_int(qdict, "val"); + #if TARGET_PHYS_ADDR_BITS == 32 switch(format) { case 'o': @@ -822,11 +855,12 @@ static void do_print(Monitor *mon, int count, int format, int size, monitor_printf(mon, "\n"); } -static void do_memory_save(Monitor *mon, unsigned int valh, unsigned int vall, - uint32_t size, const char *filename) +static void do_memory_save(Monitor *mon, const QDict *qdict) { FILE *f; - target_long addr = GET_TLONG(valh, vall); + uint32_t size = qdict_get_int(qdict, "size"); + const char *filename = qdict_get_str(qdict, "filename"); + target_long addr = qdict_get_int(qdict, "val"); uint32_t l; CPUState *env; uint8_t buf[1024]; @@ -852,14 +886,14 @@ static void do_memory_save(Monitor *mon, unsigned int valh, unsigned int vall, fclose(f); } -static void do_physical_memory_save(Monitor *mon, unsigned int valh, - unsigned int vall, uint32_t size, - const char *filename) +static void do_physical_memory_save(Monitor *mon, const QDict *qdict) { FILE *f; uint32_t l; uint8_t buf[1024]; - target_phys_addr_t addr = GET_TPHYSADDR(valh, vall); + uint32_t size = qdict_get_int(qdict, "size"); + const char *filename = qdict_get_str(qdict, "filename"); + target_phys_addr_t addr = qdict_get_int(qdict, "val"); f = fopen(filename, "wb"); if (!f) { @@ -879,11 +913,13 @@ static void do_physical_memory_save(Monitor *mon, unsigned int valh, fclose(f); } -static void do_sum(Monitor *mon, uint32_t start, uint32_t size) +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++) { @@ -1075,12 +1111,14 @@ static void release_keys(void *opaque) } } -static void do_sendkey(Monitor *mon, const char *string, int has_hold_time, - int hold_time) +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); @@ -1129,10 +1167,12 @@ static void do_sendkey(Monitor *mon, const char *string, int has_hold_time, static int mouse_button_state; -static void do_mouse_move(Monitor *mon, const char *dx_str, const char *dy_str, - const char *dz_str) +static void do_mouse_move(Monitor *mon, const QDict *qdict) { int dx, dy, dz; + const char *dx_str = qdict_get_str(qdict, "dx_str"); + const char *dy_str = qdict_get_str(qdict, "dy_str"); + const char *dz_str = qdict_get_try_str(qdict, "dz_str"); dx = strtol(dx_str, NULL, 0); dy = strtol(dy_str, NULL, 0); dz = 0; @@ -1141,20 +1181,24 @@ static void do_mouse_move(Monitor *mon, const char *dx_str, const char *dy_str, kbd_mouse_event(dx, dy, dz, mouse_button_state); } -static void do_mouse_button(Monitor *mon, int button_state) +static void do_mouse_button(Monitor *mon, const QDict *qdict) { + int button_state = qdict_get_int(qdict, "button_state"); mouse_button_state = button_state; kbd_mouse_event(0, 0, 0, mouse_button_state); } -static void do_ioport_read(Monitor *mon, int count, int format, int size, - int addr, int has_index, int index) +static void do_ioport_read(Monitor *mon, const QDict *qdict) { + int size = qdict_get_int(qdict, "size"); + int addr = qdict_get_int(qdict, "addr"); + int has_index = qdict_haskey(qdict, "index"); uint32_t val; int suffix; if (has_index) { - cpu_outb(NULL, addr & 0xffff, index & 0xff); + int index = qdict_get_int(qdict, "index"); + cpu_outb(NULL, addr & IOPORTS_MASK, index & 0xff); addr++; } addr &= 0xffff; @@ -1178,40 +1222,50 @@ static void do_ioport_read(Monitor *mon, int count, int format, int size, suffix, addr, size * 2, val); } -/* boot_set handler */ -static QEMUBootSetHandler *qemu_boot_set_handler = NULL; -static void *boot_opaque; - -void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque) +static void do_ioport_write(Monitor *mon, const QDict *qdict) { - qemu_boot_set_handler = func; - boot_opaque = opaque; + int size = qdict_get_int(qdict, "size"); + int addr = qdict_get_int(qdict, "addr"); + int val = qdict_get_int(qdict, "val"); + + addr &= IOPORTS_MASK; + + switch (size) { + default: + case 1: + cpu_outb(NULL, addr, val); + break; + case 2: + cpu_outw(NULL, addr, val); + break; + case 4: + cpu_outl(NULL, addr, val); + break; + } } -static void do_boot_set(Monitor *mon, const char *bootdevice) +static void do_boot_set(Monitor *mon, const QDict *qdict) { int res; + const char *bootdevice = qdict_get_str(qdict, "bootdevice"); - if (qemu_boot_set_handler) { - res = qemu_boot_set_handler(boot_opaque, bootdevice); - if (res == 0) - monitor_printf(mon, "boot device list now set to %s\n", - bootdevice); - else - monitor_printf(mon, "setting boot device list failed with " - "error %i\n", res); + res = qemu_boot_set(bootdevice); + if (res == 0) { + monitor_printf(mon, "boot device list now set to %s\n", bootdevice); + } else if (res > 0) { + monitor_printf(mon, "setting boot device list failed\n"); } else { monitor_printf(mon, "no function defined to set boot device list for " "this architecture\n"); } } -static void do_system_reset(Monitor *mon) +static void do_system_reset(Monitor *mon, const QDict *qdict) { qemu_system_reset_request(); } -static void do_system_powerdown(Monitor *mon) +static void do_system_powerdown(Monitor *mon, const QDict *qdict) { qemu_system_powerdown_request(); } @@ -1366,36 +1420,6 @@ static void tlb_info(Monitor *mon) #endif -static void do_info_kqemu(Monitor *mon) -{ -#ifdef CONFIG_KQEMU - CPUState *env; - int val; - val = 0; - env = mon_get_cpu(); - if (!env) { - monitor_printf(mon, "No cpu initialized yet"); - return; - } - val = env->kqemu_enabled; - monitor_printf(mon, "kqemu support: "); - switch(val) { - default: - case 0: - monitor_printf(mon, "disabled\n"); - break; - case 1: - monitor_printf(mon, "enabled for user code\n"); - break; - case 2: - monitor_printf(mon, "enabled for user and kernel code\n"); - break; - } -#else - monitor_printf(mon, "kqemu support: not compiled\n"); -#endif -} - static void do_info_kvm(Monitor *mon) { #ifdef CONFIG_KVM @@ -1409,15 +1433,26 @@ static void do_info_kvm(Monitor *mon) #endif } -#ifdef CONFIG_PROFILER +static void do_info_numa(Monitor *mon) +{ + int i; + CPUState *env; + + monitor_printf(mon, "%d nodes\n", nb_numa_nodes); + for (i = 0; i < nb_numa_nodes; i++) { + monitor_printf(mon, "node %d cpus:", i); + for (env = first_cpu; env != NULL; env = env->next_cpu) { + if (env->numa_node == i) { + monitor_printf(mon, " %d", env->cpu_index); + } + } + monitor_printf(mon, "\n"); + monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i, + node_mem[i] >> 20); + } +} -int64_t kqemu_time; -int64_t qemu_time; -int64_t kqemu_exec_count; -int64_t dev_time; -int64_t kqemu_ret_int_count; -int64_t kqemu_ret_excp_count; -int64_t kqemu_ret_intr_count; +#ifdef CONFIG_PROFILER static void do_info_profile(Monitor *mon) { @@ -1429,25 +1464,8 @@ static void do_info_profile(Monitor *mon) dev_time, dev_time / (double)ticks_per_sec); monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n", qemu_time, qemu_time / (double)ticks_per_sec); - monitor_printf(mon, "kqemu time %" PRId64 " (%0.3f %0.1f%%) count=%" - PRId64 " int=%" PRId64 " excp=%" PRId64 " intr=%" - PRId64 "\n", - kqemu_time, kqemu_time / (double)ticks_per_sec, - kqemu_time / (double)total * 100.0, - kqemu_exec_count, - kqemu_ret_int_count, - kqemu_ret_excp_count, - kqemu_ret_intr_count); qemu_time = 0; - kqemu_time = 0; - kqemu_exec_count = 0; dev_time = 0; - kqemu_ret_int_count = 0; - kqemu_ret_excp_count = 0; - kqemu_ret_intr_count = 0; -#ifdef CONFIG_KQEMU - kqemu_record_dump(); -#endif } #else static void do_info_profile(Monitor *mon) @@ -1470,9 +1488,11 @@ static void do_info_capture(Monitor *mon) } } -static void do_stop_capture(Monitor *mon, int n) +#ifdef HAS_AUDIO +static void do_stop_capture(Monitor *mon, const QDict *qdict) { int i; + int n = qdict_get_int(qdict, "n"); CaptureState *s; for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { @@ -1485,12 +1505,15 @@ static void do_stop_capture(Monitor *mon, int n) } } -#ifdef HAS_AUDIO -static void do_wav_capture(Monitor *mon, const char *path, - int has_freq, int freq, - int has_bits, int bits, - int has_channels, int nchannels) +static void do_wav_capture(Monitor *mon, const QDict *qdict) { + const char *path = qdict_get_str(qdict, "path"); + int has_freq = qdict_haskey(qdict, "freq"); + int freq = qdict_get_try_int(qdict, "freq", -1); + int has_bits = qdict_haskey(qdict, "bits"); + int bits = qdict_get_try_int(qdict, "bits", -1); + int has_channels = qdict_haskey(qdict, "nchannels"); + int nchannels = qdict_get_try_int(qdict, "nchannels", -1); CaptureState *s; s = qemu_mallocz (sizeof (*s)); @@ -1508,9 +1531,10 @@ static void do_wav_capture(Monitor *mon, const char *path, #endif #if defined(TARGET_I386) -static void do_inject_nmi(Monitor *mon, int cpu_index) +static void do_inject_nmi(Monitor *mon, const QDict *qdict) { 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) { @@ -1533,8 +1557,9 @@ static void do_info_status(Monitor *mon) } -static void do_balloon(Monitor *mon, int value) +static void do_balloon(Monitor *mon, const QDict *qdict) { + int value = qdict_get_int(qdict, "value"); ram_addr_t target = value; qemu_balloon(target << 20); } @@ -1553,60 +1578,85 @@ static void do_info_balloon(Monitor *mon) monitor_printf(mon, "balloon: actual=%d\n", (int)(actual >> 20)); } -static void do_acl(Monitor *mon, - const char *command, - const char *aclname, - const char *match, - int has_index, - int index) +static qemu_acl *find_acl(Monitor *mon, const char *name) { - qemu_acl *acl; + qemu_acl *acl = qemu_acl_find(name); - acl = qemu_acl_find(aclname); if (!acl) { - monitor_printf(mon, "acl: unknown list '%s'\n", aclname); - return; + monitor_printf(mon, "acl: unknown list '%s'\n", name); } + return acl; +} - if (strcmp(command, "show") == 0) { - int i = 0; - qemu_acl_entry *entry; +static void do_acl_show(Monitor *mon, const QDict *qdict) +{ + const char *aclname = qdict_get_str(qdict, "aclname"); + qemu_acl *acl = find_acl(mon, aclname); + qemu_acl_entry *entry; + int i = 0; + + if (acl) { monitor_printf(mon, "policy: %s\n", acl->defaultDeny ? "deny" : "allow"); TAILQ_FOREACH(entry, &acl->entries, next) { i++; monitor_printf(mon, "%d: %s %s\n", i, - entry->deny ? "deny" : "allow", - entry->match); + entry->deny ? "deny" : "allow", entry->match); } - } else if (strcmp(command, "reset") == 0) { + } +} + +static void do_acl_reset(Monitor *mon, const QDict *qdict) +{ + const char *aclname = qdict_get_str(qdict, "aclname"); + qemu_acl *acl = find_acl(mon, aclname); + + if (acl) { qemu_acl_reset(acl); monitor_printf(mon, "acl: removed all rules\n"); - } else if (strcmp(command, "policy") == 0) { - if (!match) { - monitor_printf(mon, "acl: missing policy parameter\n"); - return; - } + } +} + +static void do_acl_policy(Monitor *mon, const QDict *qdict) +{ + const char *aclname = qdict_get_str(qdict, "aclname"); + const char *policy = qdict_get_str(qdict, "policy"); + qemu_acl *acl = find_acl(mon, aclname); - if (strcmp(match, "allow") == 0) { + if (acl) { + if (strcmp(policy, "allow") == 0) { acl->defaultDeny = 0; monitor_printf(mon, "acl: policy set to 'allow'\n"); - } else if (strcmp(match, "deny") == 0) { + } else if (strcmp(policy, "deny") == 0) { acl->defaultDeny = 1; monitor_printf(mon, "acl: policy set to 'deny'\n"); } else { - monitor_printf(mon, "acl: unknown policy '%s', expected 'deny' or 'allow'\n", match); + monitor_printf(mon, "acl: unknown policy '%s', " + "expected 'deny' or 'allow'\n", policy); } - } else if ((strcmp(command, "allow") == 0) || - (strcmp(command, "deny") == 0)) { - int deny = strcmp(command, "deny") == 0 ? 1 : 0; - int ret; + } +} + +static void do_acl_add(Monitor *mon, const QDict *qdict) +{ + const char *aclname = qdict_get_str(qdict, "aclname"); + const char *match = qdict_get_str(qdict, "match"); + const char *policy = qdict_get_str(qdict, "policy"); + int has_index = qdict_haskey(qdict, "index"); + int index = qdict_get_try_int(qdict, "index", -1); + qemu_acl *acl = find_acl(mon, aclname); + int deny, ret; - if (!match) { - monitor_printf(mon, "acl: missing match parameter\n"); + if (acl) { + if (strcmp(policy, "allow") == 0) { + deny = 0; + } else if (strcmp(policy, "deny") == 0) { + deny = 1; + } else { + monitor_printf(mon, "acl: unknown policy '%s', " + "expected 'deny' or 'allow'\n", policy); return; } - if (has_index) ret = qemu_acl_insert(acl, deny, match, index); else @@ -1615,140 +1665,147 @@ static void do_acl(Monitor *mon, monitor_printf(mon, "acl: unable to add acl entry\n"); else monitor_printf(mon, "acl: added rule at position %d\n", ret); - } else if (strcmp(command, "remove") == 0) { - int ret; + } +} - if (!match) { - monitor_printf(mon, "acl: missing match parameter\n"); - return; - } +static void do_acl_remove(Monitor *mon, const QDict *qdict) +{ + const char *aclname = qdict_get_str(qdict, "aclname"); + const char *match = qdict_get_str(qdict, "match"); + qemu_acl *acl = find_acl(mon, aclname); + int ret; + if (acl) { ret = qemu_acl_remove(acl, match); if (ret < 0) monitor_printf(mon, "acl: no matching acl entry\n"); else monitor_printf(mon, "acl: removed rule at position %d\n", ret); - } else { - monitor_printf(mon, "acl: unknown command '%s'\n", command); } } -/* Please update qemu-doc.texi when adding or changing commands */ -static const mon_cmd_t mon_cmds[] = { - { "help|?", "s?", help_cmd, - "[cmd]", "show the help" }, - { "commit", "s", do_commit, - "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" }, - { "info", "s?", do_info, - "[subcommand]", "show various information about the system state" }, - { "q|quit", "", do_quit, - "", "quit the emulator" }, - { "eject", "-fB", do_eject, - "[-f] device", "eject a removable medium (use -f to force it)" }, - { "change", "BFs?", do_change, - "device filename [format]", "change a removable medium, optional format" }, - { "screendump", "F", do_screen_dump, - "filename", "save screen into PPM image 'filename'" }, - { "logfile", "F", do_logfile, - "filename", "output logs to 'filename'" }, - { "log", "s", do_log, - "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, - { "savevm", "s?", do_savevm, - "[tag|id]", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" }, - { "loadvm", "s", do_loadvm, - "tag|id", "restore a VM snapshot from its tag or id" }, - { "delvm", "s", do_delvm, - "tag|id", "delete a VM snapshot from its tag or id" }, - { "singlestep", "s?", do_singlestep, - "[on|off]", "run emulation in singlestep mode or switch to normal mode", }, - { "stop", "", do_stop, - "", "stop emulation", }, - { "c|cont", "", do_cont, - "", "resume emulation", }, -#ifdef CONFIG_GDBSTUB - { "gdbserver", "s?", do_gdbserver, - "[device]", "start gdbserver on given device (default 'tcp::1234'), stop with 'none'", }, -#endif - { "x", "/l", do_memory_dump, - "/fmt addr", "virtual memory dump starting at 'addr'", }, - { "xp", "/l", do_physical_memory_dump, - "/fmt addr", "physical memory dump starting at 'addr'", }, - { "p|print", "/l", do_print, - "/fmt expr", "print expression value (use $reg for CPU register access)", }, - { "i", "/ii.", do_ioport_read, - "/fmt addr", "I/O port read" }, - - { "sendkey", "si?", do_sendkey, - "keys [hold_ms]", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)" }, - { "system_reset", "", do_system_reset, - "", "reset the system" }, - { "system_powerdown", "", do_system_powerdown, - "", "send system power down event" }, - { "sum", "ii", do_sum, - "addr size", "compute the checksum of a memory region" }, - { "usb_add", "s", do_usb_add, - "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, - { "usb_del", "s", do_usb_del, - "device", "remove USB device 'bus.addr'" }, - { "cpu", "i", do_cpu_set, - "index", "set the default CPU" }, - { "mouse_move", "sss?", do_mouse_move, - "dx dy [dz]", "send mouse move events" }, - { "mouse_button", "i", do_mouse_button, - "state", "change mouse button state (1=L, 2=M, 4=R)" }, - { "mouse_set", "i", do_mouse_set, - "index", "set which mouse device receives events" }, -#ifdef HAS_AUDIO - { "wavcapture", "si?i?i?", do_wav_capture, - "path [frequency [bits [channels]]]", - "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" }, -#endif - { "stopcapture", "i", do_stop_capture, - "capture index", "stop capture" }, - { "memsave", "lis", do_memory_save, - "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", }, - { "pmemsave", "lis", do_physical_memory_save, - "addr size file", "save to disk physical memory dump starting at 'addr' of size 'size'", }, - { "boot_set", "s", do_boot_set, - "bootdevice", "define new values for the boot device list" }, #if defined(TARGET_I386) - { "nmi", "i", do_inject_nmi, - "cpu", "inject an NMI on the given CPU", }, -#endif - { "migrate", "-ds", do_migrate, - "[-d] uri", "migrate to URI (using -d to not wait for completion)" }, - { "migrate_cancel", "", do_migrate_cancel, - "", "cancel the current VM migration" }, - { "migrate_set_speed", "s", do_migrate_set_speed, - "value", "set maximum speed (in bytes) for migrations" }, -#if defined(TARGET_I386) - { "drive_add", "ss", drive_hot_add, "pci_addr=[[:]:]\n" - "[file=file][,if=type][,bus=n]\n" - "[,unit=m][,media=d][index=i]\n" - "[,cyls=c,heads=h,secs=s[,trans=t]]\n" - "[snapshot=on|off][,cache=on|off]", - "add drive to PCI storage controller" }, - { "pci_add", "sss", pci_device_hot_add, "pci_addr=auto|[[:]:] nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...", "hot-add PCI device" }, - { "pci_del", "s", pci_device_hot_remove, "pci_addr=[[:]:]", "hot remove PCI device" }, - { "host_net_add", "ss", net_host_device_add, - "[tap,user,socket,vde,dump] options", "add host VLAN client" }, - { "host_net_remove", "is", net_host_device_remove, - "vlan_id name", "remove host VLAN client" }, +static void do_inject_mce(Monitor *mon, const QDict *qdict) +{ + CPUState *cenv; + int cpu_index = qdict_get_int(qdict, "cpu_index"); + int bank = qdict_get_int(qdict, "bank"); + uint64_t status = qdict_get_int(qdict, "status"); + 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"); + + 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); + break; + } +} #endif - { "balloon", "i", do_balloon, - "target", "request VM to change it's memory allocation (in MB)" }, - { "set_link", "ss", do_set_link, - "name up|down", "change the link status of a network adapter" }, - { "acl", "sss?i?", do_acl, " [ []]\n", - "acl show vnc.username\n" - "acl policy vnc.username deny\n" - "acl allow vnc.username fred\n" - "acl deny vnc.username bob\n" - "acl reset vnc.username\n" }, + +static void do_getfd(Monitor *mon, const QDict *qdict) +{ + const char *fdname = qdict_get_str(qdict, "fdname"); + mon_fd_t *monfd; + int fd; + + fd = qemu_chr_get_msgfd(mon->chr); + if (fd == -1) { + monitor_printf(mon, "getfd: no file descriptor supplied via SCM_RIGHTS\n"); + return; + } + + if (qemu_isdigit(fdname[0])) { + monitor_printf(mon, "getfd: monitor names may not begin with a number\n"); + return; + } + + fd = dup(fd); + if (fd == -1) { + monitor_printf(mon, "Failed to dup() file descriptor: %s\n", + strerror(errno)); + return; + } + + LIST_FOREACH(monfd, &mon->fds, next) { + if (strcmp(monfd->name, fdname) != 0) { + continue; + } + + close(monfd->fd); + monfd->fd = fd; + return; + } + + monfd = qemu_mallocz(sizeof(mon_fd_t)); + monfd->name = qemu_strdup(fdname); + monfd->fd = fd; + + LIST_INSERT_HEAD(&mon->fds, monfd, next); +} + +static void do_closefd(Monitor *mon, const QDict *qdict) +{ + const char *fdname = qdict_get_str(qdict, "fdname"); + mon_fd_t *monfd; + + LIST_FOREACH(monfd, &mon->fds, next) { + if (strcmp(monfd->name, fdname) != 0) { + continue; + } + + LIST_REMOVE(monfd, next); + close(monfd->fd); + qemu_free(monfd->name); + qemu_free(monfd); + return; + } + + monitor_printf(mon, "Failed to find file descriptor named %s\n", + fdname); +} + +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); + + if (load_vmstate(mon, name) >= 0 && saved_vm_running) + vm_start(); +} + +int monitor_get_fd(Monitor *mon, const char *fdname) +{ + mon_fd_t *monfd; + + LIST_FOREACH(monfd, &mon->fds, next) { + int fd; + + if (strcmp(monfd->name, fdname) != 0) { + continue; + } + + fd = monfd->fd; + + /* caller takes ownership of fd */ + LIST_REMOVE(monfd, next); + qemu_free(monfd->name); + qemu_free(monfd); + + return fd; + } + + return -1; +} + +static const mon_cmd_t mon_cmds[] = { +#include "qemu-monitor.h" { NULL, NULL, }, }; -/* Please update qemu-doc.texi when adding or changing commands */ +/* Please update qemu-monitor.hx when adding or changing commands */ static const mon_cmd_t info_cmds[] = { { "version", "", do_info_version, "", "show the version of QEMU" }, @@ -1784,10 +1841,10 @@ static const mon_cmd_t info_cmds[] = { #endif { "jit", "", do_info_jit, "", "show dynamic compiler info", }, - { "kqemu", "", do_info_kqemu, - "", "show KQEMU information", }, { "kvm", "", do_info_kvm, "", "show KVM information", }, + { "numa", "", do_info_numa, + "", "show NUMA information", }, { "usb", "", usb_info, "", "show guest USB devices", }, { "usbhost", "", usb_host_info, @@ -1815,12 +1872,16 @@ static const mon_cmd_t info_cmds[] = { "", "show CPU statistics", }, #endif #if defined(CONFIG_SLIRP) - { "slirp", "", do_info_slirp, - "", "show SLIRP statistics", }, + { "usernet", "", do_info_usernet, + "", "show user network stack connection states", }, #endif { "migrate", "", do_info_migrate, "", "show migration status" }, { "balloon", "", do_info_balloon, "", "show balloon information" }, + { "qtree", "", do_info_qtree, + "", "show device tree" }, + { "qdm", "", do_info_qdm, + "", "show qdev device model list" }, { NULL, NULL, }, }; @@ -2209,7 +2270,7 @@ static int get_monitor_def(target_long *pval, const char *name) static void next(void) { - if (pch != '\0') { + if (*pch != '\0') { pch++; while (qemu_isspace(*pch)) pch++; @@ -2461,73 +2522,102 @@ static int get_str(char *buf, int buf_size, const char **pp) return 0; } +/* + * Store the command-name in cmdname, and return a pointer to + * the remaining of the command string. + */ +static const char *get_command_name(const char *cmdline, + char *cmdname, size_t nlen) +{ + size_t len; + const char *p, *pstart; + + p = cmdline; + while (qemu_isspace(*p)) + p++; + if (*p == '\0') + return NULL; + pstart = p; + while (*p != '\0' && *p != '/' && !qemu_isspace(*p)) + p++; + len = p - pstart; + if (len > nlen - 1) + len = nlen - 1; + memcpy(cmdname, pstart, len); + cmdname[len] = '\0'; + return p; +} + +/** + * Read key of 'type' into 'key' and return the current + * 'type' pointer. + */ +static char *key_get_info(const char *type, char **key) +{ + size_t len; + char *p, *str; + + if (*type == ',') + type++; + + p = strchr(type, ':'); + if (!p) { + *key = NULL; + return NULL; + } + len = p - type; + + str = qemu_malloc(len + 1); + memcpy(str, type, len); + str[len] = '\0'; + + *key = str; + return ++p; +} + static int default_fmt_format = 'x'; static int default_fmt_size = 4; #define MAX_ARGS 16 -static void monitor_handle_command(Monitor *mon, const char *cmdline) +static const mon_cmd_t *monitor_parse_command(Monitor *mon, + const char *cmdline, + QDict *qdict) { - const char *p, *pstart, *typestr; - char *q; - int c, nb_args, len, i, has_arg; + const char *p, *typestr; + int c; const mon_cmd_t *cmd; char cmdname[256]; char buf[1024]; - void *str_allocated[MAX_ARGS]; - void *args[MAX_ARGS]; - void (*handler_0)(Monitor *mon); - void (*handler_1)(Monitor *mon, void *arg0); - void (*handler_2)(Monitor *mon, void *arg0, void *arg1); - void (*handler_3)(Monitor *mon, void *arg0, void *arg1, void *arg2); - void (*handler_4)(Monitor *mon, void *arg0, void *arg1, void *arg2, - void *arg3); - void (*handler_5)(Monitor *mon, void *arg0, void *arg1, void *arg2, - void *arg3, void *arg4); - void (*handler_6)(Monitor *mon, void *arg0, void *arg1, void *arg2, - void *arg3, void *arg4, void *arg5); - void (*handler_7)(Monitor *mon, void *arg0, void *arg1, void *arg2, - void *arg3, void *arg4, void *arg5, void *arg6); + char *key; #ifdef DEBUG monitor_printf(mon, "command='%s'\n", cmdline); #endif /* extract the command name */ - p = cmdline; - q = cmdname; - while (qemu_isspace(*p)) - p++; - if (*p == '\0') - return; - pstart = p; - while (*p != '\0' && *p != '/' && !qemu_isspace(*p)) - p++; - len = p - pstart; - if (len > sizeof(cmdname) - 1) - len = sizeof(cmdname) - 1; - memcpy(cmdname, pstart, len); - cmdname[len] = '\0'; + p = get_command_name(cmdline, cmdname, sizeof(cmdname)); + if (!p) + return NULL; /* find the command */ for(cmd = mon_cmds; cmd->name != NULL; cmd++) { if (compare_cmd(cmdname, cmd->name)) - goto found; + break; } - monitor_printf(mon, "unknown command: '%s'\n", cmdname); - return; - found: - for(i = 0; i < MAX_ARGS; i++) - str_allocated[i] = NULL; + if (cmd->name == NULL) { + monitor_printf(mon, "unknown command: '%s'\n", cmdname); + return NULL; + } /* parse the parameters */ typestr = cmd->args_type; - nb_args = 0; for(;;) { - c = *typestr; - if (c == '\0') + typestr = key_get_info(typestr, &key); + if (!typestr) break; + c = *typestr; typestr++; switch(c) { case 'F': @@ -2535,7 +2625,6 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) case 's': { int ret; - char *str; while (qemu_isspace(*p)) p++; @@ -2543,8 +2632,7 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) typestr++; if (*p == '\0') { /* no optional string: NULL argument */ - str = NULL; - goto add_str; + break; } } ret = get_str(buf, sizeof(buf), &p); @@ -2564,16 +2652,7 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) } goto fail; } - str = qemu_malloc(strlen(buf) + 1); - pstrcpy(str, sizeof(buf), buf); - str_allocated[nb_args] = str; - add_str: - if (nb_args >= MAX_ARGS) { - error_args: - monitor_printf(mon, "%s: too many arguments\n", cmdname); - goto fail; - } - args[nb_args++] = str; + qdict_put(qdict, key, qstring_from_str(buf)); } break; case '/': @@ -2650,11 +2729,9 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) size = -1; } } - if (nb_args + 3 > MAX_ARGS) - goto error_args; - args[nb_args++] = (void*)(long)count; - args[nb_args++] = (void*)(long)format; - args[nb_args++] = (void*)(long)size; + qdict_put(qdict, "count", qint_from_int(count)); + qdict_put(qdict, "format", qint_from_int(format)); + qdict_put(qdict, "size", qint_from_int(size)); } break; case 'i': @@ -2666,48 +2743,31 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) p++; if (*typestr == '?' || *typestr == '.') { if (*typestr == '?') { - if (*p == '\0') - has_arg = 0; - else - has_arg = 1; + if (*p == '\0') { + typestr++; + break; + } } else { if (*p == '.') { p++; while (qemu_isspace(*p)) p++; - has_arg = 1; } else { - has_arg = 0; + typestr++; + break; } } typestr++; - if (nb_args >= MAX_ARGS) - goto error_args; - args[nb_args++] = (void *)(long)has_arg; - if (!has_arg) { - if (nb_args >= MAX_ARGS) - goto error_args; - val = -1; - goto add_num; - } } if (get_expr(mon, &val, &p)) goto fail; - add_num: - if (c == 'i') { - if (nb_args >= MAX_ARGS) - goto error_args; - args[nb_args++] = (void *)(long)val; - } else { - if ((nb_args + 1) >= MAX_ARGS) - goto error_args; -#if TARGET_PHYS_ADDR_BITS > 32 - args[nb_args++] = (void *)(long)((val >> 32) & 0xffffffff); -#else - args[nb_args++] = (void *)0; -#endif - args[nb_args++] = (void *)(long)(val & 0xffffffff); + /* Check if 'i' is greater than 32-bit */ + if ((c == 'i') && ((val >> 32) & 0xffffffff)) { + monitor_printf(mon, "\'%s\' has failed: ", cmdname); + monitor_printf(mon, "integer is for 32-bit values\n"); + goto fail; } + qdict_put(qdict, key, qint_from_int(val)); } break; case '-': @@ -2731,9 +2791,7 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) p++; has_option = 1; } - if (nb_args >= MAX_ARGS) - goto error_args; - args[nb_args++] = (void *)(long)has_option; + qdict_put(qdict, key, qint_from_int(has_option)); } break; default: @@ -2741,6 +2799,8 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) monitor_printf(mon, "%s: unknown type '%c'\n", cmdname, c); goto fail; } + qemu_free(key); + key = NULL; } /* check that all arguments were parsed */ while (qemu_isspace(*p)) @@ -2751,48 +2811,33 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) goto fail; } - switch(nb_args) { - case 0: - handler_0 = cmd->handler; - handler_0(mon); - break; - case 1: - handler_1 = cmd->handler; - handler_1(mon, args[0]); - break; - case 2: - handler_2 = cmd->handler; - handler_2(mon, args[0], args[1]); - break; - case 3: - handler_3 = cmd->handler; - handler_3(mon, args[0], args[1], args[2]); - break; - case 4: - handler_4 = cmd->handler; - handler_4(mon, args[0], args[1], args[2], args[3]); - break; - case 5: - handler_5 = cmd->handler; - handler_5(mon, args[0], args[1], args[2], args[3], args[4]); - break; - case 6: - handler_6 = cmd->handler; - handler_6(mon, args[0], args[1], args[2], args[3], args[4], args[5]); - break; - case 7: - handler_7 = cmd->handler; - handler_7(mon, args[0], args[1], args[2], args[3], args[4], args[5], - args[6]); - break; - default: - monitor_printf(mon, "unsupported number of arguments: %d\n", nb_args); - goto fail; + return cmd; + +fail: + qemu_free(key); + return NULL; +} + +static void monitor_handle_command(Monitor *mon, const char *cmdline) +{ + QDict *qdict; + const mon_cmd_t *cmd; + + qdict = qdict_new(); + + cmd = monitor_parse_command(mon, cmdline, qdict); + if (cmd) { + void (*handler)(Monitor *mon, const QDict *qdict); + + qemu_errors_to_mon(mon); + + handler = cmd->handler; + handler(mon, qdict); + + qemu_errors_to_previous(); } - fail: - for(i = 0; i < MAX_ARGS; i++) - qemu_free(str_allocated[i]); - return; + + QDECREF(qdict); } static void cmd_completion(const char *name, const char *list) @@ -2909,6 +2954,12 @@ static void parse_cmdline(const char *cmdline, *pnb_args = nb_args; } +static const char *next_arg_type(const char *typestr) +{ + const char *p = strchr(typestr, ':'); + return (p != NULL ? ++p : typestr); +} + static void monitor_find_completion(const char *cmdline) { const char *cmdname; @@ -2951,15 +3002,18 @@ static void monitor_find_completion(const char *cmdline) } return; found: - ptype = cmd->args_type; + ptype = next_arg_type(cmd->args_type); for(i = 0; i < nb_args - 2; i++) { if (*ptype != '\0') { - ptype++; + ptype = next_arg_type(ptype); while (*ptype == '?') - ptype++; + ptype = next_arg_type(ptype); } } str = args[nb_args - 1]; + if (*ptype == '-' && ptype[1] != '\0') { + ptype += 2; + } switch(*ptype) { case 'F': /* file completion */ @@ -2986,6 +3040,11 @@ static void monitor_find_completion(const char *cmdline) for(key = key_defs; key->name != NULL; key++) { cmd_completion(str, key->name); } + } else if (!strcmp(cmd->name, "help|?")) { + readline_set_completion_index(cur_mon->rs, strlen(str)); + for (cmd = mon_cmds; cmd->name != NULL; cmd++) { + cmd_completion(str, cmd->name); + } } break; default: @@ -3149,3 +3208,69 @@ void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, if (err && completion_cb) completion_cb(opaque, err); } + +typedef struct QemuErrorSink QemuErrorSink; +struct QemuErrorSink { + enum { + ERR_SINK_FILE, + ERR_SINK_MONITOR, + } dest; + union { + FILE *fp; + Monitor *mon; + }; + QemuErrorSink *previous; +}; + +static QemuErrorSink *qemu_error_sink; + +void qemu_errors_to_file(FILE *fp) +{ + QemuErrorSink *sink; + + sink = qemu_mallocz(sizeof(*sink)); + sink->dest = ERR_SINK_FILE; + sink->fp = fp; + sink->previous = qemu_error_sink; + qemu_error_sink = sink; +} + +void qemu_errors_to_mon(Monitor *mon) +{ + QemuErrorSink *sink; + + sink = qemu_mallocz(sizeof(*sink)); + sink->dest = ERR_SINK_MONITOR; + sink->mon = mon; + sink->previous = qemu_error_sink; + qemu_error_sink = sink; +} + +void qemu_errors_to_previous(void) +{ + QemuErrorSink *sink; + + assert(qemu_error_sink != NULL); + sink = qemu_error_sink; + qemu_error_sink = sink->previous; + qemu_free(sink); +} + +void qemu_error(const char *fmt, ...) +{ + va_list args; + + assert(qemu_error_sink != NULL); + switch (qemu_error_sink->dest) { + case ERR_SINK_FILE: + va_start(args, fmt); + vfprintf(qemu_error_sink->fp, fmt, args); + va_end(args); + break; + case ERR_SINK_MONITOR: + va_start(args, fmt); + monitor_vprintf(qemu_error_sink->mon, fmt, args); + va_end(args); + break; + } +}