Commit 20d8a3edb062c96f9a08ccf0637f76ae2563c5e1
1 parent
925fd0f2
Monitor multiplexing, by Jason Wessel.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2434 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
335 additions
and
166 deletions
monitor.c
| ... | ... | @@ -54,7 +54,8 @@ typedef struct term_cmd_t { |
| 54 | 54 | const char *help; |
| 55 | 55 | } term_cmd_t; |
| 56 | 56 | |
| 57 | -static CharDriverState *monitor_hd; | |
| 57 | +#define MAX_MON 4 | |
| 58 | +static CharDriverState *monitor_hd[MAX_MON]; | |
| 58 | 59 | static int hide_banner; |
| 59 | 60 | |
| 60 | 61 | static term_cmd_t term_cmds[]; |
| ... | ... | @@ -69,8 +70,11 @@ CPUState *mon_cpu = NULL; |
| 69 | 70 | |
| 70 | 71 | void term_flush(void) |
| 71 | 72 | { |
| 73 | + int i; | |
| 72 | 74 | if (term_outbuf_index > 0) { |
| 73 | - qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); | |
| 75 | + for (i = 0; i < MAX_MON; i++) | |
| 76 | + if (monitor_hd[i] && monitor_hd[i]->focus == 0) | |
| 77 | + qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index); | |
| 74 | 78 | term_outbuf_index = 0; |
| 75 | 79 | } |
| 76 | 80 | } |
| ... | ... | @@ -2452,9 +2456,25 @@ static void term_event(void *opaque, int event) |
| 2452 | 2456 | monitor_start_input(); |
| 2453 | 2457 | } |
| 2454 | 2458 | |
| 2459 | +static int is_first_init = 1; | |
| 2460 | + | |
| 2455 | 2461 | void monitor_init(CharDriverState *hd, int show_banner) |
| 2456 | 2462 | { |
| 2457 | - monitor_hd = hd; | |
| 2463 | + int i; | |
| 2464 | + | |
| 2465 | + if (is_first_init) { | |
| 2466 | + for (i = 0; i < MAX_MON; i++) { | |
| 2467 | + monitor_hd[i] = NULL; | |
| 2468 | + } | |
| 2469 | + is_first_init = 0; | |
| 2470 | + } | |
| 2471 | + for (i = 0; i < MAX_MON; i++) { | |
| 2472 | + if (monitor_hd[i] == NULL) { | |
| 2473 | + monitor_hd[i] = hd; | |
| 2474 | + break; | |
| 2475 | + } | |
| 2476 | + } | |
| 2477 | + | |
| 2458 | 2478 | hide_banner = !show_banner; |
| 2459 | 2479 | |
| 2460 | 2480 | qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL); |
| ... | ... | @@ -2475,8 +2495,12 @@ static void monitor_readline_cb(void *opaque, const char *input) |
| 2475 | 2495 | void monitor_readline(const char *prompt, int is_password, |
| 2476 | 2496 | char *buf, int buf_size) |
| 2477 | 2497 | { |
| 2498 | + int i; | |
| 2499 | + | |
| 2478 | 2500 | if (is_password) { |
| 2479 | - qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS); | |
| 2501 | + for (i = 0; i < MAX_MON; i++) | |
| 2502 | + if (monitor_hd[i] && monitor_hd[i]->focus == 0) | |
| 2503 | + qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS); | |
| 2480 | 2504 | } |
| 2481 | 2505 | readline_start(prompt, is_password, monitor_readline_cb, NULL); |
| 2482 | 2506 | monitor_readline_buf = buf; | ... | ... |
qemu-doc.texi
| ... | ... | @@ -610,6 +610,18 @@ A unix domain socket is used instead of a tcp socket. The option works the |
| 610 | 610 | same as if you had specified @code{-serial tcp} except the unix domain socket |
| 611 | 611 | @var{path} is used for connections. |
| 612 | 612 | |
| 613 | +@item mon:dev_string | |
| 614 | +This is a special option to allow the monitor to be multiplexed onto | |
| 615 | +another serial port. The monitor is accessed with key sequence of | |
| 616 | +@key{Control-a} and then pressing @key{c}. See monitor access | |
| 617 | +@ref{pcsys_keys} in the -nographic section for more keys. | |
| 618 | +@var{dev_string} should be any one of the serial devices specified | |
| 619 | +above. An example to multiplex the monitor onto a telnet server | |
| 620 | +listening on port 4444 would be: | |
| 621 | +@table @code | |
| 622 | +@item -serial mon:telnet::4444,server,nowait | |
| 623 | +@end table | |
| 624 | + | |
| 613 | 625 | @end table |
| 614 | 626 | |
| 615 | 627 | @item -parallel dev |
| ... | ... | @@ -629,6 +641,19 @@ serial port). |
| 629 | 641 | The default device is @code{vc} in graphical mode and @code{stdio} in |
| 630 | 642 | non graphical mode. |
| 631 | 643 | |
| 644 | +@item -echr numeric_ascii_value | |
| 645 | +Change the escape character used for switching to the monitor when using | |
| 646 | +monitor and serial sharing. The default is @code{0x01} when using the | |
| 647 | +@code{-nographic} option. @code{0x01} is equal to pressing | |
| 648 | +@code{Control-a}. You can select a different character from the ascii | |
| 649 | +control keys where 1 through 26 map to Control-a through Control-z. For | |
| 650 | +instance you could use the either of the following to change the escape | |
| 651 | +character to Control-t. | |
| 652 | +@table @code | |
| 653 | +@item -echr 0x14 | |
| 654 | +@item -echr 20 | |
| 655 | +@end table | |
| 656 | + | |
| 632 | 657 | @item -s |
| 633 | 658 | Wait gdb connection to port 1234 (@pxref{gdb_usage}). |
| 634 | 659 | @item -p port |
| ... | ... | @@ -711,6 +736,8 @@ Print this help |
| 711 | 736 | Exit emulator |
| 712 | 737 | @item Ctrl-a s |
| 713 | 738 | Save disk data back to file (if -snapshot) |
| 739 | +@item Ctrl-a t | |
| 740 | +toggle console timestamps | |
| 714 | 741 | @item Ctrl-a b |
| 715 | 742 | Send break (magic sysrq in Linux) |
| 716 | 743 | @item Ctrl-a c | ... | ... |
vl.c
| ... | ... | @@ -1228,6 +1228,218 @@ static CharDriverState *qemu_chr_open_null(void) |
| 1228 | 1228 | return chr; |
| 1229 | 1229 | } |
| 1230 | 1230 | |
| 1231 | +/* MUX driver for serial I/O splitting */ | |
| 1232 | +static int term_timestamps; | |
| 1233 | +static int64_t term_timestamps_start; | |
| 1234 | +#define MAX_MUX 2 | |
| 1235 | +typedef struct { | |
| 1236 | + IOCanRWHandler *chr_can_read[MAX_MUX]; | |
| 1237 | + IOReadHandler *chr_read[MAX_MUX]; | |
| 1238 | + IOEventHandler *chr_event[MAX_MUX]; | |
| 1239 | + void *ext_opaque[MAX_MUX]; | |
| 1240 | + CharDriverState *drv; | |
| 1241 | + int mux_cnt; | |
| 1242 | + int term_got_escape; | |
| 1243 | + int max_size; | |
| 1244 | +} MuxDriver; | |
| 1245 | + | |
| 1246 | + | |
| 1247 | +static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) | |
| 1248 | +{ | |
| 1249 | + MuxDriver *d = chr->opaque; | |
| 1250 | + int ret; | |
| 1251 | + if (!term_timestamps) { | |
| 1252 | + ret = d->drv->chr_write(d->drv, buf, len); | |
| 1253 | + } else { | |
| 1254 | + int i; | |
| 1255 | + | |
| 1256 | + ret = 0; | |
| 1257 | + for(i = 0; i < len; i++) { | |
| 1258 | + ret += d->drv->chr_write(d->drv, buf+i, 1); | |
| 1259 | + if (buf[i] == '\n') { | |
| 1260 | + char buf1[64]; | |
| 1261 | + int64_t ti; | |
| 1262 | + int secs; | |
| 1263 | + | |
| 1264 | + ti = get_clock(); | |
| 1265 | + if (term_timestamps_start == -1) | |
| 1266 | + term_timestamps_start = ti; | |
| 1267 | + ti -= term_timestamps_start; | |
| 1268 | + secs = ti / 1000000000; | |
| 1269 | + snprintf(buf1, sizeof(buf1), | |
| 1270 | + "[%02d:%02d:%02d.%03d] ", | |
| 1271 | + secs / 3600, | |
| 1272 | + (secs / 60) % 60, | |
| 1273 | + secs % 60, | |
| 1274 | + (int)((ti / 1000000) % 1000)); | |
| 1275 | + d->drv->chr_write(d->drv, buf1, strlen(buf1)); | |
| 1276 | + } | |
| 1277 | + } | |
| 1278 | + } | |
| 1279 | + return ret; | |
| 1280 | +} | |
| 1281 | + | |
| 1282 | +static char *mux_help[] = { | |
| 1283 | + "% h print this help\n\r", | |
| 1284 | + "% x exit emulator\n\r", | |
| 1285 | + "% s save disk data back to file (if -snapshot)\n\r", | |
| 1286 | + "% t toggle console timestamps\n\r" | |
| 1287 | + "% b send break (magic sysrq)\n\r", | |
| 1288 | + "% c switch between console and monitor\n\r", | |
| 1289 | + "% % sends %\n\r", | |
| 1290 | + NULL | |
| 1291 | +}; | |
| 1292 | + | |
| 1293 | +static int term_escape_char = 0x01; /* ctrl-a is used for escape */ | |
| 1294 | +static void mux_print_help(CharDriverState *chr) | |
| 1295 | +{ | |
| 1296 | + int i, j; | |
| 1297 | + char ebuf[15] = "Escape-Char"; | |
| 1298 | + char cbuf[50] = "\n\r"; | |
| 1299 | + | |
| 1300 | + if (term_escape_char > 0 && term_escape_char < 26) { | |
| 1301 | + sprintf(cbuf,"\n\r"); | |
| 1302 | + sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a'); | |
| 1303 | + } else { | |
| 1304 | + sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", term_escape_char); | |
| 1305 | + } | |
| 1306 | + chr->chr_write(chr, cbuf, strlen(cbuf)); | |
| 1307 | + for (i = 0; mux_help[i] != NULL; i++) { | |
| 1308 | + for (j=0; mux_help[i][j] != '\0'; j++) { | |
| 1309 | + if (mux_help[i][j] == '%') | |
| 1310 | + chr->chr_write(chr, ebuf, strlen(ebuf)); | |
| 1311 | + else | |
| 1312 | + chr->chr_write(chr, &mux_help[i][j], 1); | |
| 1313 | + } | |
| 1314 | + } | |
| 1315 | +} | |
| 1316 | + | |
| 1317 | +static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) | |
| 1318 | +{ | |
| 1319 | + if (d->term_got_escape) { | |
| 1320 | + d->term_got_escape = 0; | |
| 1321 | + if (ch == term_escape_char) | |
| 1322 | + goto send_char; | |
| 1323 | + switch(ch) { | |
| 1324 | + case '?': | |
| 1325 | + case 'h': | |
| 1326 | + mux_print_help(chr); | |
| 1327 | + break; | |
| 1328 | + case 'x': | |
| 1329 | + { | |
| 1330 | + char *term = "QEMU: Terminated\n\r"; | |
| 1331 | + chr->chr_write(chr,term,strlen(term)); | |
| 1332 | + exit(0); | |
| 1333 | + break; | |
| 1334 | + } | |
| 1335 | + case 's': | |
| 1336 | + { | |
| 1337 | + int i; | |
| 1338 | + for (i = 0; i < MAX_DISKS; i++) { | |
| 1339 | + if (bs_table[i]) | |
| 1340 | + bdrv_commit(bs_table[i]); | |
| 1341 | + } | |
| 1342 | + } | |
| 1343 | + break; | |
| 1344 | + case 'b': | |
| 1345 | + if (chr->chr_event) | |
| 1346 | + chr->chr_event(chr->opaque, CHR_EVENT_BREAK); | |
| 1347 | + break; | |
| 1348 | + case 'c': | |
| 1349 | + /* Switch to the next registered device */ | |
| 1350 | + chr->focus++; | |
| 1351 | + if (chr->focus >= d->mux_cnt) | |
| 1352 | + chr->focus = 0; | |
| 1353 | + break; | |
| 1354 | + case 't': | |
| 1355 | + term_timestamps = !term_timestamps; | |
| 1356 | + term_timestamps_start = -1; | |
| 1357 | + break; | |
| 1358 | + } | |
| 1359 | + } else if (ch == term_escape_char) { | |
| 1360 | + d->term_got_escape = 1; | |
| 1361 | + } else { | |
| 1362 | + send_char: | |
| 1363 | + return 1; | |
| 1364 | + } | |
| 1365 | + return 0; | |
| 1366 | +} | |
| 1367 | + | |
| 1368 | +static int mux_chr_can_read(void *opaque) | |
| 1369 | +{ | |
| 1370 | + CharDriverState *chr = opaque; | |
| 1371 | + MuxDriver *d = chr->opaque; | |
| 1372 | + if (d->chr_can_read[chr->focus]) | |
| 1373 | + return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); | |
| 1374 | + return 0; | |
| 1375 | +} | |
| 1376 | + | |
| 1377 | +static void mux_chr_read(void *opaque, const uint8_t *buf, int size) | |
| 1378 | +{ | |
| 1379 | + CharDriverState *chr = opaque; | |
| 1380 | + MuxDriver *d = chr->opaque; | |
| 1381 | + int i; | |
| 1382 | + for(i = 0; i < size; i++) | |
| 1383 | + if (mux_proc_byte(chr, d, buf[i])) | |
| 1384 | + d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1); | |
| 1385 | +} | |
| 1386 | + | |
| 1387 | +static void mux_chr_event(void *opaque, int event) | |
| 1388 | +{ | |
| 1389 | + CharDriverState *chr = opaque; | |
| 1390 | + MuxDriver *d = chr->opaque; | |
| 1391 | + int i; | |
| 1392 | + | |
| 1393 | + /* Send the event to all registered listeners */ | |
| 1394 | + for (i = 0; i < d->mux_cnt; i++) | |
| 1395 | + if (d->chr_event[i]) | |
| 1396 | + d->chr_event[i](d->ext_opaque[i], event); | |
| 1397 | +} | |
| 1398 | + | |
| 1399 | +static void mux_chr_update_read_handler(CharDriverState *chr) | |
| 1400 | +{ | |
| 1401 | + MuxDriver *d = chr->opaque; | |
| 1402 | + | |
| 1403 | + if (d->mux_cnt >= MAX_MUX) { | |
| 1404 | + fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); | |
| 1405 | + return; | |
| 1406 | + } | |
| 1407 | + d->ext_opaque[d->mux_cnt] = chr->handler_opaque; | |
| 1408 | + d->chr_can_read[d->mux_cnt] = chr->chr_can_read; | |
| 1409 | + d->chr_read[d->mux_cnt] = chr->chr_read; | |
| 1410 | + d->chr_event[d->mux_cnt] = chr->chr_event; | |
| 1411 | + /* Fix up the real driver with mux routines */ | |
| 1412 | + if (d->mux_cnt == 0) { | |
| 1413 | + qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, | |
| 1414 | + mux_chr_event, chr); | |
| 1415 | + } | |
| 1416 | + chr->focus = d->mux_cnt; | |
| 1417 | + d->mux_cnt++; | |
| 1418 | +} | |
| 1419 | + | |
| 1420 | +CharDriverState *qemu_chr_open_mux(CharDriverState *drv) | |
| 1421 | +{ | |
| 1422 | + CharDriverState *chr; | |
| 1423 | + MuxDriver *d; | |
| 1424 | + | |
| 1425 | + chr = qemu_mallocz(sizeof(CharDriverState)); | |
| 1426 | + if (!chr) | |
| 1427 | + return NULL; | |
| 1428 | + d = qemu_mallocz(sizeof(MuxDriver)); | |
| 1429 | + if (!d) { | |
| 1430 | + free(chr); | |
| 1431 | + return NULL; | |
| 1432 | + } | |
| 1433 | + | |
| 1434 | + chr->opaque = d; | |
| 1435 | + d->drv = drv; | |
| 1436 | + chr->focus = -1; | |
| 1437 | + chr->chr_write = mux_chr_write; | |
| 1438 | + chr->chr_update_read_handler = mux_chr_update_read_handler; | |
| 1439 | + return chr; | |
| 1440 | +} | |
| 1441 | + | |
| 1442 | + | |
| 1231 | 1443 | #ifdef _WIN32 |
| 1232 | 1444 | |
| 1233 | 1445 | static void socket_cleanup(void) |
| ... | ... | @@ -1319,10 +1531,8 @@ typedef struct { |
| 1319 | 1531 | int max_size; |
| 1320 | 1532 | } FDCharDriver; |
| 1321 | 1533 | |
| 1322 | -#define STDIO_MAX_CLIENTS 2 | |
| 1323 | - | |
| 1324 | -static int stdio_nb_clients; | |
| 1325 | -static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; | |
| 1534 | +#define STDIO_MAX_CLIENTS 1 | |
| 1535 | +static int stdio_nb_clients = 0; | |
| 1326 | 1536 | |
| 1327 | 1537 | static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) |
| 1328 | 1538 | { |
| ... | ... | @@ -1435,162 +1645,45 @@ static CharDriverState *qemu_chr_open_pipe(const char *filename) |
| 1435 | 1645 | /* for STDIO, we handle the case where several clients use it |
| 1436 | 1646 | (nographic mode) */ |
| 1437 | 1647 | |
| 1438 | -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ | |
| 1439 | - | |
| 1440 | 1648 | #define TERM_FIFO_MAX_SIZE 1 |
| 1441 | 1649 | |
| 1442 | -static int term_got_escape, client_index; | |
| 1443 | 1650 | static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; |
| 1444 | 1651 | static int term_fifo_size; |
| 1445 | -static int term_timestamps; | |
| 1446 | -static int64_t term_timestamps_start; | |
| 1447 | - | |
| 1448 | -void term_print_help(void) | |
| 1449 | -{ | |
| 1450 | - printf("\n" | |
| 1451 | - "C-a h print this help\n" | |
| 1452 | - "C-a x exit emulator\n" | |
| 1453 | - "C-a s save disk data back to file (if -snapshot)\n" | |
| 1454 | - "C-a b send break (magic sysrq)\n" | |
| 1455 | - "C-a t toggle console timestamps\n" | |
| 1456 | - "C-a c switch between console and monitor\n" | |
| 1457 | - "C-a C-a send C-a\n" | |
| 1458 | - ); | |
| 1459 | -} | |
| 1460 | - | |
| 1461 | -/* called when a char is received */ | |
| 1462 | -static void stdio_received_byte(int ch) | |
| 1463 | -{ | |
| 1464 | - if (term_got_escape) { | |
| 1465 | - term_got_escape = 0; | |
| 1466 | - switch(ch) { | |
| 1467 | - case 'h': | |
| 1468 | - term_print_help(); | |
| 1469 | - break; | |
| 1470 | - case 'x': | |
| 1471 | - exit(0); | |
| 1472 | - break; | |
| 1473 | - case 's': | |
| 1474 | - { | |
| 1475 | - int i; | |
| 1476 | - for (i = 0; i < MAX_DISKS; i++) { | |
| 1477 | - if (bs_table[i]) | |
| 1478 | - bdrv_commit(bs_table[i]); | |
| 1479 | - } | |
| 1480 | - } | |
| 1481 | - break; | |
| 1482 | - case 'b': | |
| 1483 | - if (client_index < stdio_nb_clients) { | |
| 1484 | - CharDriverState *chr; | |
| 1485 | - FDCharDriver *s; | |
| 1486 | - | |
| 1487 | - chr = stdio_clients[client_index]; | |
| 1488 | - s = chr->opaque; | |
| 1489 | - qemu_chr_event(chr, CHR_EVENT_BREAK); | |
| 1490 | - } | |
| 1491 | - break; | |
| 1492 | - case 'c': | |
| 1493 | - client_index++; | |
| 1494 | - if (client_index >= stdio_nb_clients) | |
| 1495 | - client_index = 0; | |
| 1496 | - if (client_index == 0) { | |
| 1497 | - /* send a new line in the monitor to get the prompt */ | |
| 1498 | - ch = '\r'; | |
| 1499 | - goto send_char; | |
| 1500 | - } | |
| 1501 | - break; | |
| 1502 | - case 't': | |
| 1503 | - term_timestamps = !term_timestamps; | |
| 1504 | - term_timestamps_start = -1; | |
| 1505 | - break; | |
| 1506 | - case TERM_ESCAPE: | |
| 1507 | - goto send_char; | |
| 1508 | - } | |
| 1509 | - } else if (ch == TERM_ESCAPE) { | |
| 1510 | - term_got_escape = 1; | |
| 1511 | - } else { | |
| 1512 | - send_char: | |
| 1513 | - if (client_index < stdio_nb_clients) { | |
| 1514 | - uint8_t buf[1]; | |
| 1515 | - CharDriverState *chr; | |
| 1516 | - | |
| 1517 | - chr = stdio_clients[client_index]; | |
| 1518 | - if (qemu_chr_can_read(chr) > 0) { | |
| 1519 | - buf[0] = ch; | |
| 1520 | - qemu_chr_read(chr, buf, 1); | |
| 1521 | - } else if (term_fifo_size == 0) { | |
| 1522 | - term_fifo[term_fifo_size++] = ch; | |
| 1523 | - } | |
| 1524 | - } | |
| 1525 | - } | |
| 1526 | -} | |
| 1527 | 1652 | |
| 1528 | 1653 | static int stdio_read_poll(void *opaque) |
| 1529 | 1654 | { |
| 1530 | - CharDriverState *chr; | |
| 1655 | + CharDriverState *chr = opaque; | |
| 1531 | 1656 | |
| 1532 | - if (client_index < stdio_nb_clients) { | |
| 1533 | - chr = stdio_clients[client_index]; | |
| 1534 | - /* try to flush the queue if needed */ | |
| 1535 | - if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { | |
| 1536 | - qemu_chr_read(chr, term_fifo, 1); | |
| 1537 | - term_fifo_size = 0; | |
| 1538 | - } | |
| 1539 | - /* see if we can absorb more chars */ | |
| 1540 | - if (term_fifo_size == 0) | |
| 1541 | - return 1; | |
| 1542 | - else | |
| 1543 | - return 0; | |
| 1544 | - } else { | |
| 1545 | - return 1; | |
| 1657 | + /* try to flush the queue if needed */ | |
| 1658 | + if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { | |
| 1659 | + qemu_chr_read(chr, term_fifo, 1); | |
| 1660 | + term_fifo_size = 0; | |
| 1546 | 1661 | } |
| 1662 | + /* see if we can absorb more chars */ | |
| 1663 | + if (term_fifo_size == 0) | |
| 1664 | + return 1; | |
| 1665 | + else | |
| 1666 | + return 0; | |
| 1547 | 1667 | } |
| 1548 | 1668 | |
| 1549 | 1669 | static void stdio_read(void *opaque) |
| 1550 | 1670 | { |
| 1551 | 1671 | int size; |
| 1552 | 1672 | uint8_t buf[1]; |
| 1553 | - | |
| 1673 | + CharDriverState *chr = opaque; | |
| 1674 | + | |
| 1554 | 1675 | size = read(0, buf, 1); |
| 1555 | 1676 | if (size == 0) { |
| 1556 | 1677 | /* stdin has been closed. Remove it from the active list. */ |
| 1557 | 1678 | qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); |
| 1558 | 1679 | return; |
| 1559 | 1680 | } |
| 1560 | - if (size > 0) | |
| 1561 | - stdio_received_byte(buf[0]); | |
| 1562 | -} | |
| 1563 | - | |
| 1564 | -static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len) | |
| 1565 | -{ | |
| 1566 | - FDCharDriver *s = chr->opaque; | |
| 1567 | - if (!term_timestamps) { | |
| 1568 | - return unix_write(s->fd_out, buf, len); | |
| 1569 | - } else { | |
| 1570 | - int i; | |
| 1571 | - char buf1[64]; | |
| 1572 | - | |
| 1573 | - for(i = 0; i < len; i++) { | |
| 1574 | - unix_write(s->fd_out, buf + i, 1); | |
| 1575 | - if (buf[i] == '\n') { | |
| 1576 | - int64_t ti; | |
| 1577 | - int secs; | |
| 1578 | - | |
| 1579 | - ti = get_clock(); | |
| 1580 | - if (term_timestamps_start == -1) | |
| 1581 | - term_timestamps_start = ti; | |
| 1582 | - ti -= term_timestamps_start; | |
| 1583 | - secs = ti / 1000000000; | |
| 1584 | - snprintf(buf1, sizeof(buf1), | |
| 1585 | - "[%02d:%02d:%02d.%03d] ", | |
| 1586 | - secs / 3600, | |
| 1587 | - (secs / 60) % 60, | |
| 1588 | - secs % 60, | |
| 1589 | - (int)((ti / 1000000) % 1000)); | |
| 1590 | - unix_write(s->fd_out, buf1, strlen(buf1)); | |
| 1591 | - } | |
| 1681 | + if (size > 0) { | |
| 1682 | + if (qemu_chr_can_read(chr) > 0) { | |
| 1683 | + qemu_chr_read(chr, buf, 1); | |
| 1684 | + } else if (term_fifo_size == 0) { | |
| 1685 | + term_fifo[term_fifo_size++] = buf[0]; | |
| 1592 | 1686 | } |
| 1593 | - return len; | |
| 1594 | 1687 | } |
| 1595 | 1688 | } |
| 1596 | 1689 | |
| ... | ... | @@ -1635,24 +1728,13 @@ static CharDriverState *qemu_chr_open_stdio(void) |
| 1635 | 1728 | { |
| 1636 | 1729 | CharDriverState *chr; |
| 1637 | 1730 | |
| 1638 | - if (nographic) { | |
| 1639 | - if (stdio_nb_clients >= STDIO_MAX_CLIENTS) | |
| 1640 | - return NULL; | |
| 1641 | - chr = qemu_chr_open_fd(0, 1); | |
| 1642 | - chr->chr_write = stdio_write; | |
| 1643 | - if (stdio_nb_clients == 0) | |
| 1644 | - qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL); | |
| 1645 | - client_index = stdio_nb_clients; | |
| 1646 | - } else { | |
| 1647 | - if (stdio_nb_clients != 0) | |
| 1648 | - return NULL; | |
| 1649 | - chr = qemu_chr_open_fd(0, 1); | |
| 1650 | - } | |
| 1651 | - stdio_clients[stdio_nb_clients++] = chr; | |
| 1652 | - if (stdio_nb_clients == 1) { | |
| 1653 | - /* set the terminal in raw mode */ | |
| 1654 | - term_init(); | |
| 1655 | - } | |
| 1731 | + if (stdio_nb_clients >= STDIO_MAX_CLIENTS) | |
| 1732 | + return NULL; | |
| 1733 | + chr = qemu_chr_open_fd(0, 1); | |
| 1734 | + qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); | |
| 1735 | + stdio_nb_clients++; | |
| 1736 | + term_init(); | |
| 1737 | + | |
| 1656 | 1738 | return chr; |
| 1657 | 1739 | } |
| 1658 | 1740 | |
| ... | ... | @@ -2815,6 +2897,16 @@ CharDriverState *qemu_chr_open(const char *filename) |
| 2815 | 2897 | if (strstart(filename, "udp:", &p)) { |
| 2816 | 2898 | return qemu_chr_open_udp(p); |
| 2817 | 2899 | } else |
| 2900 | + if (strstart(filename, "mon:", &p)) { | |
| 2901 | + CharDriverState *drv = qemu_chr_open(p); | |
| 2902 | + if (drv) { | |
| 2903 | + drv = qemu_chr_open_mux(drv); | |
| 2904 | + monitor_init(drv, !nographic); | |
| 2905 | + return drv; | |
| 2906 | + } | |
| 2907 | + printf("Unable to open driver: %s\n", p); | |
| 2908 | + return 0; | |
| 2909 | + } else | |
| 2818 | 2910 | #ifndef _WIN32 |
| 2819 | 2911 | if (strstart(filename, "unix:", &p)) { |
| 2820 | 2912 | return qemu_chr_open_tcp(p, 0, 1); |
| ... | ... | @@ -6416,6 +6508,7 @@ enum { |
| 6416 | 6508 | QEMU_OPTION_cirrusvga, |
| 6417 | 6509 | QEMU_OPTION_g, |
| 6418 | 6510 | QEMU_OPTION_std_vga, |
| 6511 | + QEMU_OPTION_echr, | |
| 6419 | 6512 | QEMU_OPTION_monitor, |
| 6420 | 6513 | QEMU_OPTION_serial, |
| 6421 | 6514 | QEMU_OPTION_parallel, |
| ... | ... | @@ -6497,6 +6590,7 @@ const QEMUOption qemu_options[] = { |
| 6497 | 6590 | #endif |
| 6498 | 6591 | { "localtime", 0, QEMU_OPTION_localtime }, |
| 6499 | 6592 | { "std-vga", 0, QEMU_OPTION_std_vga }, |
| 6593 | + { "echr", 1, QEMU_OPTION_echr }, | |
| 6500 | 6594 | { "monitor", 1, QEMU_OPTION_monitor }, |
| 6501 | 6595 | { "serial", 1, QEMU_OPTION_serial }, |
| 6502 | 6596 | { "parallel", 1, QEMU_OPTION_parallel }, |
| ... | ... | @@ -6932,8 +7026,8 @@ int main(int argc, char **argv) |
| 6932 | 7026 | } |
| 6933 | 7027 | break; |
| 6934 | 7028 | case QEMU_OPTION_nographic: |
| 6935 | - pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); | |
| 6936 | 7029 | pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); |
| 7030 | + pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); | |
| 6937 | 7031 | nographic = 1; |
| 6938 | 7032 | break; |
| 6939 | 7033 | case QEMU_OPTION_kernel: |
| ... | ... | @@ -7094,6 +7188,14 @@ int main(int argc, char **argv) |
| 7094 | 7188 | graphic_depth = depth; |
| 7095 | 7189 | } |
| 7096 | 7190 | break; |
| 7191 | + case QEMU_OPTION_echr: | |
| 7192 | + { | |
| 7193 | + char *r; | |
| 7194 | + term_escape_char = strtol(optarg, &r, 0); | |
| 7195 | + if (r == optarg) | |
| 7196 | + printf("Bad argument to echr\n"); | |
| 7197 | + break; | |
| 7198 | + } | |
| 7097 | 7199 | case QEMU_OPTION_monitor: |
| 7098 | 7200 | pstrcpy(monitor_device, sizeof(monitor_device), optarg); |
| 7099 | 7201 | break; |
| ... | ... | @@ -7384,12 +7486,27 @@ int main(int argc, char **argv) |
| 7384 | 7486 | #endif |
| 7385 | 7487 | } |
| 7386 | 7488 | |
| 7387 | - monitor_hd = qemu_chr_open(monitor_device); | |
| 7388 | - if (!monitor_hd) { | |
| 7389 | - fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); | |
| 7390 | - exit(1); | |
| 7489 | + /* Maintain compatibility with multiple stdio monitors */ | |
| 7490 | + if (!strcmp(monitor_device,"stdio")) { | |
| 7491 | + for (i = 0; i < MAX_SERIAL_PORTS; i++) { | |
| 7492 | + if (!strcmp(serial_devices[i],"mon:stdio")) { | |
| 7493 | + monitor_device[0] = '\0'; | |
| 7494 | + break; | |
| 7495 | + } else if (!strcmp(serial_devices[i],"stdio")) { | |
| 7496 | + monitor_device[0] = '\0'; | |
| 7497 | + pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "mon:stdio"); | |
| 7498 | + break; | |
| 7499 | + } | |
| 7500 | + } | |
| 7501 | + } | |
| 7502 | + if (monitor_device[0] != '\0') { | |
| 7503 | + monitor_hd = qemu_chr_open(monitor_device); | |
| 7504 | + if (!monitor_hd) { | |
| 7505 | + fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); | |
| 7506 | + exit(1); | |
| 7507 | + } | |
| 7508 | + monitor_init(monitor_hd, !nographic); | |
| 7391 | 7509 | } |
| 7392 | - monitor_init(monitor_hd, !nographic); | |
| 7393 | 7510 | |
| 7394 | 7511 | for(i = 0; i < MAX_SERIAL_PORTS; i++) { |
| 7395 | 7512 | const char *devname = serial_devices[i]; | ... | ... |
vl.h