X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=monitor.c;h=70b473ddbff6ba7b3b3373485a05640675a88d2e;hb=e80e1cc4b18d388227d2fa6b8551929a381d2490;hp=8b03a7e1a5377d4370787380268e9bab94307bf7;hpb=4c27ba27c5dd810fdcfbe82e3998a174a6e793f2;p=qemu diff --git a/monitor.c b/monitor.c index 8b03a7e..70b473d 100644 --- a/monitor.c +++ b/monitor.c @@ -23,37 +23,23 @@ */ #include "vl.h" #include "disas.h" +#include //#define DEBUG +//#define DEBUG_COMPLETION #ifndef offsetof #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif -#define TERM_CMD_BUF_SIZE 4095 -#define TERM_MAX_CMDS 64 - -#define IS_NORM 0 -#define IS_ESC 1 -#define IS_CSI 2 - -#define printf do_not_use_printf - -static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1]; -static int term_cmd_buf_index; -static int term_cmd_buf_size; -static int term_esc_state; -static int term_esc_param; - -static char *term_history[TERM_MAX_CMDS]; -static int term_hist_entry; - /* * Supported types: * * 'F' filename + * 'B' block device name * 's' string (accept optional quote) - * 'i' integer + * 'i' 32 bit integer + * 'l' target long (32 or 64 bit) * '/' optional gdb-like print format (like "/10x") * * '?' optional type (for 'F', 's' and 'i') @@ -68,20 +54,63 @@ typedef struct term_cmd_t { const char *help; } term_cmd_t; +static CharDriverState *monitor_hd; + static term_cmd_t term_cmds[]; static term_cmd_t info_cmds[]; +static char term_outbuf[1024]; +static int term_outbuf_index; + +static void monitor_start_input(void); + +CPUState *mon_cpu = NULL; + +void term_flush(void) +{ + if (term_outbuf_index > 0) { + qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); + term_outbuf_index = 0; + } +} + +/* flush at every end of line or if the buffer is full */ +void term_puts(const char *str) +{ + int c; + for(;;) { + c = *str++; + if (c == '\0') + break; + term_outbuf[term_outbuf_index++] = c; + if (term_outbuf_index >= sizeof(term_outbuf) || + c == '\n') + term_flush(); + } +} + +void term_vprintf(const char *fmt, va_list ap) +{ + char buf[4096]; + vsnprintf(buf, sizeof(buf), fmt, ap); + term_puts(buf); +} + void term_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); - vprintf(fmt, ap); + term_vprintf(fmt, ap); va_end(ap); } -void term_flush(void) +static int monitor_fprintf(FILE *stream, const char *fmt, ...) { - fflush(stdout); + va_list ap; + va_start(ap, fmt); + term_vprintf(fmt, ap); + va_end(ap); + return 0; } static int compare_cmd(const char *name, const char *list) @@ -141,8 +170,9 @@ static void do_commit(void) int i; for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) + if (bs_table[i]) { bdrv_commit(bs_table[i]); + } } } @@ -163,50 +193,108 @@ static void do_info(const char *item) cmd->handler(); } -static void do_info_network(void) +static void do_info_version(void) { - int i, j; - NetDriverState *nd; - - for(i = 0; i < nb_nics; i++) { - nd = &nd_table[i]; - term_printf("%d: ifname=%s macaddr=", i, nd->ifname); - for(j = 0; j < 6; j++) { - if (j > 0) - term_printf(":"); - term_printf("%02x", nd->macaddr[j]); - } - term_printf("\n"); - } + term_printf("%s\n", QEMU_VERSION); } - + static void do_info_block(void) { bdrv_info(); } +/* get the current CPU defined by the user */ +int mon_set_cpu(int cpu_index) +{ + CPUState *env; + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + if (env->cpu_index == cpu_index) { + mon_cpu = env; + return 0; + } + } + return -1; +} + +CPUState *mon_get_cpu(void) +{ + if (!mon_cpu) { + mon_set_cpu(0); + } + return mon_cpu; +} + static void do_info_registers(void) { + CPUState *env; + env = mon_get_cpu(); + if (!env) + return; #ifdef TARGET_I386 - cpu_dump_state(cpu_single_env, stdout, X86_DUMP_FPU | X86_DUMP_CCOP); + cpu_dump_state(env, NULL, monitor_fprintf, + X86_DUMP_FPU); #else - cpu_dump_state(cpu_single_env, stdout, 0); + cpu_dump_state(env, NULL, monitor_fprintf, + 0); +#endif +} + +static void do_info_cpus(void) +{ + CPUState *env; + + /* just to set the default cpu if not already done */ + mon_get_cpu(); + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + 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 (msr_pow) + term_printf(" (halted)"); #endif + term_printf("\n"); + } +} + +static void do_cpu_set(int index) +{ + if (mon_set_cpu(index) < 0) + term_printf("Invalid CPU index\n"); +} + +static void do_info_jit(void) +{ + dump_exec_info(NULL, monitor_fprintf); } static void do_info_history (void) { int i; - - for (i = 0; i < TERM_MAX_CMDS; i++) { - if (term_history[i] == NULL) - break; - term_printf("%d: '%s'\n", i, term_history[i]); + const char *str; + + i = 0; + for(;;) { + str = readline_get_history(i); + if (!str) + break; + term_printf("%d: '%s'\n", i, str); + i++; } } static void do_quit(void) { +#ifdef USE_KQEMU + kqemu_record_dump(); +#endif exit(0); } @@ -232,8 +320,6 @@ static void do_eject(int force, const char *filename) { BlockDriverState *bs; - term_printf("%d %s\n", force, filename); - bs = bdrv_find(filename); if (!bs) { term_printf("device not found\n"); @@ -245,6 +331,8 @@ static void do_eject(int force, const char *filename) static void do_change(const char *device, const char *filename) { BlockDriverState *bs; + int i; + char password[256]; bs = bdrv_find(device); if (!bs) { @@ -254,6 +342,15 @@ static void do_change(const char *device, const char *filename) 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"); + } + } } static void do_screen_dump(const char *filename) @@ -342,6 +439,7 @@ static void term_printc(int c) static void memory_dump(int count, int format, int wsize, target_ulong addr, int is_physical) { + CPUState *env; int nb_per_line, l, line_size, i, max_digits, len; uint8_t buf[16]; uint64_t v; @@ -349,19 +447,22 @@ static void memory_dump(int count, int format, int wsize, if (format == 'i') { int flags; flags = 0; + env = mon_get_cpu(); + if (!env && !is_physical) + return; #ifdef TARGET_I386 if (wsize == 2) { flags = 1; } else if (wsize == 4) { flags = 0; } else { - /* as default we use the current CS size */ + /* as default we use the current CS size */ flags = 0; - if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK)) + if (env && !(env->segs[R_CS].flags & DESC_B_MASK)) flags = 1; } #endif - monitor_disas(addr, count, is_physical, flags); + monitor_disas(env, addr, count, is_physical, flags); return; } @@ -391,14 +492,17 @@ static void memory_dump(int count, int format, int wsize, } while (len > 0) { - term_printf("0x%08x:", addr); + term_printf(TARGET_FMT_lx ":", addr); l = len; if (l > line_size) l = line_size; if (is_physical) { cpu_physical_memory_rw(addr, buf, l, 0); } else { - cpu_memory_rw_debug(cpu_single_env, addr, buf, l, 0); + env = mon_get_cpu(); + if (!env) + break; + cpu_memory_rw_debug(env, addr, buf, l, 0); } i = 0; while (i < l) { @@ -411,7 +515,7 @@ static void memory_dump(int count, int format, int wsize, v = lduw_raw(buf + i); break; case 4: - v = ldl_raw(buf + i); + v = (uint32_t)ldl_raw(buf + i); break; case 8: v = ldq_raw(buf + i); @@ -443,18 +547,31 @@ static void memory_dump(int count, int format, int wsize, } } -static void do_memory_dump(int count, int format, int size, int addr) +#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(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); } -static void do_physical_memory_dump(int count, int format, int size, int addr) +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); memory_dump(count, format, size, addr, 1); } -static void do_print(int count, int format, int size, int val) +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 switch(format) { case 'o': term_printf("%#o", val); @@ -473,9 +590,378 @@ static void do_print(int count, int format, int size, int val) term_printc(val); break; } +#else + switch(format) { + case 'o': + term_printf("%#llo", val); + break; + case 'x': + term_printf("%#llx", val); + break; + case 'u': + term_printf("%llu", val); + break; + default: + case 'd': + term_printf("%lld", val); + break; + case 'c': + term_printc(val); + break; + } +#endif term_printf("\n"); } +static void do_sum(uint32_t start, uint32_t size) +{ + uint32_t addr; + uint8_t buf[1]; + uint16_t sum; + + sum = 0; + for(addr = start; addr < (start + size); addr++) { + cpu_physical_memory_rw(addr, buf, 1, 0); + /* BSD sum algorithm ('sum' Unix command) */ + sum = (sum >> 1) | (sum << 15); + sum += buf[0]; + } + term_printf("%05d\n", sum); +} + +typedef struct { + int keycode; + const char *name; +} KeyDef; + +static const KeyDef key_defs[] = { + { 0x2a, "shift" }, + { 0x36, "shift_r" }, + + { 0x38, "alt" }, + { 0xb8, "alt_r" }, + { 0x1d, "ctrl" }, + { 0x9d, "ctrl_r" }, + + { 0xdd, "menu" }, + + { 0x01, "esc" }, + + { 0x02, "1" }, + { 0x03, "2" }, + { 0x04, "3" }, + { 0x05, "4" }, + { 0x06, "5" }, + { 0x07, "6" }, + { 0x08, "7" }, + { 0x09, "8" }, + { 0x0a, "9" }, + { 0x0b, "0" }, + { 0x0e, "backspace" }, + + { 0x0f, "tab" }, + { 0x10, "q" }, + { 0x11, "w" }, + { 0x12, "e" }, + { 0x13, "r" }, + { 0x14, "t" }, + { 0x15, "y" }, + { 0x16, "u" }, + { 0x17, "i" }, + { 0x18, "o" }, + { 0x19, "p" }, + + { 0x1c, "ret" }, + + { 0x1e, "a" }, + { 0x1f, "s" }, + { 0x20, "d" }, + { 0x21, "f" }, + { 0x22, "g" }, + { 0x23, "h" }, + { 0x24, "j" }, + { 0x25, "k" }, + { 0x26, "l" }, + + { 0x2c, "z" }, + { 0x2d, "x" }, + { 0x2e, "c" }, + { 0x2f, "v" }, + { 0x30, "b" }, + { 0x31, "n" }, + { 0x32, "m" }, + + { 0x39, "spc" }, + { 0x3a, "caps_lock" }, + { 0x3b, "f1" }, + { 0x3c, "f2" }, + { 0x3d, "f3" }, + { 0x3e, "f4" }, + { 0x3f, "f5" }, + { 0x40, "f6" }, + { 0x41, "f7" }, + { 0x42, "f8" }, + { 0x43, "f9" }, + { 0x44, "f10" }, + { 0x45, "num_lock" }, + { 0x46, "scroll_lock" }, + + { 0x56, "<" }, + + { 0x57, "f11" }, + { 0x58, "f12" }, + + { 0xb7, "print" }, + + { 0xc7, "home" }, + { 0xc9, "pgup" }, + { 0xd1, "pgdn" }, + { 0xcf, "end" }, + + { 0xcb, "left" }, + { 0xc8, "up" }, + { 0xd0, "down" }, + { 0xcd, "right" }, + + { 0xd2, "insert" }, + { 0xd3, "delete" }, + { 0, NULL }, +}; + +static int get_keycode(const char *key) +{ + const KeyDef *p; + + for(p = key_defs; p->name != NULL; p++) { + if (!strcmp(key, p->name)) + return p->keycode; + } + return -1; +} + +static void do_send_key(const char *string) +{ + 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; + } + p++; + } + *q = '\0'; + keycode = get_keycode(keybuf); + if (keycode < 0) { + term_printf("unknown key: '%s'\n", keybuf); + return; + } + keycodes[nb_keycodes++] = keycode; + if (*p == '\0') + break; + p++; + } + /* key down events */ + for(i = 0; i < nb_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); + } +} + +static void do_ioport_read(int count, int format, int size, int addr, int has_index, int index) +{ + uint32_t val; + int suffix; + + if (has_index) { + cpu_outb(NULL, addr & 0xffff, index & 0xff); + addr++; + } + addr &= 0xffff; + + switch(size) { + default: + case 1: + val = cpu_inb(NULL, addr); + suffix = 'b'; + break; + case 2: + val = cpu_inw(NULL, addr); + suffix = 'w'; + break; + case 4: + val = cpu_inl(NULL, addr); + suffix = 'l'; + break; + } + term_printf("port%c[0x%04x] = %#0*x\n", + suffix, addr, size * 2, val); +} + +static void do_system_reset(void) +{ + qemu_system_reset_request(); +} + +static void do_system_powerdown(void) +{ + qemu_system_powerdown_request(); +} + +#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", + addr, + pte & mask, + pte & PG_GLOBAL_MASK ? 'G' : '-', + pte & PG_PSE_MASK ? 'P' : '-', + pte & PG_DIRTY_MASK ? 'D' : '-', + pte & PG_ACCESSED_MASK ? 'A' : '-', + pte & PG_PCD_MASK ? 'C' : '-', + pte & PG_PWT_MASK ? 'T' : '-', + pte & PG_USER_MASK ? 'U' : '-', + pte & PG_RW_MASK ? 'W' : '-'); +} + +static void tlb_info(void) +{ + CPUState *env; + int l1, l2; + uint32_t pgd, pde, pte; + + env = mon_get_cpu(); + if (!env) + return; + + if (!(env->cr[0] & CR0_PG_MASK)) { + term_printf("PG disabled\n"); + return; + } + pgd = env->cr[3] & ~0xfff; + for(l1 = 0; l1 < 1024; l1++) { + cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + pde = le32_to_cpu(pde); + if (pde & PG_PRESENT_MASK) { + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + print_pte((l1 << 22), pde, ~((1 << 20) - 1)); + } else { + for(l2 = 0; l2 < 1024; l2++) { + 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, + ~0xfff); + } + } + } + } + } +} + +static void mem_print(uint32_t *pstart, int *plast_prot, + uint32_t end, int prot) +{ + int prot1; + prot1 = *plast_prot; + if (prot != prot1) { + if (*pstart != -1) { + term_printf("%08x-%08x %08x %c%c%c\n", + *pstart, end, end - *pstart, + prot1 & PG_USER_MASK ? 'u' : '-', + 'r', + prot1 & PG_RW_MASK ? 'w' : '-'); + } + if (prot != 0) + *pstart = end; + else + *pstart = -1; + *plast_prot = prot; + } +} + +static void mem_info(void) +{ + CPUState *env; + int l1, l2, prot, last_prot; + uint32_t pgd, pde, pte, start, end; + + env = mon_get_cpu(); + if (!env) + return; + + if (!(env->cr[0] & CR0_PG_MASK)) { + term_printf("PG disabled\n"); + return; + } + pgd = env->cr[3] & ~0xfff; + last_prot = 0; + start = -1; + for(l1 = 0; l1 < 1024; l1++) { + cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + pde = le32_to_cpu(pde); + end = l1 << 22; + if (pde & PG_PRESENT_MASK) { + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + prot = pde & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK); + mem_print(&start, &last_prot, end, prot); + } else { + for(l2 = 0; l2 < 1024; l2++) { + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, + (uint8_t *)&pte, 4); + pte = le32_to_cpu(pte); + end = (l1 << 22) + (l2 << 12); + if (pte & PG_PRESENT_MASK) { + prot = pte & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK); + } else { + prot = 0; + } + mem_print(&start, &last_prot, end, prot); + } + } + } else { + prot = 0; + mem_print(&start, &last_prot, end, prot); + } + } +} +#endif + +static void do_info_kqemu(void) +{ +#ifdef USE_KQEMU + CPUState *env; + int val; + val = 0; + env = mon_get_cpu(); + if (!env) { + term_printf("No cpu initialized yet"); + return; + } + val = env->kqemu_enabled; + term_printf("kqemu is %s\n", val ? "enabled" : "disabled"); +#else + term_printf("kqemu support is not compiled\n"); +#endif +} + static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -485,9 +971,9 @@ static term_cmd_t term_cmds[] = { "subcommand", "show various information about the system state" }, { "q|quit", "", do_quit, "", "quit the emulator" }, - { "eject", "-fs", do_eject, + { "eject", "-fB", do_eject, "[-f] device", "eject a removable media (use -f to force it)" }, - { "change", "sF", do_change, + { "change", "BF", do_change, "device filename", "change a removable media" }, { "screendump", "F", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, @@ -505,26 +991,65 @@ static term_cmd_t term_cmds[] = { { "gdbserver", "i?", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, #endif - { "x", "/i", do_memory_dump, + { "x", "/l", do_memory_dump, "/fmt addr", "virtual memory dump starting at 'addr'", }, - { "xp", "/i", do_physical_memory_dump, + { "xp", "/l", do_physical_memory_dump, "/fmt addr", "physical memory dump starting at 'addr'", }, - { "p|print", "/i", do_print, + { "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", "s", do_send_key, + "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, + { "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" }, { NULL, NULL, }, }; static term_cmd_t info_cmds[] = { + { "version", "", do_info_version, + "", "show the version of qemu" }, { "network", "", do_info_network, "", "show the network state" }, { "block", "", do_info_block, "", "show the block devices" }, { "registers", "", do_info_registers, "", "show the cpu registers" }, + { "cpus", "", do_info_cpus, + "", "show infos for each CPU" }, { "history", "", do_info_history, "", "show the command line history", }, + { "irq", "", irq_info, + "", "show the interrupts statistics (if available)", }, { "pic", "", pic_info, "", "show i8259 (PIC) state", }, + { "pci", "", pci_info, + "", "show PCI info", }, +#if defined(TARGET_I386) + { "tlb", "", tlb_info, + "", "show virtual to physical memory mappings", }, + { "mem", "", mem_info, + "", "show the active virtual memory mappings", }, +#endif + { "jit", "", do_info_jit, + "", "show dynamic compiler info", }, + { "kqemu", "", do_info_kqemu, + "", "show kqemu information", }, + { "usb", "", usb_info, + "", "show guest USB devices", }, + { "usbhost", "", usb_host_info, + "", "show host USB devices", }, { NULL, NULL, }, }; @@ -533,55 +1058,129 @@ static term_cmd_t info_cmds[] = { static const char *pch; static jmp_buf expr_env; +#define MD_TLONG 0 +#define MD_I32 1 + typedef struct MonitorDef { const char *name; int offset; - int (*get_value)(struct MonitorDef *md); + target_long (*get_value)(struct MonitorDef *md, int val); + int type; } MonitorDef; +#if defined(TARGET_I386) +static target_long monitor_get_pc (struct MonitorDef *md, int val) +{ + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return env->eip + env->segs[R_CS].base; +} +#endif + #if defined(TARGET_PPC) -static int monitor_get_ccr (struct MonitorDef *md) +static target_long monitor_get_ccr (struct MonitorDef *md, int val) { + CPUState *env = mon_get_cpu(); unsigned int u; int i; + if (!env) + return 0; + u = 0; for (i = 0; i < 8; i++) - u |= cpu_single_env->crf[i] << (32 - (4 * i)); + u |= env->crf[i] << (32 - (4 * i)); return u; } -static int monitor_get_msr (struct MonitorDef *md) +static target_long monitor_get_msr (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) +{ + 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); +} + +static target_long monitor_get_decr (struct MonitorDef *md, int val) +{ + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return cpu_ppc_load_decr(env); +} + +static target_long monitor_get_tbu (struct MonitorDef *md, int val) +{ + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return cpu_ppc_load_tbu(env); +} + +static target_long monitor_get_tbl (struct MonitorDef *md, int val) +{ + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return cpu_ppc_load_tbl(env); +} +#endif + +#if defined(TARGET_SPARC) +#ifndef TARGET_SPARC64 +static target_long monitor_get_psr (struct MonitorDef *md, int val) { - return (cpu_single_env->msr[MSR_POW] << MSR_POW) | - (cpu_single_env->msr[MSR_ILE] << MSR_ILE) | - (cpu_single_env->msr[MSR_EE] << MSR_EE) | - (cpu_single_env->msr[MSR_PR] << MSR_PR) | - (cpu_single_env->msr[MSR_FP] << MSR_FP) | - (cpu_single_env->msr[MSR_ME] << MSR_ME) | - (cpu_single_env->msr[MSR_FE0] << MSR_FE0) | - (cpu_single_env->msr[MSR_SE] << MSR_SE) | - (cpu_single_env->msr[MSR_BE] << MSR_BE) | - (cpu_single_env->msr[MSR_FE1] << MSR_FE1) | - (cpu_single_env->msr[MSR_IP] << MSR_IP) | - (cpu_single_env->msr[MSR_IR] << MSR_IR) | - (cpu_single_env->msr[MSR_DR] << MSR_DR) | - (cpu_single_env->msr[MSR_RI] << MSR_RI) | - (cpu_single_env->msr[MSR_LE] << MSR_LE); + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return GET_PSR(env); } +#endif -static int monitor_get_xer (struct MonitorDef *md) +static target_long monitor_get_reg(struct MonitorDef *md, int val) { - return (cpu_single_env->xer[XER_SO] << XER_SO) | - (cpu_single_env->xer[XER_OV] << XER_OV) | - (cpu_single_env->xer[XER_CA] << XER_CA) | - (cpu_single_env->xer[XER_BC] << XER_BC); + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return env->regwptr[val]; } #endif static MonitorDef monitor_defs[] = { #ifdef TARGET_I386 + +#define SEG(name, seg) \ + { name, offsetof(CPUState, segs[seg].selector), NULL, MD_I32 },\ + { name ".base", offsetof(CPUState, segs[seg].base) },\ + { name ".limit", offsetof(CPUState, segs[seg].limit), NULL, MD_I32 }, + { "eax", offsetof(CPUState, regs[0]) }, { "ecx", offsetof(CPUState, regs[1]) }, { "edx", offsetof(CPUState, regs[2]) }, @@ -589,9 +1188,26 @@ static MonitorDef monitor_defs[] = { { "esp|sp", offsetof(CPUState, regs[4]) }, { "ebp|fp", offsetof(CPUState, regs[5]) }, { "esi", offsetof(CPUState, regs[6]) }, - { "esi", offsetof(CPUState, regs[7]) }, + { "edi", offsetof(CPUState, regs[7]) }, +#ifdef TARGET_X86_64 + { "r8", offsetof(CPUState, regs[8]) }, + { "r9", offsetof(CPUState, regs[9]) }, + { "r10", offsetof(CPUState, regs[10]) }, + { "r11", offsetof(CPUState, regs[11]) }, + { "r12", offsetof(CPUState, regs[12]) }, + { "r13", offsetof(CPUState, regs[13]) }, + { "r14", offsetof(CPUState, regs[14]) }, + { "r15", offsetof(CPUState, regs[15]) }, +#endif { "eflags", offsetof(CPUState, eflags) }, - { "eip|pc", offsetof(CPUState, eip) }, + { "eip", offsetof(CPUState, eip) }, + SEG("cs", R_CS) + SEG("ds", R_DS) + SEG("es", R_ES) + SEG("ss", R_SS) + SEG("fs", R_FS) + SEG("gs", R_GS) + { "pc", 0, monitor_get_pc, }, #elif defined(TARGET_PPC) { "r0", offsetof(CPUState, gpr[0]) }, { "r1", offsetof(CPUState, gpr[1]) }, @@ -625,14 +1241,15 @@ static MonitorDef monitor_defs[] = { { "r29", offsetof(CPUState, gpr[29]) }, { "r30", offsetof(CPUState, gpr[30]) }, { "r31", offsetof(CPUState, gpr[31]) }, + { "nip|pc", offsetof(CPUState, nip) }, { "lr", offsetof(CPUState, lr) }, { "ctr", offsetof(CPUState, ctr) }, - { "decr", offsetof(CPUState, decr) }, + { "decr", 0, &monitor_get_decr, }, { "ccr", 0, &monitor_get_ccr, }, { "msr", 0, &monitor_get_msr, }, { "xer", 0, &monitor_get_xer, }, - { "tbu", offsetof(CPUState, tb[0]) }, - { "tbl", offsetof(CPUState, tb[1]) }, + { "tbu", 0, &monitor_get_tbu, }, + { "tbl", 0, &monitor_get_tbl, }, { "sdr1", offsetof(CPUState, sdr1) }, { "sr0", offsetof(CPUState, sr[0]) }, { "sr1", offsetof(CPUState, sr[1]) }, @@ -651,6 +1268,106 @@ static MonitorDef monitor_defs[] = { { "sr14", offsetof(CPUState, sr[14]) }, { "sr15", offsetof(CPUState, sr[15]) }, /* Too lazy to put BATs and SPRs ... */ +#elif defined(TARGET_SPARC) + { "g0", offsetof(CPUState, gregs[0]) }, + { "g1", offsetof(CPUState, gregs[1]) }, + { "g2", offsetof(CPUState, gregs[2]) }, + { "g3", offsetof(CPUState, gregs[3]) }, + { "g4", offsetof(CPUState, gregs[4]) }, + { "g5", offsetof(CPUState, gregs[5]) }, + { "g6", offsetof(CPUState, gregs[6]) }, + { "g7", offsetof(CPUState, gregs[7]) }, + { "o0", 0, monitor_get_reg }, + { "o1", 1, monitor_get_reg }, + { "o2", 2, monitor_get_reg }, + { "o3", 3, monitor_get_reg }, + { "o4", 4, monitor_get_reg }, + { "o5", 5, monitor_get_reg }, + { "o6", 6, monitor_get_reg }, + { "o7", 7, monitor_get_reg }, + { "l0", 8, monitor_get_reg }, + { "l1", 9, monitor_get_reg }, + { "l2", 10, monitor_get_reg }, + { "l3", 11, monitor_get_reg }, + { "l4", 12, monitor_get_reg }, + { "l5", 13, monitor_get_reg }, + { "l6", 14, monitor_get_reg }, + { "l7", 15, monitor_get_reg }, + { "i0", 16, monitor_get_reg }, + { "i1", 17, monitor_get_reg }, + { "i2", 18, monitor_get_reg }, + { "i3", 19, monitor_get_reg }, + { "i4", 20, monitor_get_reg }, + { "i5", 21, monitor_get_reg }, + { "i6", 22, monitor_get_reg }, + { "i7", 23, monitor_get_reg }, + { "pc", offsetof(CPUState, pc) }, + { "npc", offsetof(CPUState, npc) }, + { "y", offsetof(CPUState, y) }, +#ifndef TARGET_SPARC64 + { "psr", 0, &monitor_get_psr, }, + { "wim", offsetof(CPUState, wim) }, +#endif + { "tbr", offsetof(CPUState, tbr) }, + { "fsr", offsetof(CPUState, fsr) }, + { "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]) }, +#ifdef TARGET_SPARC64 + { "f32", offsetof(CPUState, fpr[32]) }, + { "f34", offsetof(CPUState, fpr[34]) }, + { "f36", offsetof(CPUState, fpr[36]) }, + { "f38", offsetof(CPUState, fpr[38]) }, + { "f40", offsetof(CPUState, fpr[40]) }, + { "f42", offsetof(CPUState, fpr[42]) }, + { "f44", offsetof(CPUState, fpr[44]) }, + { "f46", offsetof(CPUState, fpr[46]) }, + { "f48", offsetof(CPUState, fpr[48]) }, + { "f50", offsetof(CPUState, fpr[50]) }, + { "f52", offsetof(CPUState, fpr[52]) }, + { "f54", offsetof(CPUState, fpr[54]) }, + { "f56", offsetof(CPUState, fpr[56]) }, + { "f58", offsetof(CPUState, fpr[58]) }, + { "f60", offsetof(CPUState, fpr[60]) }, + { "f62", offsetof(CPUState, fpr[62]) }, + { "asi", offsetof(CPUState, asi) }, + { "pstate", offsetof(CPUState, pstate) }, + { "cansave", offsetof(CPUState, cansave) }, + { "canrestore", offsetof(CPUState, canrestore) }, + { "otherwin", offsetof(CPUState, otherwin) }, + { "wstate", offsetof(CPUState, wstate) }, + { "cleanwin", offsetof(CPUState, cleanwin) }, + { "fprs", offsetof(CPUState, fprs) }, +#endif #endif { NULL }, }; @@ -662,15 +1379,32 @@ static void expr_error(const char *fmt) longjmp(expr_env, 1); } -static int get_monitor_def(int *pval, const char *name) +/* 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; + void *ptr; + for(md = monitor_defs; md->name != NULL; md++) { if (compare_cmd(name, md->name)) { if (md->get_value) { - *pval = md->get_value(md); + *pval = md->get_value(md, md->offset); } else { - *pval = *(uint32_t *)((uint8_t *)cpu_single_env + md->offset); + CPUState *env = mon_get_cpu(); + if (!env) + return -2; + ptr = (uint8_t *)env + md->offset; + switch(md->type) { + case MD_I32: + *pval = *(int32_t *)ptr; + break; + case MD_TLONG: + *pval = *(target_long *)ptr; + break; + default: + *pval = 0; + break; + } } return 0; } @@ -687,12 +1421,13 @@ static void next(void) } } -static int expr_sum(void); +static target_long expr_sum(void); -static int expr_unary(void) +static target_long expr_unary(void) { - int n; + target_long n; char *p; + int ret; switch(*pch) { case '+': @@ -715,6 +1450,16 @@ static int expr_unary(void) } next(); break; + case '\'': + pch++; + if (*pch == '\0') + expr_error("character constant expected"); + n = *pch; + pch++; + if (*pch != '\'') + expr_error("missing terminating \' character"); + next(); + break; case '$': { char buf[128], *q; @@ -724,7 +1469,7 @@ static int expr_unary(void) while ((*pch >= 'a' && *pch <= 'z') || (*pch >= 'A' && *pch <= 'Z') || (*pch >= '0' && *pch <= '9') || - *pch == '_') { + *pch == '_' || *pch == '.') { if ((q - buf) < sizeof(buf) - 1) *q++ = *pch; pch++; @@ -732,8 +1477,11 @@ static int expr_unary(void) while (isspace(*pch)) pch++; *q = 0; - if (get_monitor_def(&n, buf)) + ret = get_monitor_def(&n, buf); + if (ret == -1) expr_error("unknown register"); + else if (ret == -2) + expr_error("no cpu defined"); } break; case '\0': @@ -754,10 +1502,11 @@ static int expr_unary(void) } -static int expr_prod(void) +static target_long expr_prod(void) { - int val, val2, op; - + target_long val, val2; + int op; + val = expr_unary(); for(;;) { op = *pch; @@ -773,7 +1522,7 @@ static int expr_prod(void) case '/': case '%': if (val2 == 0) - expr_error("divison by zero"); + expr_error("division by zero"); if (op == '/') val /= val2; else @@ -784,9 +1533,10 @@ static int expr_prod(void) return val; } -static int expr_logic(void) +static target_long expr_logic(void) { - int val, val2, op; + target_long val, val2; + int op; val = expr_prod(); for(;;) { @@ -811,9 +1561,10 @@ static int expr_logic(void) return val; } -static int expr_sum(void) +static target_long expr_sum(void) { - int val, val2, op; + target_long val, val2; + int op; val = expr_logic(); for(;;) { @@ -830,7 +1581,7 @@ static int expr_sum(void) return val; } -static int get_expr(int *pval, const char **pp) +static int get_expr(target_long *pval, const char **pp) { pch = *pp; if (setjmp(expr_env)) { @@ -850,15 +1601,16 @@ static int get_str(char *buf, int buf_size, const char **pp) char *q; int c; + q = buf; p = *pp; while (isspace(*p)) p++; if (*p == '\0') { fail: + *q = '\0'; *pp = p; return -1; } - q = buf; if (*p == '\"') { p++; while (*p != '\0' && *p != '\"') { @@ -891,7 +1643,7 @@ static int get_str(char *buf, int buf_size, const char **pp) } } if (*p != '\"') { - qemu_printf("untermintated string\n"); + qemu_printf("unterminated string\n"); goto fail; } p++; @@ -902,8 +1654,8 @@ static int get_str(char *buf, int buf_size, const char **pp) } p++; } - *q = '\0'; } + *q = '\0'; *pp = p; return 0; } @@ -913,7 +1665,7 @@ static int default_fmt_size = 4; #define MAX_ARGS 16 -static void term_handle_command(const char *cmdline) +static void monitor_handle_command(const char *cmdline) { const char *p, *pstart, *typestr; char *q; @@ -966,6 +1718,7 @@ static void term_handle_command(const char *cmdline) typestr++; switch(c) { case 'F': + case 'B': case 's': { int ret; @@ -983,10 +1736,17 @@ static void term_handle_command(const char *cmdline) } ret = get_str(buf, sizeof(buf), &p); if (ret < 0) { - if (c == 'F') + switch(c) { + case 'F': term_printf("%s: filename expected\n", cmdname); - else + break; + case 'B': + term_printf("%s: block device name expected\n", cmdname); + break; + default: term_printf("%s: string expected\n", cmdname); + break; + } goto fail; } str = qemu_malloc(strlen(buf) + 1); @@ -1082,16 +1842,28 @@ static void term_handle_command(const char *cmdline) } break; case 'i': + case 'l': { - int val; + target_long val; while (isspace(*p)) p++; - if (*typestr == '?') { + if (*typestr == '?' || *typestr == '.') { typestr++; - if (*p == '\0') - has_arg = 0; - else - has_arg = 1; + if (*typestr == '?') { + if (*p == '\0') + has_arg = 0; + else + has_arg = 1; + } else { + if (*p == '.') { + p++; + while (isspace(*p)) + p++; + has_arg = 1; + } else { + has_arg = 0; + } + } if (nb_args >= MAX_ARGS) goto error_args; args[nb_args++] = (void *)has_arg; @@ -1105,9 +1877,20 @@ static void term_handle_command(const char *cmdline) if (get_expr(&val, &p)) goto fail; add_num: - if (nb_args >= MAX_ARGS) - goto error_args; - args[nb_args++] = (void *)val; + if (c == 'i') { + if (nb_args >= MAX_ARGS) + goto error_args; + args[nb_args++] = (void *)(int)val; + } else { + if ((nb_args + 1) >= MAX_ARGS) + goto error_args; +#if TARGET_LONG_BITS == 64 + args[nb_args++] = (void *)(int)((val >> 32) & 0xffffffff); +#else + args[nb_args++] = (void *)0; +#endif + args[nb_args++] = (void *)(int)(val & 0xffffffff); + } } break; case '-': @@ -1170,6 +1953,9 @@ static void term_handle_command(const char *cmdline) case 5: cmd->handler(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]); + break; default: term_printf("unsupported number of arguments: %d\n", nb_args); goto fail; @@ -1180,354 +1966,253 @@ static void term_handle_command(const char *cmdline) return; } -static void term_show_prompt(void) -{ - term_printf("(qemu) "); - fflush(stdout); - term_cmd_buf_index = 0; - term_cmd_buf_size = 0; - term_esc_state = IS_NORM; -} - -static void term_print_cmdline (const char *cmdline) -{ - term_show_prompt(); - term_printf(cmdline); - term_flush(); -} - -static void term_insert_char(int ch) +static void cmd_completion(const char *name, const char *list) { - if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) { - memmove(term_cmd_buf + term_cmd_buf_index + 1, - term_cmd_buf + term_cmd_buf_index, - term_cmd_buf_size - term_cmd_buf_index); - term_cmd_buf[term_cmd_buf_index] = ch; - term_cmd_buf_size++; - term_printf("\033[@%c", ch); - term_cmd_buf_index++; - term_flush(); - } -} + const char *p, *pstart; + char cmd[128]; + int len; -static void term_backward_char(void) -{ - if (term_cmd_buf_index > 0) { - term_cmd_buf_index--; - term_printf("\033[D"); - term_flush(); + p = list; + for(;;) { + pstart = p; + p = strchr(p, '|'); + if (!p) + p = pstart + strlen(pstart); + len = p - pstart; + if (len > sizeof(cmd) - 2) + len = sizeof(cmd) - 2; + memcpy(cmd, pstart, len); + cmd[len] = '\0'; + if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) { + add_completion(cmd); + } + if (*p == '\0') + break; + p++; } } -static void term_forward_char(void) +static void file_completion(const char *input) { - if (term_cmd_buf_index < term_cmd_buf_size) { - term_cmd_buf_index++; - term_printf("\033[C"); - term_flush(); - } -} + DIR *ffs; + struct dirent *d; + char path[1024]; + char file[1024], file_prefix[1024]; + int input_path_len; + const char *p; -static void term_delete_char(void) -{ - if (term_cmd_buf_index < term_cmd_buf_size) { - memmove(term_cmd_buf + term_cmd_buf_index, - term_cmd_buf + term_cmd_buf_index + 1, - term_cmd_buf_size - term_cmd_buf_index - 1); - term_printf("\033[P"); - term_cmd_buf_size--; - term_flush(); + p = strrchr(input, '/'); + if (!p) { + input_path_len = 0; + pstrcpy(file_prefix, sizeof(file_prefix), input); + strcpy(path, "."); + } else { + input_path_len = p - input + 1; + memcpy(path, input, input_path_len); + if (input_path_len > sizeof(path) - 1) + input_path_len = sizeof(path) - 1; + path[input_path_len] = '\0'; + pstrcpy(file_prefix, sizeof(file_prefix), p + 1); } -} - -static void term_backspace(void) -{ - if (term_cmd_buf_index > 0) { - term_backward_char(); - term_delete_char(); +#ifdef DEBUG_COMPLETION + term_printf("input='%s' path='%s' prefix='%s'\n", input, path, file_prefix); +#endif + ffs = opendir(path); + if (!ffs) + return; + for(;;) { + struct stat sb; + d = readdir(ffs); + if (!d) + break; + if (strstart(d->d_name, file_prefix, NULL)) { + memcpy(file, input, input_path_len); + strcpy(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, "/"); + add_completion(file); + } } + closedir(ffs); } -static void term_bol(void) -{ - while (term_cmd_buf_index > 0) - term_backward_char(); -} - -static void term_eol(void) -{ - while (term_cmd_buf_index < term_cmd_buf_size) - term_forward_char(); -} - -static void term_up_char(void) +static void block_completion_it(void *opaque, const char *name) { - int idx; + const char *input = opaque; - if (term_hist_entry == 0) - return; - if (term_hist_entry == -1) { - /* Find latest entry */ - for (idx = 0; idx < TERM_MAX_CMDS; idx++) { - if (term_history[idx] == NULL) - break; - } - term_hist_entry = idx; - } - term_hist_entry--; - if (term_hist_entry >= 0) { - strcpy(term_cmd_buf, term_history[term_hist_entry]); - term_printf("\n"); - term_print_cmdline(term_cmd_buf); - term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); + if (input[0] == '\0' || + !strncmp(name, (char *)input, strlen(input))) { + add_completion(name); } } -static void term_down_char(void) +/* NOTE: this parser is an approximate form of the real command parser */ +static void parse_cmdline(const char *cmdline, + int *pnb_args, char **args) { - if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1) - return; - if (term_history[++term_hist_entry] != NULL) { - strcpy(term_cmd_buf, term_history[term_hist_entry]); - } else { - term_hist_entry = -1; + const char *p; + int nb_args, ret; + char buf[1024]; + + p = cmdline; + nb_args = 0; + for(;;) { + while (isspace(*p)) + p++; + if (*p == '\0') + break; + if (nb_args >= MAX_ARGS) + break; + ret = get_str(buf, sizeof(buf), &p); + args[nb_args] = qemu_strdup(buf); + nb_args++; + if (ret < 0) + break; } - term_printf("\n"); - term_print_cmdline(term_cmd_buf); - term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); + *pnb_args = nb_args; } -static void term_hist_add(const char *cmdline) +void readline_find_completion(const char *cmdline) { - char *hist_entry, *new_entry; - int idx; + const char *cmdname; + char *args[MAX_ARGS]; + int nb_args, i, len; + const char *ptype, *str; + term_cmd_t *cmd; - if (cmdline[0] == '\0') - return; - new_entry = NULL; - if (term_hist_entry != -1) { - /* We were editing an existing history entry: replace it */ - hist_entry = term_history[term_hist_entry]; - idx = term_hist_entry; - if (strcmp(hist_entry, cmdline) == 0) { - goto same_entry; - } - } - /* Search cmdline in history buffers */ - for (idx = 0; idx < TERM_MAX_CMDS; idx++) { - hist_entry = term_history[idx]; - if (hist_entry == NULL) - break; - if (strcmp(hist_entry, cmdline) == 0) { - same_entry: - new_entry = hist_entry; - /* Put this entry at the end of history */ - memmove(&term_history[idx], &term_history[idx + 1], - &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]); - term_history[TERM_MAX_CMDS - 1] = NULL; - for (; idx < TERM_MAX_CMDS; idx++) { - if (term_history[idx] == NULL) - break; - } - break; - } + parse_cmdline(cmdline, &nb_args, args); +#ifdef DEBUG_COMPLETION + for(i = 0; i < nb_args; i++) { + term_printf("arg%d = '%s'\n", i, (char *)args[i]); } - if (idx == TERM_MAX_CMDS) { - /* Need to get one free slot */ - free(term_history[0]); - memcpy(term_history, &term_history[1], - &term_history[TERM_MAX_CMDS] - &term_history[1]); - term_history[TERM_MAX_CMDS - 1] = NULL; - idx = TERM_MAX_CMDS - 1; - } - if (new_entry == NULL) - new_entry = strdup(cmdline); - term_history[idx] = new_entry; - term_hist_entry = -1; -} +#endif -/* return true if command handled */ -static void term_handle_byte(int ch) -{ - switch(term_esc_state) { - case IS_NORM: - switch(ch) { - case 1: - term_bol(); - break; - case 5: - term_eol(); - break; - case 10: - case 13: - term_cmd_buf[term_cmd_buf_size] = '\0'; - term_hist_add(term_cmd_buf); - term_printf("\n"); - term_handle_command(term_cmd_buf); - term_show_prompt(); - break; - case 27: - term_esc_state = IS_ESC; - break; - case 127: - case 8: - term_backspace(); - break; - case 155: - term_esc_state = IS_CSI; - break; - default: - if (ch >= 32) { - term_insert_char(ch); - } - break; + /* 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 (nb_args >= MAX_ARGS) + return; + args[nb_args++] = qemu_strdup(""); + } + if (nb_args <= 1) { + /* command completion */ + if (nb_args == 0) + cmdname = ""; + else + cmdname = args[0]; + completion_index = strlen(cmdname); + for(cmd = term_cmds; cmd->name != NULL; cmd++) { + cmd_completion(cmdname, cmd->name); } - break; - case IS_ESC: - if (ch == '[') { - term_esc_state = IS_CSI; - term_esc_param = 0; - } else { - term_esc_state = IS_NORM; + } else { + /* find the command */ + for(cmd = term_cmds; cmd->name != NULL; cmd++) { + if (compare_cmd(args[0], cmd->name)) + goto found; } - break; - case IS_CSI: - switch(ch) { - case 'A': - case 'F': - term_up_char(); - break; - case 'B': - case 'E': - term_down_char(); - break; - case 'D': - term_backward_char(); + return; + found: + ptype = cmd->args_type; + for(i = 0; i < nb_args - 2; i++) { + if (*ptype != '\0') { + ptype++; + while (*ptype == '?') + ptype++; + } + } + str = args[nb_args - 1]; + switch(*ptype) { + case 'F': + /* file completion */ + completion_index = strlen(str); + file_completion(str); break; - case 'C': - term_forward_char(); + case 'B': + /* block device name completion */ + completion_index = strlen(str); + bdrv_iterate(block_completion_it, (void *)str); break; - case '0' ... '9': - term_esc_param = term_esc_param * 10 + (ch - '0'); - goto the_end; - case '~': - switch(term_esc_param) { - case 1: - term_bol(); - break; - case 3: - term_delete_char(); - break; - case 4: - term_eol(); - break; + case 's': + /* XXX: more generic ? */ + if (!strcmp(cmd->name, "info")) { + completion_index = strlen(str); + for(cmd = info_cmds; cmd->name != NULL; cmd++) { + cmd_completion(str, cmd->name); + } } break; default: break; } - term_esc_state = IS_NORM; - the_end: - break; } + for(i = 0; i < nb_args; i++) + qemu_free(args[i]); } -/*************************************************************/ -/* serial console support */ +static int term_can_read(void *opaque) +{ + return 128; +} -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ +static void term_read(void *opaque, const uint8_t *buf, int size) +{ + int i; + for(i = 0; i < size; i++) + readline_handle_byte(buf[i]); +} -static int term_got_escape, term_command; +static void monitor_start_input(void); -void term_print_help(void) +static void monitor_handle_command1(void *opaque, const char *cmdline) { - term_printf("\n" - "C-a h print this help\n" - "C-a x exit emulatior\n" - "C-a s save disk data back to file (if -snapshot)\n" - "C-a b send break (magic sysrq)\n" - "C-a c switch between console and monitor\n" - "C-a C-a send C-a\n" - ); + monitor_handle_command(cmdline); + monitor_start_input(); } -/* called when a char is received */ -static void term_received_byte(int ch) +static void monitor_start_input(void) { - if (!serial_console) { - /* if no serial console, handle every command */ - term_handle_byte(ch); - } else { - if (term_got_escape) { - term_got_escape = 0; - switch(ch) { - case 'h': - term_print_help(); - break; - case 'x': - exit(0); - break; - case 's': - { - int i; - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) - bdrv_commit(bs_table[i]); - } - } - break; - case 'b': - if (serial_console) - serial_receive_break(serial_console); - break; - case 'c': - if (!term_command) { - term_show_prompt(); - term_command = 1; - } else { - term_command = 0; - } - break; - case TERM_ESCAPE: - goto send_char; - } - } else if (ch == TERM_ESCAPE) { - term_got_escape = 1; - } else { - send_char: - if (term_command) { - term_handle_byte(ch); - } else { - if (serial_console) - serial_receive_byte(serial_console, ch); - } - } - } + readline_start("(qemu) ", 0, monitor_handle_command1, NULL); } -static int term_can_read(void *opaque) +void monitor_init(CharDriverState *hd, int show_banner) { - if (serial_console) { - return serial_can_receive(serial_console); - } else { - return 128; + monitor_hd = hd; + if (show_banner) { + term_printf("QEMU %s monitor - type 'help' for more information\n", + QEMU_VERSION); } + qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL); + monitor_start_input(); } -static void term_read(void *opaque, const uint8_t *buf, int size) +/* XXX: use threads ? */ +/* modal monitor readline */ +static int monitor_readline_started; +static char *monitor_readline_buf; +static int monitor_readline_buf_size; + +static void monitor_readline_cb(void *opaque, const char *input) { - int i; - for(i = 0; i < size; i++) - term_received_byte(buf[i]); + pstrcpy(monitor_readline_buf, monitor_readline_buf_size, input); + monitor_readline_started = 0; } -void monitor_init(void) +void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size) { - if (!serial_console) { - term_printf("QEMU %s monitor - type 'help' for more information\n", - QEMU_VERSION); - term_show_prompt(); + if (is_password) { + qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS); + } + readline_start(prompt, is_password, monitor_readline_cb, NULL); + monitor_readline_buf = buf; + monitor_readline_buf_size = buf_size; + monitor_readline_started = 1; + while (monitor_readline_started) { + main_loop_wait(10); } - term_hist_entry = -1; - qemu_add_fd_read_handler(0, term_can_read, term_read, NULL); }