X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/6a15fd12ca1bccb72335132686db7adef5937a0a..006f3a48e0793caae62c002636c9cd0c5334ae24:/monitor.c diff --git a/monitor.c b/monitor.c index 3c0fd916fa..354a792d40 100644 --- a/monitor.c +++ b/monitor.c @@ -1,8 +1,8 @@ /* * QEMU monitor - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -21,20 +21,31 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw/hw.h" +#include "hw/usb.h" +#include "hw/pcmcia.h" +#include "hw/pc.h" +#include "hw/pci.h" +#include "gdbstub.h" +#include "net.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "console.h" +#include "block.h" +#include "audio/audio.h" #include "disas.h" +#include "balloon.h" #include +#include "qemu-timer.h" +#include "migration.h" +#include "kvm.h" //#define DEBUG //#define DEBUG_COMPLETION -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - /* * Supported types: - * + * * 'F' filename * 'B' block device name * 's' string (accept optional quote) @@ -49,27 +60,32 @@ typedef struct term_cmd_t { const char *name; const char *args_type; - void (*handler)(); + void *handler; const char *params; const char *help; } term_cmd_t; -static CharDriverState *monitor_hd; +#define MAX_MON 4 +static CharDriverState *monitor_hd[MAX_MON]; +static int hide_banner; -static term_cmd_t term_cmds[]; -static term_cmd_t info_cmds[]; +static const term_cmd_t term_cmds[]; +static const term_cmd_t info_cmds[]; -static char term_outbuf[1024]; +static uint8_t term_outbuf[1024]; static int term_outbuf_index; static void monitor_start_input(void); -CPUState *mon_cpu = NULL; +static CPUState *mon_cpu = NULL; void term_flush(void) { + int i; if (term_outbuf_index > 0) { - qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); + for (i = 0; i < MAX_MON; i++) + if (monitor_hd[i] && monitor_hd[i]->focus == 0) + qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index); term_outbuf_index = 0; } } @@ -77,13 +93,15 @@ void term_flush(void) /* flush at every end of line or if the buffer is full */ void term_puts(const char *str) { - int c; + char c; for(;;) { c = *str++; if (c == '\0') break; + if (c == '\n') + term_outbuf[term_outbuf_index++] = '\r'; term_outbuf[term_outbuf_index++] = c; - if (term_outbuf_index >= sizeof(term_outbuf) || + if (term_outbuf_index >= (sizeof(term_outbuf) - 1) || c == '\n') term_flush(); } @@ -104,6 +122,33 @@ void term_printf(const char *fmt, ...) va_end(ap); } +void term_print_filename(const char *filename) +{ + int i; + + for (i = 0; filename[i]; i++) { + switch (filename[i]) { + case ' ': + case '"': + case '\\': + term_printf("\\%c", filename[i]); + break; + case '\t': + term_printf("\\t"); + break; + case '\r': + term_printf("\\r"); + break; + case '\n': + term_printf("\\n"); + break; + default: + term_printf("%c", filename[i]); + break; + } + } +} + static int monitor_fprintf(FILE *stream, const char *fmt, ...) { va_list ap; @@ -133,9 +178,9 @@ static int compare_cmd(const char *name, const char *list) return 0; } -static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name) +static void help_cmd1(const term_cmd_t *cmds, const char *prefix, const char *name) { - term_cmd_t *cmd; + const term_cmd_t *cmd; for(cmd = cmds; cmd->name != NULL; cmd++) { if (!name || !strcmp(name, cmd->name)) @@ -150,7 +195,7 @@ static void help_cmd(const char *name) } else { help_cmd1(term_cmds, "", name); if (name && !strcmp(name, "log")) { - CPULogItem *item; + const CPULogItem *item; term_printf("Log items (comma separated):\n"); term_printf("%-10s %s\n", "none", "remove all logs"); for(item = cpu_log_items; item->mask != 0; item++) { @@ -165,32 +210,35 @@ static void do_help(const char *name) help_cmd(name); } -static void do_commit(void) +static void do_commit(const char *device) { - int i; + int i, all_devices; - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) { - bdrv_commit(bs_table[i]); - } + 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); } } static void do_info(const char *item) { - term_cmd_t *cmd; + const term_cmd_t *cmd; + void (*handler)(void); if (!item) goto help; for(cmd = info_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(item, cmd->name)) + if (compare_cmd(item, cmd->name)) goto found; } help: help_cmd("info"); return; found: - cmd->handler(); + handler = cmd->handler; + handler(); } static void do_info_version(void) @@ -198,13 +246,40 @@ static void do_info_version(void) term_printf("%s\n", QEMU_VERSION); } +static void do_info_name(void) +{ + if (qemu_name) + term_printf("%s\n", qemu_name); +} + +#if defined(TARGET_I386) +static void do_info_hpet(void) +{ + term_printf("HPET is %s by QEMU\n", (no_hpet) ? "disabled" : "enabled"); +} +#endif + +static void do_info_uuid(void) +{ + term_printf(UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], + qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], + qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], + qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], + qemu_uuid[15]); +} + static void do_info_block(void) { bdrv_info(); } +static void do_info_blockstats(void) +{ + bdrv_info_stats(); +} + /* get the current CPU defined by the user */ -int mon_set_cpu(int cpu_index) +static int mon_set_cpu(int cpu_index) { CPUState *env; @@ -217,7 +292,7 @@ int mon_set_cpu(int cpu_index) return -1; } -CPUState *mon_get_cpu(void) +static CPUState *mon_get_cpu(void) { if (!mon_cpu) { mon_set_cpu(0); @@ -235,7 +310,7 @@ static void do_info_registers(void) cpu_dump_state(env, NULL, monitor_fprintf, X86_DUMP_FPU); #else - cpu_dump_state(env, NULL, monitor_fprintf, + cpu_dump_state(env, NULL, monitor_fprintf, 0); #endif } @@ -248,22 +323,20 @@ static void do_info_cpus(void) mon_get_cpu(); for(env = first_cpu; env != NULL; env = env->next_cpu) { - term_printf("%c CPU #%d:", + term_printf("%c CPU #%d:", (env == mon_cpu) ? '*' : ' ', env->cpu_index); #if defined(TARGET_I386) term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base); - if (env->hflags & HF_HALTED_MASK) - term_printf(" (halted)"); #elif defined(TARGET_PPC) term_printf(" nip=0x" TARGET_FMT_lx, env->nip); - if (env->halted) - term_printf(" (halted)"); #elif defined(TARGET_SPARC) term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc); +#elif defined(TARGET_MIPS) + term_printf(" PC=0x" TARGET_FMT_lx, env->active_tc.PC); +#endif if (env->halted) term_printf(" (halted)"); -#endif term_printf("\n"); } } @@ -283,7 +356,7 @@ static void do_info_history (void) { int i; const char *str; - + i = 0; for(;;) { str = readline_get_history(i); @@ -294,6 +367,17 @@ static void do_info_history (void) } } +#if defined(TARGET_PPC) +/* XXX: not implemented in other targets */ +static void do_info_cpu_stats (void) +{ + CPUState *env; + + env = mon_get_cpu(); + cpu_dump_statistics(env, NULL, &monitor_fprintf, 0); +} +#endif + static void do_quit(void) { exit(0); @@ -329,28 +413,53 @@ static void do_eject(int force, const char *filename) eject_device(bs, force); } -static void do_change(const char *device, const char *filename) +static void do_change_block(const char *device, const char *filename, const char *fmt) { BlockDriverState *bs; - int i; - char password[256]; + BlockDriver *drv = NULL; bs = bdrv_find(device); if (!bs) { term_printf("device not found\n"); return; } + if (fmt) { + drv = bdrv_find_format(fmt); + if (!drv) { + term_printf("invalid format %s\n", fmt); + return; + } + } if (eject_device(bs, 0) < 0) return; - bdrv_open(bs, filename, 0); - if (bdrv_is_encrypted(bs)) { - term_printf("%s is encrypted.\n", device); - for(i = 0; i < 3; i++) { - monitor_readline("Password: ", 1, password, sizeof(password)); - if (bdrv_set_key(bs, password) == 0) - break; - term_printf("invalid password\n"); - } + bdrv_open2(bs, filename, 0, drv); + qemu_key_check(bs, filename); +} + +static void do_change_vnc(const char *target, const char *arg) +{ + if (strcmp(target, "passwd") == 0 || + strcmp(target, "password") == 0) { + char password[9]; + if (arg) { + strncpy(password, arg, sizeof(password)); + password[sizeof(password) - 1] = '\0'; + } else + monitor_readline("Password: ", 1, password, sizeof(password)); + if (vnc_display_password(NULL, password) < 0) + term_printf("could not set VNC server password\n"); + } else { + if (vnc_display_open(NULL, target) < 0) + term_printf("could not start VNC server on %s\n", target); + } +} + +static void do_change(const char *device, const char *target, const char *arg) +{ + if (strcmp(device, "vnc") == 0) { + do_change_vnc(target, arg); + } else { + do_change_block(device, target, arg); } } @@ -359,10 +468,15 @@ static void do_screen_dump(const char *filename) vga_hw_screen_dump(filename); } +static void do_logfile(const char *filename) +{ + cpu_set_log_filename(filename); +} + static void do_log(const char *items) { int mask; - + if (!strcmp(items, "none")) { mask = 0; } else { @@ -375,18 +489,6 @@ static void do_log(const char *items) cpu_set_log(mask); } -static void do_savevm(const char *filename) -{ - if (qemu_savevm(filename) < 0) - term_printf("I/O error when saving VM to '%s'\n", filename); -} - -static void do_loadvm(const char *filename) -{ - if (qemu_loadvm(filename) < 0) - term_printf("I/O error when loading VM from '%s'\n", filename); -} - static void do_stop(void) { vm_stop(EXCP_INTERRUPT); @@ -398,14 +500,14 @@ static void do_cont(void) } #ifdef CONFIG_GDBSTUB -static void do_gdbserver(int has_port, int port) +static void do_gdbserver(const char *port) { - if (!has_port) + if (!port) port = DEFAULT_GDBSTUB_PORT; if (gdbserver_start(port) < 0) { - qemu_printf("Could not open gdbserver socket on port %d\n", port); + qemu_printf("Could not open gdbserver socket on port '%s'\n", port); } else { - qemu_printf("Waiting gdb connection on port %d\n", port); + qemu_printf("Waiting gdb connection on port '%s'\n", port); } } #endif @@ -437,8 +539,8 @@ static void term_printc(int c) term_printf("'"); } -static void memory_dump(int count, int format, int wsize, - target_ulong addr, int is_physical) +static void memory_dump(int count, int format, int wsize, + target_phys_addr_t addr, int is_physical) { CPUState *env; int nb_per_line, l, line_size, i, max_digits, len; @@ -461,7 +563,7 @@ static void memory_dump(int count, int format, int wsize, flags = 0; if (env) { #ifdef TARGET_X86_64 - if ((env->efer & MSR_EFER_LMA) && + if ((env->efer & MSR_EFER_LMA) && (env->segs[R_CS].flags & DESC_L_MASK)) flags = 2; else @@ -501,7 +603,10 @@ static void memory_dump(int count, int format, int wsize, } while (len > 0) { - term_printf(TARGET_FMT_lx ":", addr); + if (is_physical) + term_printf(TARGET_FMT_plx ":", addr); + else + term_printf(TARGET_FMT_lx ":", (target_ulong)addr); l = len; if (l > line_size) l = line_size; @@ -511,9 +616,12 @@ static void memory_dump(int count, int format, int wsize, env = mon_get_cpu(); if (!env) break; - cpu_memory_rw_debug(env, addr, buf, l, 0); + if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) { + term_printf(" Cannot access memory\n"); + break; + } } - i = 0; + i = 0; while (i < l) { switch(wsize) { default: @@ -533,16 +641,16 @@ static void memory_dump(int count, int format, int wsize, term_printf(" "); switch(format) { case 'o': - term_printf("%#*llo", max_digits, v); + term_printf("%#*" PRIo64, max_digits, v); break; case 'x': - term_printf("0x%0*llx", max_digits, v); + term_printf("0x%0*" PRIx64, max_digits, v); break; case 'u': - term_printf("%*llu", max_digits, v); + term_printf("%*" PRIu64, max_digits, v); break; case 'd': - term_printf("%*lld", max_digits, v); + term_printf("%*" PRId64, max_digits, v); break; case 'c': term_printc(v); @@ -562,25 +670,31 @@ static void memory_dump(int count, int format, int wsize, #define GET_TLONG(h, l) (l) #endif -static void do_memory_dump(int count, int format, int size, +static void do_memory_dump(int count, int format, int size, uint32_t addrh, uint32_t addrl) { target_long addr = GET_TLONG(addrh, addrl); memory_dump(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(int count, int format, int size, uint32_t addrh, uint32_t addrl) { - target_long addr = GET_TLONG(addrh, addrl); + target_phys_addr_t addr = GET_TPHYSADDR(addrh, addrl); memory_dump(count, format, size, addr, 1); } static void do_print(int count, int format, int size, unsigned int valh, unsigned int vall) { - target_long val = GET_TLONG(valh, vall); -#if TARGET_LONG_BITS == 32 + target_phys_addr_t val = GET_TPHYSADDR(valh, vall); +#if TARGET_PHYS_ADDR_BITS == 32 switch(format) { case 'o': term_printf("%#o", val); @@ -602,17 +716,17 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne #else switch(format) { case 'o': - term_printf("%#llo", val); + term_printf("%#" PRIo64, val); break; case 'x': - term_printf("%#llx", val); + term_printf("%#" PRIx64, val); break; case 'u': - term_printf("%llu", val); + term_printf("%" PRIu64, val); break; default: case 'd': - term_printf("%lld", val); + term_printf("%" PRId64, val); break; case 'c': term_printc(val); @@ -622,6 +736,62 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne term_printf("\n"); } +static void do_memory_save(unsigned int valh, unsigned int vall, + uint32_t size, const char *filename) +{ + FILE *f; + target_long addr = GET_TLONG(valh, vall); + uint32_t l; + CPUState *env; + uint8_t buf[1024]; + + env = mon_get_cpu(); + if (!env) + return; + + f = fopen(filename, "wb"); + if (!f) { + term_printf("could not open '%s'\n", filename); + return; + } + while (size != 0) { + l = sizeof(buf); + if (l > size) + l = size; + cpu_memory_rw_debug(env, addr, buf, l, 0); + fwrite(buf, 1, l, f); + addr += l; + size -= l; + } + fclose(f); +} + +static void do_physical_memory_save(unsigned int valh, unsigned int vall, + uint32_t size, const char *filename) +{ + FILE *f; + uint32_t l; + uint8_t buf[1024]; + target_phys_addr_t addr = GET_TPHYSADDR(valh, vall); + + f = fopen(filename, "wb"); + if (!f) { + term_printf("could not open '%s'\n", filename); + return; + } + while (size != 0) { + l = sizeof(buf); + if (l > size) + l = size; + cpu_physical_memory_rw(addr, buf, l, 0); + fwrite(buf, 1, l, f); + fflush(f); + addr += l; + size -= l; + } + fclose(f); +} + static void do_sum(uint32_t start, uint32_t size) { uint32_t addr; @@ -646,9 +816,11 @@ typedef struct { 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" }, @@ -666,6 +838,8 @@ static const KeyDef key_defs[] = { { 0x09, "8" }, { 0x0a, "9" }, { 0x0b, "0" }, + { 0x0c, "minus" }, + { 0x0d, "equal" }, { 0x0e, "backspace" }, { 0x0f, "tab" }, @@ -699,7 +873,12 @@ static const KeyDef key_defs[] = { { 0x30, "b" }, { 0x31, "n" }, { 0x32, "m" }, - + { 0x33, "comma" }, + { 0x34, "dot" }, + { 0x35, "slash" }, + + { 0x37, "asterisk" }, + { 0x39, "spc" }, { 0x3a, "caps_lock" }, { 0x3b, "f1" }, @@ -715,6 +894,25 @@ static const KeyDef key_defs[] = { { 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" }, @@ -734,62 +932,131 @@ static const KeyDef key_defs[] = { { 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; } -static void do_send_key(const char *string) +#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) { - char keybuf[16], *q; - uint8_t keycodes[16]; - const char *p; - int nb_keycodes, keycode, i; - - nb_keycodes = 0; - p = string; - while (*p != '\0') { - q = keybuf; - while (*p != '\0' && *p != '-') { - if ((q - keybuf) < sizeof(keybuf) - 1) { - *q++ = *p; + 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(const char *string, int has_hold_time, int hold_time) +{ + char keyname_buf[16]; + char *separator; + int keyname_len, keycode, i; + + 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) { + term_printf("invalid key: '%s...'\n", keyname_buf); + return; } - p++; - } - *q = '\0'; - keycode = get_keycode(keybuf); - if (keycode < 0) { - term_printf("unknown key: '%s'\n", keybuf); - return; + if (i == MAX_KEYCODES) { + term_printf("too many keys\n"); + return; + } + keyname_buf[keyname_len] = 0; + keycode = get_keycode(keyname_buf); + if (keycode < 0) { + term_printf("unknown key: '%s'\n", keyname_buf); + return; + } + keycodes[i++] = keycode; } - keycodes[nb_keycodes++] = keycode; - if (*p == '\0') + if (!separator) break; - p++; + string = separator + 1; } + nb_pending_keycodes = i; /* key down events */ - for(i = 0; i < nb_keycodes; i++) { + for (i = 0; i < nb_pending_keycodes; i++) { keycode = keycodes[i]; if (keycode & 0x80) kbd_put_keycode(0xe0); kbd_put_keycode(keycode & 0x7f); } - /* key up events */ - for(i = nb_keycodes - 1; i >= 0; i--) { - keycode = keycodes[i]; - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); - } + /* delayed key up events */ + qemu_mod_timer(key_timer, qemu_get_clock(vm_clock) + + muldiv64(ticks_per_sec, hold_time, 1000)); +} + +static int mouse_button_state; + +static void do_mouse_move(const char *dx_str, const char *dy_str, + const char *dz_str) +{ + int dx, dy, dz; + dx = strtol(dx_str, NULL, 0); + dy = strtol(dy_str, NULL, 0); + dz = 0; + if (dz_str) + dz = strtol(dz_str, NULL, 0); + kbd_mouse_event(dx, dy, dz, mouse_button_state); +} + +static void do_mouse_button(int button_state) +{ + mouse_button_state = button_state; + kbd_mouse_event(0, 0, 0, mouse_button_state); } static void do_ioport_read(int count, int format, int size, int addr, int has_index, int index) @@ -822,6 +1089,31 @@ static void do_ioport_read(int count, int format, int size, int addr, int has_in 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) +{ + qemu_boot_set_handler = func; + boot_opaque = opaque; +} + +static void do_boot_set(const char *bootdevice) +{ + int res; + + if (qemu_boot_set_handler) { + res = qemu_boot_set_handler(boot_opaque, bootdevice); + if (res == 0) + term_printf("boot device list now set to %s\n", bootdevice); + else + term_printf("setting boot device list failed with error %i\n", res); + } else { + term_printf("no function defined to set boot device list for this architecture\n"); + } +} + static void do_system_reset(void) { qemu_system_reset_request(); @@ -835,7 +1127,7 @@ static void do_system_powerdown(void) #if defined(TARGET_I386) static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask) { - term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n", + term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n", addr, pte & mask, pte & PG_GLOBAL_MASK ? 'G' : '-', @@ -871,12 +1163,12 @@ static void tlb_info(void) print_pte((l1 << 22), pde, ~((1 << 20) - 1)); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, (uint8_t *)&pte, 4); pte = le32_to_cpu(pte); if (pte & PG_PRESENT_MASK) { - print_pte((l1 << 22) + (l2 << 12), - pte & ~PG_PSE_MASK, + print_pte((l1 << 22) + (l2 << 12), + pte & ~PG_PSE_MASK, ~0xfff); } } @@ -885,7 +1177,7 @@ static void tlb_info(void) } } -static void mem_print(uint32_t *pstart, int *plast_prot, +static void mem_print(uint32_t *pstart, int *plast_prot, uint32_t end, int prot) { int prot1; @@ -893,7 +1185,7 @@ static void mem_print(uint32_t *pstart, int *plast_prot, if (prot != prot1) { if (*pstart != -1) { term_printf("%08x-%08x %08x %c%c%c\n", - *pstart, end, end - *pstart, + *pstart, end, end - *pstart, prot1 & PG_USER_MASK ? 'u' : '-', 'r', prot1 & PG_RW_MASK ? 'w' : '-'); @@ -933,7 +1225,7 @@ static void mem_info(void) mem_print(&start, &last_prot, end, prot); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, (uint8_t *)&pte, 4); pte = le32_to_cpu(pte); end = (l1 << 22) + (l2 << 12); @@ -981,7 +1273,20 @@ static void do_info_kqemu(void) #else term_printf("kqemu support: not compiled\n"); #endif -} +} + +static void do_info_kvm(void) +{ +#ifdef CONFIG_KVM + term_printf("kvm support: "); + if (kvm_enabled()) + term_printf("enabled\n"); + else + term_printf("disabled\n"); +#else + term_printf("kvm support: not compiled\n"); +#endif +} #ifdef CONFIG_PROFILER @@ -999,11 +1304,11 @@ static void do_info_profile(void) total = qemu_time; if (total == 0) total = 1; - term_printf("async time %lld (%0.3f)\n", + term_printf("async time %" PRId64 " (%0.3f)\n", dev_time, dev_time / (double)ticks_per_sec); - term_printf("qemu time %lld (%0.3f)\n", + term_printf("qemu time %" PRId64 " (%0.3f)\n", qemu_time, qemu_time / (double)ticks_per_sec); - term_printf("kqemu time %lld (%0.3f %0.1f%%) count=%lld int=%lld excp=%lld intr=%lld\n", + term_printf("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, @@ -1028,68 +1333,202 @@ static void do_info_profile(void) } #endif -static term_cmd_t term_cmds[] = { - { "help|?", "s?", do_help, +/* Capture support */ +static LIST_HEAD (capture_list_head, CaptureState) capture_head; + +static void do_info_capture (void) +{ + int i; + CaptureState *s; + + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { + term_printf ("[%d]: ", i); + s->ops.info (s->opaque); + } +} + +static void do_stop_capture (int n) +{ + int i; + CaptureState *s; + + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { + if (i == n) { + s->ops.destroy (s->opaque); + LIST_REMOVE (s, entries); + qemu_free (s); + return; + } + } +} + +#ifdef HAS_AUDIO +static void do_wav_capture (const char *path, + int has_freq, int freq, + int has_bits, int bits, + int has_channels, int nchannels) +{ + CaptureState *s; + + s = qemu_mallocz (sizeof (*s)); + + freq = has_freq ? freq : 44100; + bits = has_bits ? bits : 16; + nchannels = has_channels ? nchannels : 2; + + if (wav_start_capture (s, path, freq, bits, nchannels)) { + term_printf ("Faied to add wave capture\n"); + qemu_free (s); + } + LIST_INSERT_HEAD (&capture_head, s, entries); +} +#endif + +#if defined(TARGET_I386) +static void do_inject_nmi(int cpu_index) +{ + CPUState *env; + + for (env = first_cpu; env != NULL; env = env->next_cpu) + if (env->cpu_index == cpu_index) { + cpu_interrupt(env, CPU_INTERRUPT_NMI); + break; + } +} +#endif + +static void do_info_status(void) +{ + if (vm_running) + term_printf("VM status: running\n"); + else + term_printf("VM status: paused\n"); +} + + +static void do_balloon(int value) +{ + ram_addr_t target = value; + qemu_balloon(target << 20); +} + +static void do_info_balloon(void) +{ + ram_addr_t actual; + + actual = qemu_balloon_status(); + if (kvm_enabled() && !kvm_has_sync_mmu()) + term_printf("Using KVM without synchronous MMU, ballooning disabled\n"); + else if (actual == 0) + term_printf("Ballooning not activated in VM\n"); + else + term_printf("balloon: actual=%d\n", (int)(actual >> 20)); +} + +/* Please update qemu-doc.texi when adding or changing commands */ +static const term_cmd_t term_cmds[] = { + { "help|?", "s?", do_help, "[cmd]", "show the help" }, - { "commit", "", do_commit, - "", "commit changes to the disk images (if -snapshot is used)" }, + { "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 media (use -f to force it)" }, - { "change", "BF", do_change, - "device filename", "change a removable media" }, - { "screendump", "F", do_screen_dump, + "[-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", "F", do_savevm, - "filename", "save the whole virtual machine state to 'filename'" }, - { "loadvm", "F", do_loadvm, - "filename", "restore the whole virtual machine state from 'filename'" }, - { "stop", "", do_stop, + "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" }, + { "stop", "", do_stop, "", "stop emulation", }, - { "c|cont", "", do_cont, + { "c|cont", "", do_cont, "", "resume emulation", }, #ifdef CONFIG_GDBSTUB - { "gdbserver", "i?", do_gdbserver, + { "gdbserver", "s?", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, #endif - { "x", "/l", do_memory_dump, + { "x", "/l", do_memory_dump, "/fmt addr", "virtual memory dump starting at 'addr'", }, - { "xp", "/l", do_physical_memory_dump, + { "xp", "/l", do_physical_memory_dump, "/fmt addr", "physical memory dump starting at 'addr'", }, - { "p|print", "/l", do_print, + { "p|print", "/l", do_print, "/fmt expr", "print expression value (use $reg for CPU register access)", }, - { "i", "/ii.", do_ioport_read, + { "i", "/ii.", do_ioport_read, "/fmt addr", "I/O port read" }, - { "sendkey", "s", do_send_key, - "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, - { "system_reset", "", do_system_reset, + { "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, + { "system_powerdown", "", do_system_powerdown, "", "send system power down event" }, - { "sum", "ii", do_sum, + { "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, + { "cpu", "i", do_cpu_set, "index", "set the default CPU" }, - { NULL, NULL, }, + { "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" }, + { "balloon", "i", do_balloon, + "target", "request VM to change it's memory allocation (in MB)" }, + { "set_link", "ss", do_set_link, "name [up|down]" }, + { NULL, NULL, }, }; -static term_cmd_t info_cmds[] = { +/* Please update qemu-doc.texi when adding or changing commands */ +static const term_cmd_t info_cmds[] = { { "version", "", do_info_version, - "", "show the version of qemu" }, + "", "show the version of QEMU" }, { "network", "", do_info_network, "", "show the network state" }, + { "chardev", "", qemu_chr_info, + "", "show the character devices" }, { "block", "", do_info_block, "", "show the block devices" }, + { "blockstats", "", do_info_blockstats, + "", "show block device statistics" }, { "registers", "", do_info_registers, "", "show the cpu registers" }, { "cpus", "", do_info_cpus, @@ -1107,17 +1546,48 @@ static term_cmd_t info_cmds[] = { "", "show virtual to physical memory mappings", }, { "mem", "", mem_info, "", "show the active virtual memory mappings", }, + { "hpet", "", do_info_hpet, + "", "show state of HPET", }, #endif { "jit", "", do_info_jit, "", "show dynamic compiler info", }, { "kqemu", "", do_info_kqemu, - "", "show kqemu information", }, + "", "show KQEMU information", }, + { "kvm", "", do_info_kvm, + "", "show KVM information", }, { "usb", "", usb_info, "", "show guest USB devices", }, { "usbhost", "", usb_host_info, "", "show host USB devices", }, { "profile", "", do_info_profile, "", "show profiling information", }, + { "capture", "", do_info_capture, + "", "show capture information" }, + { "snapshots", "", do_info_snapshots, + "", "show the currently saved VM snapshots" }, + { "status", "", do_info_status, + "", "show the current VM status (running|paused)" }, + { "pcmcia", "", pcmcia_info, + "", "show guest PCMCIA status" }, + { "mice", "", do_info_mice, + "", "show which guest mouse is receiving events" }, + { "vnc", "", do_info_vnc, + "", "show the vnc server status"}, + { "name", "", do_info_name, + "", "show the current VM name" }, + { "uuid", "", do_info_uuid, + "", "show the current VM UUID" }, +#if defined(TARGET_PPC) + { "cpustats", "", do_info_cpu_stats, + "", "show CPU statistics", }, +#endif +#if defined(CONFIG_SLIRP) + { "slirp", "", do_info_slirp, + "", "show SLIRP statistics", }, +#endif + { "migrate", "", do_info_migrate, "", "show migration status" }, + { "balloon", "", do_info_balloon, + "", "show balloon information" }, { NULL, NULL, }, }; @@ -1132,12 +1602,12 @@ static jmp_buf expr_env; typedef struct MonitorDef { const char *name; int offset; - target_long (*get_value)(struct MonitorDef *md, int val); + target_long (*get_value)(const struct MonitorDef *md, int val); int type; } MonitorDef; #if defined(TARGET_I386) -static target_long monitor_get_pc (struct MonitorDef *md, int val) +static target_long monitor_get_pc (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1147,7 +1617,7 @@ static target_long monitor_get_pc (struct MonitorDef *md, int val) #endif #if defined(TARGET_PPC) -static target_long monitor_get_ccr (struct MonitorDef *md, int val) +static target_long monitor_get_ccr (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); unsigned int u; @@ -1163,40 +1633,23 @@ static target_long monitor_get_ccr (struct MonitorDef *md, int val) return u; } -static target_long monitor_get_msr (struct MonitorDef *md, int val) +static target_long monitor_get_msr (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) return 0; - return (env->msr[MSR_POW] << MSR_POW) | - (env->msr[MSR_ILE] << MSR_ILE) | - (env->msr[MSR_EE] << MSR_EE) | - (env->msr[MSR_PR] << MSR_PR) | - (env->msr[MSR_FP] << MSR_FP) | - (env->msr[MSR_ME] << MSR_ME) | - (env->msr[MSR_FE0] << MSR_FE0) | - (env->msr[MSR_SE] << MSR_SE) | - (env->msr[MSR_BE] << MSR_BE) | - (env->msr[MSR_FE1] << MSR_FE1) | - (env->msr[MSR_IP] << MSR_IP) | - (env->msr[MSR_IR] << MSR_IR) | - (env->msr[MSR_DR] << MSR_DR) | - (env->msr[MSR_RI] << MSR_RI) | - (env->msr[MSR_LE] << MSR_LE); -} - -static target_long monitor_get_xer (struct MonitorDef *md, int val) + return env->msr; +} + +static target_long monitor_get_xer (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) return 0; - return (env->xer[XER_SO] << XER_SO) | - (env->xer[XER_OV] << XER_OV) | - (env->xer[XER_CA] << XER_CA) | - (env->xer[XER_BC] << XER_BC); + return env->xer; } -static target_long monitor_get_decr (struct MonitorDef *md, int val) +static target_long monitor_get_decr (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1204,7 +1657,7 @@ static target_long monitor_get_decr (struct MonitorDef *md, int val) return cpu_ppc_load_decr(env); } -static target_long monitor_get_tbu (struct MonitorDef *md, int val) +static target_long monitor_get_tbu (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1212,7 +1665,7 @@ static target_long monitor_get_tbu (struct MonitorDef *md, int val) return cpu_ppc_load_tbu(env); } -static target_long monitor_get_tbl (struct MonitorDef *md, int val) +static target_long monitor_get_tbl (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1223,7 +1676,7 @@ static target_long monitor_get_tbl (struct MonitorDef *md, int val) #if defined(TARGET_SPARC) #ifndef TARGET_SPARC64 -static target_long monitor_get_psr (struct MonitorDef *md, int val) +static target_long monitor_get_psr (const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1232,7 +1685,7 @@ static target_long monitor_get_psr (struct MonitorDef *md, int val) } #endif -static target_long monitor_get_reg(struct MonitorDef *md, int val) +static target_long monitor_get_reg(const struct MonitorDef *md, int val) { CPUState *env = mon_get_cpu(); if (!env) @@ -1241,7 +1694,7 @@ static target_long monitor_get_reg(struct MonitorDef *md, int val) } #endif -static MonitorDef monitor_defs[] = { +static const MonitorDef monitor_defs[] = { #ifdef TARGET_I386 #define SEG(name, seg) \ @@ -1277,6 +1730,7 @@ static MonitorDef monitor_defs[] = { SEG("gs", R_GS) { "pc", 0, monitor_get_pc, }, #elif defined(TARGET_PPC) + /* General purpose registers */ { "r0", offsetof(CPUState, gpr[0]) }, { "r1", offsetof(CPUState, gpr[1]) }, { "r2", offsetof(CPUState, gpr[2]) }, @@ -1309,15 +1763,56 @@ static MonitorDef monitor_defs[] = { { "r29", offsetof(CPUState, gpr[29]) }, { "r30", offsetof(CPUState, gpr[30]) }, { "r31", offsetof(CPUState, gpr[31]) }, + /* Floating point registers */ + { "f0", offsetof(CPUState, fpr[0]) }, + { "f1", offsetof(CPUState, fpr[1]) }, + { "f2", offsetof(CPUState, fpr[2]) }, + { "f3", offsetof(CPUState, fpr[3]) }, + { "f4", offsetof(CPUState, fpr[4]) }, + { "f5", offsetof(CPUState, fpr[5]) }, + { "f6", offsetof(CPUState, fpr[6]) }, + { "f7", offsetof(CPUState, fpr[7]) }, + { "f8", offsetof(CPUState, fpr[8]) }, + { "f9", offsetof(CPUState, fpr[9]) }, + { "f10", offsetof(CPUState, fpr[10]) }, + { "f11", offsetof(CPUState, fpr[11]) }, + { "f12", offsetof(CPUState, fpr[12]) }, + { "f13", offsetof(CPUState, fpr[13]) }, + { "f14", offsetof(CPUState, fpr[14]) }, + { "f15", offsetof(CPUState, fpr[15]) }, + { "f16", offsetof(CPUState, fpr[16]) }, + { "f17", offsetof(CPUState, fpr[17]) }, + { "f18", offsetof(CPUState, fpr[18]) }, + { "f19", offsetof(CPUState, fpr[19]) }, + { "f20", offsetof(CPUState, fpr[20]) }, + { "f21", offsetof(CPUState, fpr[21]) }, + { "f22", offsetof(CPUState, fpr[22]) }, + { "f23", offsetof(CPUState, fpr[23]) }, + { "f24", offsetof(CPUState, fpr[24]) }, + { "f25", offsetof(CPUState, fpr[25]) }, + { "f26", offsetof(CPUState, fpr[26]) }, + { "f27", offsetof(CPUState, fpr[27]) }, + { "f28", offsetof(CPUState, fpr[28]) }, + { "f29", offsetof(CPUState, fpr[29]) }, + { "f30", offsetof(CPUState, fpr[30]) }, + { "f31", offsetof(CPUState, fpr[31]) }, + { "fpscr", offsetof(CPUState, fpscr) }, + /* Next instruction pointer */ { "nip|pc", offsetof(CPUState, nip) }, { "lr", offsetof(CPUState, lr) }, { "ctr", offsetof(CPUState, ctr) }, { "decr", 0, &monitor_get_decr, }, { "ccr", 0, &monitor_get_ccr, }, + /* Machine state register */ { "msr", 0, &monitor_get_msr, }, { "xer", 0, &monitor_get_xer, }, { "tbu", 0, &monitor_get_tbu, }, { "tbl", 0, &monitor_get_tbl, }, +#if defined(TARGET_PPC64) + /* Address space register */ + { "asr", offsetof(CPUState, asr) }, +#endif + /* Segment registers */ { "sdr1", offsetof(CPUState, sdr1) }, { "sr0", offsetof(CPUState, sr[0]) }, { "sr1", offsetof(CPUState, sr[1]) }, @@ -1440,17 +1935,16 @@ static MonitorDef monitor_defs[] = { { NULL }, }; -static void expr_error(const char *fmt) +static void expr_error(const char *msg) { - term_printf(fmt); - term_printf("\n"); + term_printf("%s\n", msg); longjmp(expr_env, 1); } /* return 0 if OK, -1 if not found, -2 if no CPU defined */ static int get_monitor_def(target_long *pval, const char *name) { - MonitorDef *md; + const MonitorDef *md; void *ptr; for(md = monitor_defs; md->name != NULL; md++) { @@ -1484,16 +1978,16 @@ static void next(void) { if (pch != '\0') { pch++; - while (isspace(*pch)) + while (qemu_isspace(*pch)) pch++; } } -static target_long expr_sum(void); +static int64_t expr_sum(void); -static target_long expr_unary(void) +static int64_t expr_unary(void) { - target_long n; + int64_t n; char *p; int ret; @@ -1531,7 +2025,8 @@ static target_long expr_unary(void) case '$': { char buf[128], *q; - + target_long reg=0; + pch++; q = buf; while ((*pch >= 'a' && *pch <= 'z') || @@ -1542,14 +2037,15 @@ static target_long expr_unary(void) *q++ = *pch; pch++; } - while (isspace(*pch)) + while (qemu_isspace(*pch)) pch++; *q = 0; - ret = get_monitor_def(&n, buf); + ret = get_monitor_def(®, buf); if (ret == -1) expr_error("unknown register"); - else if (ret == -2) + else if (ret == -2) expr_error("no cpu defined"); + n = reg; } break; case '\0': @@ -1557,13 +2053,16 @@ static target_long expr_unary(void) n = 0; break; default: - /* XXX: 64 bit version */ +#if TARGET_PHYS_ADDR_BITS > 32 + n = strtoull(pch, &p, 0); +#else n = strtoul(pch, &p, 0); +#endif if (pch == p) { expr_error("invalid char in expression"); } pch = p; - while (isspace(*pch)) + while (qemu_isspace(*pch)) pch++; break; } @@ -1571,11 +2070,11 @@ static target_long expr_unary(void) } -static target_long expr_prod(void) +static int64_t expr_prod(void) { - target_long val, val2; + int64_t val, val2; int op; - + val = expr_unary(); for(;;) { op = *pch; @@ -1590,7 +2089,7 @@ static target_long expr_prod(void) break; case '/': case '%': - if (val2 == 0) + if (val2 == 0) expr_error("division by zero"); if (op == '/') val /= val2; @@ -1602,9 +2101,9 @@ static target_long expr_prod(void) return val; } -static target_long expr_logic(void) +static int64_t expr_logic(void) { - target_long val, val2; + int64_t val, val2; int op; val = expr_prod(); @@ -1630,9 +2129,9 @@ static target_long expr_logic(void) return val; } -static target_long expr_sum(void) +static int64_t expr_sum(void) { - target_long val, val2; + int64_t val, val2; int op; val = expr_logic(); @@ -1650,14 +2149,14 @@ static target_long expr_sum(void) return val; } -static int get_expr(target_long *pval, const char **pp) +static int get_expr(int64_t *pval, const char **pp) { pch = *pp; if (setjmp(expr_env)) { *pp = pch; return -1; } - while (isspace(*pch)) + while (qemu_isspace(*pch)) pch++; *pval = expr_sum(); *pp = pch; @@ -1672,7 +2171,7 @@ static int get_str(char *buf, int buf_size, const char **pp) q = buf; p = *pp; - while (isspace(*p)) + while (qemu_isspace(*p)) p++; if (*p == '\0') { fail: @@ -1717,7 +2216,7 @@ static int get_str(char *buf, int buf_size, const char **pp) } p++; } else { - while (*p != '\0' && !isspace(*p)) { + while (*p != '\0' && !qemu_isspace(*p)) { if ((q - buf) < buf_size - 1) { *q++ = *p; } @@ -1739,35 +2238,46 @@ static void monitor_handle_command(const char *cmdline) const char *p, *pstart, *typestr; char *q; int c, nb_args, len, i, has_arg; - term_cmd_t *cmd; + const term_cmd_t *cmd; char cmdname[256]; char buf[1024]; void *str_allocated[MAX_ARGS]; void *args[MAX_ARGS]; + void (*handler_0)(void); + void (*handler_1)(void *arg0); + void (*handler_2)(void *arg0, void *arg1); + void (*handler_3)(void *arg0, void *arg1, void *arg2); + void (*handler_4)(void *arg0, void *arg1, void *arg2, void *arg3); + void (*handler_5)(void *arg0, void *arg1, void *arg2, void *arg3, + void *arg4); + void (*handler_6)(void *arg0, void *arg1, void *arg2, void *arg3, + void *arg4, void *arg5); + void (*handler_7)(void *arg0, void *arg1, void *arg2, void *arg3, + void *arg4, void *arg5, void *arg6); #ifdef DEBUG term_printf("command='%s'\n", cmdline); #endif - + /* extract the command name */ p = cmdline; q = cmdname; - while (isspace(*p)) + while (qemu_isspace(*p)) p++; if (*p == '\0') return; pstart = p; - while (*p != '\0' && *p != '/' && !isspace(*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'; - + /* find the command */ for(cmd = term_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(cmdname, cmd->name)) + if (compare_cmd(cmdname, cmd->name)) goto found; } term_printf("unknown command: '%s'\n", cmdname); @@ -1776,7 +2286,7 @@ static void monitor_handle_command(const char *cmdline) for(i = 0; i < MAX_ARGS; i++) str_allocated[i] = NULL; - + /* parse the parameters */ typestr = cmd->args_type; nb_args = 0; @@ -1792,8 +2302,8 @@ static void monitor_handle_command(const char *cmdline) { int ret; char *str; - - while (isspace(*p)) + + while (qemu_isspace(*p)) p++; if (*typestr == '?') { typestr++; @@ -1819,7 +2329,7 @@ static void monitor_handle_command(const char *cmdline) goto fail; } str = qemu_malloc(strlen(buf) + 1); - strcpy(str, buf); + pstrcpy(str, sizeof(buf), buf); str_allocated[nb_args] = str; add_str: if (nb_args >= MAX_ARGS) { @@ -1833,16 +2343,16 @@ static void monitor_handle_command(const char *cmdline) case '/': { int count, format, size; - - while (isspace(*p)) + + while (qemu_isspace(*p)) p++; if (*p == '/') { /* format found */ p++; count = 1; - if (isdigit(*p)) { + if (qemu_isdigit(*p)) { count = 0; - while (isdigit(*p)) { + while (qemu_isdigit(*p)) { count = count * 10 + (*p - '0'); p++; } @@ -1881,7 +2391,7 @@ static void monitor_handle_command(const char *cmdline) } } next: - if (*p != '\0' && !isspace(*p)) { + if (*p != '\0' && !qemu_isspace(*p)) { term_printf("invalid char in format: '%c'\n", *p); goto fail; } @@ -1891,8 +2401,8 @@ static void monitor_handle_command(const char *cmdline) /* for 'i', not specifying a size gives -1 as size */ if (size < 0) size = default_fmt_size; + default_fmt_size = size; } - default_fmt_size = size; default_fmt_format = format; } else { count = 1; @@ -1905,19 +2415,19 @@ static void monitor_handle_command(const char *cmdline) } if (nb_args + 3 > MAX_ARGS) goto error_args; - args[nb_args++] = (void*)count; - args[nb_args++] = (void*)format; - args[nb_args++] = (void*)size; + args[nb_args++] = (void*)(long)count; + args[nb_args++] = (void*)(long)format; + args[nb_args++] = (void*)(long)size; } break; case 'i': case 'l': { - target_long val; - while (isspace(*p)) + int64_t val; + + while (qemu_isspace(*p)) p++; if (*typestr == '?' || *typestr == '.') { - typestr++; if (*typestr == '?') { if (*p == '\0') has_arg = 0; @@ -1926,16 +2436,17 @@ static void monitor_handle_command(const char *cmdline) } else { if (*p == '.') { p++; - while (isspace(*p)) + while (qemu_isspace(*p)) p++; has_arg = 1; } else { has_arg = 0; } } + typestr++; if (nb_args >= MAX_ARGS) goto error_args; - args[nb_args++] = (void *)has_arg; + args[nb_args++] = (void *)(long)has_arg; if (!has_arg) { if (nb_args >= MAX_ARGS) goto error_args; @@ -1949,16 +2460,16 @@ static void monitor_handle_command(const char *cmdline) if (c == 'i') { if (nb_args >= MAX_ARGS) goto error_args; - args[nb_args++] = (void *)(int)val; + args[nb_args++] = (void *)(long)val; } else { if ((nb_args + 1) >= MAX_ARGS) goto error_args; -#if TARGET_LONG_BITS == 64 - args[nb_args++] = (void *)(int)((val >> 32) & 0xffffffff); +#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 *)(int)(val & 0xffffffff); + args[nb_args++] = (void *)(long)(val & 0xffffffff); } } break; @@ -1966,17 +2477,17 @@ static void monitor_handle_command(const char *cmdline) { int has_option; /* option */ - + c = *typestr++; if (c == '\0') goto bad_type; - while (isspace(*p)) + while (qemu_isspace(*p)) p++; has_option = 0; if (*p == '-') { p++; if (*p != c) { - term_printf("%s: unsupported option -%c\n", + term_printf("%s: unsupported option -%c\n", cmdname, *p); goto fail; } @@ -1985,7 +2496,7 @@ static void monitor_handle_command(const char *cmdline) } if (nb_args >= MAX_ARGS) goto error_args; - args[nb_args++] = (void *)has_option; + args[nb_args++] = (void *)(long)has_option; } break; default: @@ -1995,35 +2506,46 @@ static void monitor_handle_command(const char *cmdline) } } /* check that all arguments were parsed */ - while (isspace(*p)) + while (qemu_isspace(*p)) p++; if (*p != '\0') { - term_printf("%s: extraneous characters at the end of line\n", + term_printf("%s: extraneous characters at the end of line\n", cmdname); goto fail; } switch(nb_args) { case 0: - cmd->handler(); + handler_0 = cmd->handler; + handler_0(); break; case 1: - cmd->handler(args[0]); + handler_1 = cmd->handler; + handler_1(args[0]); break; case 2: - cmd->handler(args[0], args[1]); + handler_2 = cmd->handler; + handler_2(args[0], args[1]); break; case 3: - cmd->handler(args[0], args[1], args[2]); + handler_3 = cmd->handler; + handler_3(args[0], args[1], args[2]); break; case 4: - cmd->handler(args[0], args[1], args[2], args[3]); + handler_4 = cmd->handler; + handler_4(args[0], args[1], args[2], args[3]); break; case 5: - cmd->handler(args[0], args[1], args[2], args[3], args[4]); + handler_5 = cmd->handler; + handler_5(args[0], args[1], args[2], args[3], args[4]); break; case 6: - cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]); + handler_6 = cmd->handler; + handler_6(args[0], args[1], args[2], args[3], args[4], args[5]); + break; + case 7: + handler_7 = cmd->handler; + handler_7(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break; default: term_printf("unsupported number of arguments: %d\n", nb_args); @@ -2070,11 +2592,11 @@ static void file_completion(const char *input) int input_path_len; const char *p; - p = strrchr(input, '/'); + p = strrchr(input, '/'); if (!p) { input_path_len = 0; pstrcpy(file_prefix, sizeof(file_prefix), input); - strcpy(path, "."); + pstrcpy(path, sizeof(path), "."); } else { input_path_len = p - input + 1; memcpy(path, input, input_path_len); @@ -2096,13 +2618,15 @@ static void file_completion(const char *input) break; if (strstart(d->d_name, file_prefix, NULL)) { memcpy(file, input, input_path_len); - strcpy(file + input_path_len, d->d_name); + if (input_path_len < sizeof(file)) + pstrcpy(file + input_path_len, sizeof(file) - input_path_len, + d->d_name); /* stat the file to find out if it's a directory. * In that case add a slash to speed up typing long paths */ stat(file, &sb); if(S_ISDIR(sb.st_mode)) - strcat(file, "/"); + pstrcat(file, sizeof(file), "/"); add_completion(file); } } @@ -2130,7 +2654,7 @@ static void parse_cmdline(const char *cmdline, p = cmdline; nb_args = 0; for(;;) { - while (isspace(*p)) + while (qemu_isspace(*p)) p++; if (*p == '\0') break; @@ -2151,7 +2675,8 @@ void readline_find_completion(const char *cmdline) char *args[MAX_ARGS]; int nb_args, i, len; const char *ptype, *str; - term_cmd_t *cmd; + const term_cmd_t *cmd; + const KeyDef *key; parse_cmdline(cmdline, &nb_args, args); #ifdef DEBUG_COMPLETION @@ -2163,7 +2688,7 @@ void readline_find_completion(const char *cmdline) /* if the line ends with a space, it means we want to complete the next arg */ len = strlen(cmdline); - if (len > 0 && isspace(cmdline[len - 1])) { + if (len > 0 && qemu_isspace(cmdline[len - 1])) { if (nb_args >= MAX_ARGS) return; args[nb_args++] = qemu_strdup(""); @@ -2213,6 +2738,11 @@ void readline_find_completion(const char *cmdline) for(cmd = info_cmds; cmd->name != NULL; cmd++) { cmd_completion(str, cmd->name); } + } else if (!strcmp(cmd->name, "sendkey")) { + completion_index = strlen(str); + for(key = key_defs; key->name != NULL; key++) { + cmd_completion(str, key->name); + } } break; default: @@ -2235,12 +2765,27 @@ static void term_read(void *opaque, const uint8_t *buf, int size) readline_handle_byte(buf[i]); } -static void monitor_start_input(void); +static int monitor_suspended; static void monitor_handle_command1(void *opaque, const char *cmdline) { monitor_handle_command(cmdline); - monitor_start_input(); + if (!monitor_suspended) + monitor_start_input(); + else + monitor_suspended = 2; +} + +void monitor_suspend(void) +{ + monitor_suspended = 1; +} + +void monitor_resume(void) +{ + if (monitor_suspended == 2) + monitor_start_input(); + monitor_suspended = 0; } static void monitor_start_input(void) @@ -2248,15 +2793,44 @@ static void monitor_start_input(void) readline_start("(qemu) ", 0, monitor_handle_command1, NULL); } +static void term_event(void *opaque, int event) +{ + if (event != CHR_EVENT_RESET) + return; + + if (!hide_banner) + term_printf("QEMU %s monitor - type 'help' for more information\n", + QEMU_VERSION); + monitor_start_input(); +} + +static int is_first_init = 1; + void monitor_init(CharDriverState *hd, int show_banner) { - monitor_hd = hd; - if (show_banner) { - term_printf("QEMU %s monitor - type 'help' for more information\n", - QEMU_VERSION); + int i; + + if (is_first_init) { + key_timer = qemu_new_timer(vm_clock, release_keys, NULL); + if (!key_timer) + return; + for (i = 0; i < MAX_MON; i++) { + monitor_hd[i] = NULL; + } + is_first_init = 0; } - qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL); - monitor_start_input(); + for (i = 0; i < MAX_MON; i++) { + if (monitor_hd[i] == NULL) { + monitor_hd[i] = hd; + break; + } + } + + hide_banner = !show_banner; + + qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL); + + readline_start("", 0, monitor_handle_command1, NULL); } /* XXX: use threads ? */ @@ -2274,9 +2848,20 @@ static void monitor_readline_cb(void *opaque, const char *input) void monitor_readline(const char *prompt, int is_password, char *buf, int buf_size) { + int i; + int old_focus[MAX_MON]; + if (is_password) { - qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS); + for (i = 0; i < MAX_MON; i++) { + old_focus[i] = 0; + if (monitor_hd[i]) { + old_focus[i] = monitor_hd[i]->focus; + monitor_hd[i]->focus = 0; + qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS); + } + } } + readline_start(prompt, is_password, monitor_readline_cb, NULL); monitor_readline_buf = buf; monitor_readline_buf_size = buf_size; @@ -2284,4 +2869,10 @@ void monitor_readline(const char *prompt, int is_password, while (monitor_readline_started) { main_loop_wait(10); } + /* restore original focus */ + if (is_password) { + for (i = 0; i < MAX_MON; i++) + if (old_focus[i]) + monitor_hd[i]->focus = old_focus[i]; + } }