Commit 9dc39cbae32d54f0f0c07337439446787f723fb7

Authored by bellard
1 parent 80cabfad

added a command line monitor


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@657 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 572 additions and 2 deletions
Makefile.target
... ... @@ -204,7 +204,8 @@ ifeq ($(ARCH),alpha)
204 204 endif
205 205  
206 206 # must use static linking to avoid leaving stuff in virtual address space
207   -VL_OBJS=vl.o osdep.o block.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \
  207 +VL_OBJS=vl.o osdep.o block.o monitor.o \
  208 + ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \
208 209 fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
209 210 ifeq ($(TARGET_ARCH), ppc)
210 211 VL_OBJS+= hw.o
... ... @@ -226,7 +227,7 @@ VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
226 227 endif
227 228  
228 229 $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
229   - $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS)
  230 + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) -lutil
230 231  
231 232 sdl.o: sdl.c
232 233 $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
... ...
monitor.c 0 → 100644
  1 +/*
  2 + * QEMU monitor
  3 + *
  4 + * Copyright (c) 2003-2004 Fabrice Bellard
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include <stdlib.h>
  25 +#include <stdio.h>
  26 +#include <stdarg.h>
  27 +#include <string.h>
  28 +#include <getopt.h>
  29 +#include <inttypes.h>
  30 +#include <unistd.h>
  31 +#include <sys/mman.h>
  32 +#include <fcntl.h>
  33 +#include <signal.h>
  34 +#include <time.h>
  35 +#include <sys/time.h>
  36 +#include <malloc.h>
  37 +#include <termios.h>
  38 +#include <sys/poll.h>
  39 +#include <errno.h>
  40 +#include <ctype.h>
  41 +
  42 +#include "cpu.h"
  43 +#include "vl.h"
  44 +
  45 +//#define DEBUG
  46 +
  47 +#define TERM_CMD_BUF_SIZE 4095
  48 +#define MAX_ARGS 64
  49 +
  50 +#define IS_NORM 0
  51 +#define IS_ESC 1
  52 +#define IS_CSI 2
  53 +
  54 +#define printf do_not_use_printf
  55 +
  56 +static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
  57 +static int term_cmd_buf_index;
  58 +static int term_cmd_buf_size;
  59 +static int term_esc_state;
  60 +static int term_esc_param;
  61 +
  62 +typedef struct term_cmd_t {
  63 + const char *name;
  64 + void (*handler)(int argc, const char **argv);
  65 + const char *params;
  66 + const char *help;
  67 +} term_cmd_t;
  68 +
  69 +static term_cmd_t term_cmds[];
  70 +static term_cmd_t info_cmds[];
  71 +
  72 +void term_printf(const char *fmt, ...)
  73 +{
  74 + va_list ap;
  75 + va_start(ap, fmt);
  76 + vprintf(fmt, ap);
  77 + va_end(ap);
  78 +}
  79 +
  80 +void term_flush(void)
  81 +{
  82 + fflush(stdout);
  83 +}
  84 +
  85 +static int compare_cmd(const char *name, const char *list)
  86 +{
  87 + const char *p, *pstart;
  88 + int len;
  89 + len = strlen(name);
  90 + p = list;
  91 + for(;;) {
  92 + pstart = p;
  93 + p = strchr(p, '|');
  94 + if (!p)
  95 + p = pstart + strlen(pstart);
  96 + if ((p - pstart) == len && !memcmp(pstart, name, len))
  97 + return 1;
  98 + if (*p == '\0')
  99 + break;
  100 + p++;
  101 + }
  102 + return 0;
  103 +}
  104 +
  105 +static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name)
  106 +{
  107 + term_cmd_t *cmd;
  108 +
  109 + for(cmd = cmds; cmd->name != NULL; cmd++) {
  110 + if (!name || !strcmp(name, cmd->name))
  111 + term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help);
  112 + }
  113 +}
  114 +
  115 +static void help_cmd(const char *name)
  116 +{
  117 + if (name && !strcmp(name, "info")) {
  118 + help_cmd1(info_cmds, "info ", NULL);
  119 + } else {
  120 + help_cmd1(term_cmds, "", name);
  121 + }
  122 +}
  123 +
  124 +static void do_help(int argc, const char **argv)
  125 +{
  126 + help_cmd(argv[1]);
  127 +}
  128 +
  129 +static void do_commit(int argc, const char **argv)
  130 +{
  131 + int i;
  132 +
  133 + for (i = 0; i < MAX_DISKS; i++) {
  134 + if (bs_table[i])
  135 + bdrv_commit(bs_table[i]);
  136 + }
  137 +}
  138 +
  139 +static void do_info(int argc, const char **argv)
  140 +{
  141 + term_cmd_t *cmd;
  142 + const char *item;
  143 +
  144 + if (argc < 2)
  145 + goto help;
  146 + item = argv[1];
  147 + for(cmd = info_cmds; cmd->name != NULL; cmd++) {
  148 + if (compare_cmd(argv[1], cmd->name))
  149 + goto found;
  150 + }
  151 + help:
  152 + help_cmd(argv[0]);
  153 + return;
  154 + found:
  155 + cmd->handler(argc, argv);
  156 +}
  157 +
  158 +static void do_info_network(int argc, const char **argv)
  159 +{
  160 + int i, j;
  161 + NetDriverState *nd;
  162 +
  163 + for(i = 0; i < nb_nics; i++) {
  164 + nd = &nd_table[i];
  165 + term_printf("%d: ifname=%s macaddr=", i, nd->ifname);
  166 + for(j = 0; j < 6; j++) {
  167 + if (j > 0)
  168 + term_printf(":");
  169 + term_printf("%02x", nd->macaddr[j]);
  170 + }
  171 + term_printf("\n");
  172 + }
  173 +}
  174 +
  175 +static void do_info_block(int argc, const char **argv)
  176 +{
  177 + bdrv_info();
  178 +}
  179 +
  180 +static void do_quit(int argc, const char **argv)
  181 +{
  182 + exit(0);
  183 +}
  184 +
  185 +static int eject_device(BlockDriverState *bs, int force)
  186 +{
  187 + if (bdrv_is_inserted(bs)) {
  188 + if (!force) {
  189 + if (!bdrv_is_removable(bs)) {
  190 + term_printf("device is not removable\n");
  191 + return -1;
  192 + }
  193 + if (bdrv_is_locked(bs)) {
  194 + term_printf("device is locked\n");
  195 + return -1;
  196 + }
  197 + }
  198 + bdrv_close(bs);
  199 + }
  200 + return 0;
  201 +}
  202 +
  203 +static void do_eject(int argc, const char **argv)
  204 +{
  205 + BlockDriverState *bs;
  206 + const char **parg;
  207 + int force;
  208 +
  209 + parg = argv + 1;
  210 + if (!*parg) {
  211 + fail:
  212 + help_cmd(argv[0]);
  213 + return;
  214 + }
  215 + force = 0;
  216 + if (!strcmp(*parg, "-f")) {
  217 + force = 1;
  218 + parg++;
  219 + }
  220 + if (!*parg)
  221 + goto fail;
  222 + bs = bdrv_find(*parg);
  223 + if (!bs) {
  224 + term_printf("device not found\n");
  225 + return;
  226 + }
  227 + eject_device(bs, force);
  228 +}
  229 +
  230 +static void do_change(int argc, const char **argv)
  231 +{
  232 + BlockDriverState *bs;
  233 +
  234 + if (argc != 3) {
  235 + help_cmd(argv[0]);
  236 + return;
  237 + }
  238 + bs = bdrv_find(argv[1]);
  239 + if (!bs) {
  240 + term_printf("device not found\n");
  241 + return;
  242 + }
  243 + if (eject_device(bs, 0) < 0)
  244 + return;
  245 + bdrv_open(bs, argv[2], 0);
  246 +}
  247 +
  248 +static term_cmd_t term_cmds[] = {
  249 + { "help|?", do_help,
  250 + "[cmd]", "show the help" },
  251 + { "commit", do_commit,
  252 + "", "commit changes to the disk images (if -snapshot is used)" },
  253 + { "info", do_info,
  254 + "subcommand", "show various information about the system state" },
  255 + { "q|quit", do_quit,
  256 + "", "quit the emulator" },
  257 + { "eject", do_eject,
  258 + "[-f] device", "eject a removable media (use -f to force it)" },
  259 + { "change", do_change,
  260 + "device filename", "change a removable media" },
  261 + { NULL, NULL, },
  262 +};
  263 +
  264 +static term_cmd_t info_cmds[] = {
  265 + { "network", do_info_network,
  266 + "", "show the network state" },
  267 + { "block", do_info_block,
  268 + "", "show the block devices" },
  269 + { NULL, NULL, },
  270 +};
  271 +
  272 +static void term_handle_command(char *cmdline)
  273 +{
  274 + char *p, *pstart;
  275 + int argc;
  276 + const char *args[MAX_ARGS + 1];
  277 + term_cmd_t *cmd;
  278 +
  279 +#ifdef DEBUG
  280 + term_printf("command='%s'\n", cmdline);
  281 +#endif
  282 +
  283 + /* split command in words */
  284 + argc = 0;
  285 + p = cmdline;
  286 + for(;;) {
  287 + while (isspace(*p))
  288 + p++;
  289 + if (*p == '\0')
  290 + break;
  291 + pstart = p;
  292 + while (*p != '\0' && !isspace(*p))
  293 + p++;
  294 + args[argc] = pstart;
  295 + argc++;
  296 + if (argc >= MAX_ARGS)
  297 + break;
  298 + if (*p == '\0')
  299 + break;
  300 + *p++ = '\0';
  301 + }
  302 + args[argc] = NULL;
  303 +#ifdef DEBUG
  304 + for(i=0;i<argc;i++) {
  305 + term_printf(" '%s'", args[i]);
  306 + }
  307 + term_printf("\n");
  308 +#endif
  309 + if (argc <= 0)
  310 + return;
  311 + for(cmd = term_cmds; cmd->name != NULL; cmd++) {
  312 + if (compare_cmd(args[0], cmd->name))
  313 + goto found;
  314 + }
  315 + term_printf("unknown command: '%s'\n", args[0]);
  316 + return;
  317 + found:
  318 + cmd->handler(argc, args);
  319 +}
  320 +
  321 +static void term_show_prompt(void)
  322 +{
  323 + term_printf("(qemu) ");
  324 + fflush(stdout);
  325 + term_cmd_buf_index = 0;
  326 + term_cmd_buf_size = 0;
  327 + term_esc_state = IS_NORM;
  328 +}
  329 +
  330 +static void term_insert_char(int ch)
  331 +{
  332 + if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
  333 + memmove(term_cmd_buf + term_cmd_buf_index + 1,
  334 + term_cmd_buf + term_cmd_buf_index,
  335 + term_cmd_buf_size - term_cmd_buf_index);
  336 + term_cmd_buf[term_cmd_buf_index] = ch;
  337 + term_cmd_buf_size++;
  338 + term_printf("\033[@%c", ch);
  339 + term_cmd_buf_index++;
  340 + term_flush();
  341 + }
  342 +}
  343 +
  344 +static void term_backward_char(void)
  345 +{
  346 + if (term_cmd_buf_index > 0) {
  347 + term_cmd_buf_index--;
  348 + term_printf("\033[D");
  349 + term_flush();
  350 + }
  351 +}
  352 +
  353 +static void term_forward_char(void)
  354 +{
  355 + if (term_cmd_buf_index < term_cmd_buf_size) {
  356 + term_cmd_buf_index++;
  357 + term_printf("\033[C");
  358 + term_flush();
  359 + }
  360 +}
  361 +
  362 +static void term_delete_char(void)
  363 +{
  364 + if (term_cmd_buf_index < term_cmd_buf_size) {
  365 + memmove(term_cmd_buf + term_cmd_buf_index,
  366 + term_cmd_buf + term_cmd_buf_index + 1,
  367 + term_cmd_buf_size - term_cmd_buf_index - 1);
  368 + term_printf("\033[P");
  369 + term_cmd_buf_size--;
  370 + term_flush();
  371 + }
  372 +}
  373 +
  374 +static void term_backspace(void)
  375 +{
  376 + if (term_cmd_buf_index > 0) {
  377 + term_backward_char();
  378 + term_delete_char();
  379 + }
  380 +}
  381 +
  382 +static void term_bol(void)
  383 +{
  384 + while (term_cmd_buf_index > 0)
  385 + term_backward_char();
  386 +}
  387 +
  388 +static void term_eol(void)
  389 +{
  390 + while (term_cmd_buf_index < term_cmd_buf_size)
  391 + term_forward_char();
  392 +}
  393 +
  394 +/* return true if command handled */
  395 +static void term_handle_byte(int ch)
  396 +{
  397 + switch(term_esc_state) {
  398 + case IS_NORM:
  399 + switch(ch) {
  400 + case 1:
  401 + term_bol();
  402 + break;
  403 + case 5:
  404 + term_eol();
  405 + break;
  406 + case 10:
  407 + case 13:
  408 + term_cmd_buf[term_cmd_buf_size] = '\0';
  409 + term_printf("\n");
  410 + term_handle_command(term_cmd_buf);
  411 + term_show_prompt();
  412 + break;
  413 + case 27:
  414 + term_esc_state = IS_ESC;
  415 + break;
  416 + case 127:
  417 + case 8:
  418 + term_backspace();
  419 + break;
  420 + default:
  421 + if (ch >= 32) {
  422 + term_insert_char(ch);
  423 + }
  424 + break;
  425 + }
  426 + break;
  427 + case IS_ESC:
  428 + if (ch == '[') {
  429 + term_esc_state = IS_CSI;
  430 + term_esc_param = 0;
  431 + } else {
  432 + term_esc_state = IS_NORM;
  433 + }
  434 + break;
  435 + case IS_CSI:
  436 + switch(ch) {
  437 + case 'D':
  438 + term_backward_char();
  439 + break;
  440 + case 'C':
  441 + term_forward_char();
  442 + break;
  443 + case '0' ... '9':
  444 + term_esc_param = term_esc_param * 10 + (ch - '0');
  445 + goto the_end;
  446 + case '~':
  447 + switch(term_esc_param) {
  448 + case 1:
  449 + term_bol();
  450 + break;
  451 + case 3:
  452 + term_delete_char();
  453 + break;
  454 + case 4:
  455 + term_eol();
  456 + break;
  457 + }
  458 + break;
  459 + default:
  460 + break;
  461 + }
  462 + term_esc_state = IS_NORM;
  463 + the_end:
  464 + break;
  465 + }
  466 +}
  467 +
  468 +/*************************************************************/
  469 +/* serial console support */
  470 +
  471 +#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
  472 +
  473 +static int term_got_escape, term_command;
  474 +
  475 +void term_print_help(void)
  476 +{
  477 + term_printf("\n"
  478 + "C-a h print this help\n"
  479 + "C-a x exit emulatior\n"
  480 + "C-a d switch on/off debug log\n"
  481 + "C-a s save disk data back to file (if -snapshot)\n"
  482 + "C-a b send break (magic sysrq)\n"
  483 + "C-a c switch between console and monitor\n"
  484 + "C-a C-a send C-a\n"
  485 + );
  486 +}
  487 +
  488 +/* called when a char is received */
  489 +static void term_received_byte(int ch)
  490 +{
  491 + if (!serial_console) {
  492 + /* if no serial console, handle every command */
  493 + term_handle_byte(ch);
  494 + } else {
  495 + if (term_got_escape) {
  496 + term_got_escape = 0;
  497 + switch(ch) {
  498 + case 'h':
  499 + term_print_help();
  500 + break;
  501 + case 'x':
  502 + exit(0);
  503 + break;
  504 + case 's':
  505 + {
  506 + int i;
  507 + for (i = 0; i < MAX_DISKS; i++) {
  508 + if (bs_table[i])
  509 + bdrv_commit(bs_table[i]);
  510 + }
  511 + }
  512 + break;
  513 + case 'b':
  514 + if (serial_console)
  515 + serial_receive_break(serial_console);
  516 + break;
  517 + case 'c':
  518 + if (!term_command) {
  519 + term_show_prompt();
  520 + term_command = 1;
  521 + } else {
  522 + term_command = 0;
  523 + }
  524 + break;
  525 + case 'd':
  526 + cpu_set_log(CPU_LOG_ALL);
  527 + break;
  528 + case TERM_ESCAPE:
  529 + goto send_char;
  530 + }
  531 + } else if (ch == TERM_ESCAPE) {
  532 + term_got_escape = 1;
  533 + } else {
  534 + send_char:
  535 + if (term_command) {
  536 + term_handle_byte(ch);
  537 + } else {
  538 + if (serial_console)
  539 + serial_receive_byte(serial_console, ch);
  540 + }
  541 + }
  542 + }
  543 +}
  544 +
  545 +static int term_can_read(void *opaque)
  546 +{
  547 + if (serial_console) {
  548 + return serial_can_receive(serial_console);
  549 + } else {
  550 + return 1;
  551 + }
  552 +}
  553 +
  554 +static void term_read(void *opaque, const uint8_t *buf, int size)
  555 +{
  556 + int i;
  557 + for(i = 0; i < size; i++)
  558 + term_received_byte(buf[i]);
  559 +}
  560 +
  561 +void monitor_init(void)
  562 +{
  563 + if (!serial_console) {
  564 + term_printf("QEMU %s monitor - type 'help' for more information\n",
  565 + QEMU_VERSION);
  566 + term_show_prompt();
  567 + }
  568 + add_fd_read_handler(0, term_can_read, term_read, NULL);
  569 +}
... ...