} term_cmd_t;
static CharDriverState *monitor_hd;
+static int hide_banner;
static term_cmd_t term_cmds[];
static term_cmd_t info_cmds[];
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();
}
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;
help_cmd(name);
}
-static void do_commit(void)
+static void do_commit(const char *device)
{
- int i;
-
+ int i, all_devices;
+
+ all_devices = !strcmp(device, "all");
for (i = 0; i < MAX_DISKS; i++) {
if (bs_table[i]) {
- bdrv_commit(bs_table[i]);
+ if (all_devices ||
+ !strcmp(bdrv_get_device_name(bs_table[i]), device))
+ bdrv_commit(bs_table[i]);
}
}
}
static void do_quit(void)
{
-#ifdef USE_KQEMU
- kqemu_record_dump();
-#endif
exit(0);
}
static void do_screen_dump(const char *filename)
{
- vga_screen_dump(filename);
+ vga_hw_screen_dump(filename);
}
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);
} 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 (env && !(env->segs[R_CS].flags & DESC_B_MASK))
- flags = 1;
+ if (env) {
+#ifdef TARGET_X86_64
+ if ((env->efer & MSR_EFER_LMA) &&
+ (env->segs[R_CS].flags & DESC_L_MASK))
+ flags = 2;
+ else
+#endif
+ if (!(env->segs[R_CS].flags & DESC_B_MASK))
+ flags = 1;
+ }
}
#endif
monitor_disas(env, addr, count, is_physical, flags);
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);
#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);
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_sum(uint32_t start, uint32_t size)
{
uint32_t addr;
{ 0x09, "8" },
{ 0x0a, "9" },
{ 0x0b, "0" },
+ { 0x0c, "minus" },
+ { 0x0d, "equal" },
{ 0x0e, "backspace" },
{ 0x0f, "tab" },
{ 0x45, "num_lock" },
{ 0x46, "scroll_lock" },
+ { 0xb5, "kp_divide" },
+ { 0x37, "kp_multiply" },
+ { 0x4a, "kp_substract" },
+ { 0x4e, "kp_add" },
+ { 0x9c, "kp_enter" },
+ { 0x53, "kp_decimal" },
+
+ { 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" },
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 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)
{
uint32_t val;
return;
}
val = env->kqemu_enabled;
- term_printf("kqemu is %s\n", val ? "enabled" : "disabled");
+ term_printf("kqemu support: ");
+ switch(val) {
+ default:
+ case 0:
+ term_printf("disabled\n");
+ break;
+ case 1:
+ term_printf("enabled for user code\n");
+ break;
+ case 2:
+ term_printf("enabled for user and kernel code\n");
+ break;
+ }
#else
- term_printf("kqemu support is not compiled\n");
+ term_printf("kqemu support: not compiled\n");
#endif
}
+#ifdef CONFIG_PROFILER
+
+int64_t kqemu_time;
+int64_t qemu_time;
+int64_t kqemu_exec_count;
+int64_t dev_time;
+int64_t kqemu_ret_int_count;
+int64_t kqemu_ret_excp_count;
+int64_t kqemu_ret_intr_count;
+
+static void do_info_profile(void)
+{
+ int64_t total;
+ total = qemu_time;
+ if (total == 0)
+ total = 1;
+ term_printf("async time %" PRId64 " (%0.3f)\n",
+ dev_time, dev_time / (double)ticks_per_sec);
+ term_printf("qemu time %" PRId64 " (%0.3f)\n",
+ qemu_time, qemu_time / (double)ticks_per_sec);
+ 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,
+ kqemu_ret_int_count,
+ kqemu_ret_excp_count,
+ kqemu_ret_intr_count);
+ qemu_time = 0;
+ kqemu_time = 0;
+ kqemu_exec_count = 0;
+ dev_time = 0;
+ kqemu_ret_int_count = 0;
+ kqemu_ret_excp_count = 0;
+ kqemu_ret_intr_count = 0;
+#ifdef USE_KQEMU
+ kqemu_record_dump();
+#endif
+}
+#else
+static void do_info_profile(void)
+{
+ term_printf("Internal profiler not compiled\n");
+}
+#endif
+
+/* 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
+int wav_start_capture (CaptureState *s, const char *path, int freq,
+ int bits, int nchannels);
+
+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));
+ if (!s) {
+ term_printf ("Not enough memory to add wave capture\n");
+ return;
+ }
+
+ 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
+
static 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,
"filename", "save screen into PPM image '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'" },
+ { "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,
"device", "remove USB device 'bus.addr'" },
{ "cpu", "i", do_cpu_set,
"index", "set the default CPU" },
+ { "mouse_move", "sss?", do_mouse_move,
+ "dx dy [dz]", "send mouse move events" },
+ { "mouse_button", "i", do_mouse_button,
+ "state", "change mouse button state (1=L, 2=M, 4=R)" },
+ { "mouse_set", "i", do_mouse_set,
+ "index", "set which mouse device receives events" },
+#ifdef HAS_AUDIO
+ { "wavcapture", "si?i?i?", do_wav_capture,
+ "path [frequency bits channels]",
+ "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" },
+#endif
+ { "stopcapture", "i", do_stop_capture,
+ "capture index", "stop capture" },
+ { "memsave", "lis", do_memory_save,
+ "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", },
{ NULL, NULL, },
};
"", "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" },
+ { "mice", "", do_info_mice,
+ "", "show which guest mouse is receiving events" },
{ NULL, NULL, },
};
n = 0;
break;
default:
+#if TARGET_LONG_BITS == 64
+ n = strtoull(pch, &p, 0);
+#else
n = strtoul(pch, &p, 0);
+#endif
if (pch == p) {
expr_error("invalid char in expression");
}
while (isspace(*p))
p++;
if (*typestr == '?' || *typestr == '.') {
- typestr++;
if (*typestr == '?') {
if (*p == '\0')
has_arg = 0;
has_arg = 0;
}
}
+ typestr++;
if (nb_args >= MAX_ARGS)
goto error_args;
args[nb_args++] = (void *)has_arg;
case 6:
cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]);
break;
+ case 7:
+ cmd->handler(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);
goto fail;
int nb_args, i, len;
const char *ptype, *str;
term_cmd_t *cmd;
+ const KeyDef *key;
parse_cmdline(cmdline, &nb_args, args);
#ifdef DEBUG_COMPLETION
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:
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();
+}
+
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);
- }
- qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL);
- monitor_start_input();
+ hide_banner = !show_banner;
+
+ qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL);
}
/* XXX: use threads ? */