qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 5/5] Netconsole and updated Monitor support


From: Jason Wessel
Subject: [Qemu-devel] [PATCH 5/5] Netconsole and updated Monitor support
Date: Sat, 20 May 2006 16:02:16 -0500
User-agent: Thunderbird 1.5.0.2 (Windows/20060308)

This patch add support for remote net consoles via udp similar to what you would do with a net console with u-boot or a linux kernel. Typically you use the netcat tool for this.

This patch also partially abstracts the ability to switch between the monitor and the main focus of a port. I say it is only partially abstracted, because I only implemented the shared console support for the stdio and udp consoles. To minimize the amount of changes in this patch, I left the stdio driver's stdio_clients array alone. It seems that its main purpose was for monitor sharing, but I was not certain. If the only purpose was for the monitor, then the array can be refactored out in the future.

The code well on Win32 and Linux. The original command line arguments and defaults were all preserved. The new command line options were documented in the documentation section of the patch.

signed-off-by: address@hidden

Jason.

PS:
I can also supply the netcat patches to force telnet into character mode with remote echo turned on.
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c
+++ qemu/vl.c
@@ -1132,6 +1132,160 @@ CharDriverState *qemu_chr_open_null(void
     return chr;
 }
 
+typedef struct {
+    IOCanRWHandler *fd_can_read;
+    IOReadHandler *fd_read;
+    void *ext_opaque;
+    int fd_in, fd_out;
+    void *mon_orig;
+    void *mon_opaque;
+    int max_size;
+} MonitorDriver;
+
+#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
+static MonitorDriver *mon_priv; /* pointer to current monitor console */
+static int term_got_escape = 0;
+void monitor_print_help(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    char *buf = "\n\r"
+           "C-a h    print this help\n\r"
+           "C-a x    exit emulator\n\r"
+           "C-a s    save disk data back to file (if -snapshot)\n\r"
+           "C-a b    send break (magic sysrq)\n\r"
+           "C-a c    switch between console and monitor\n\r"
+        "C-a C-a  send C-a\n\r";
+    chr->chr_write(chr, buf, strlen(buf));
+}
+
+/* An I/O driver can choose to call this to get shared monitor
+ * support.  The routine returns 1 if the caller should process the
+ * character else it returns 0 to indicate that the character was
+ * handled by this routine.
+ */
+static int proc_received_byte(int ch, void *opaque)
+{
+    CharDriverState *chr = opaque;
+
+    if (!chr->monitorEnabled)
+        goto send_char;
+    if (term_got_escape) {
+        term_got_escape = 0;
+        switch(ch) {
+        case 'h':
+            monitor_print_help(opaque);
+            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':
+            {
+                CharDriverState *chr;
+                /* Note that this is dependant on each driver which
+                 * calls this proc_received_byte an opaque pointer at
+                 * the same ofset in the structure.  A some futre time this
+                 * might have to be abstracted via opaque.
+                 *
+                 * IE: MonitorDriver, FDCharDriver, WinCharState
+                 * ---
+                 * IOCanRWHandler *can_read;
+                 * IOReadHandler *read;
+                 * void *opaque;
+                 * ---
+                 */
+                MonitorDriver *s;
+
+                chr = opaque;
+                s = chr->opaque;
+                if (chr->chr_event)
+                    chr->chr_event(s->ext_opaque, CHR_EVENT_BREAK);
+            }
+            break;
+        case 'c':
+            /* swap the monitor in and out */
+            if (mon_priv->mon_opaque == opaque)
+            {
+                mon_priv->mon_opaque = mon_priv->mon_orig;
+            } else {
+                mon_priv->mon_opaque = opaque;
+                /* send a new line in the monitor to get the prompt */
+                ch = '\r';
+                goto send_char;
+            }
+            break;
+        case TERM_ESCAPE:
+            goto send_char;
+        }
+    } else if (ch == TERM_ESCAPE) {
+        term_got_escape = 1;
+    } else {
+    send_char:
+        if (mon_priv && mon_priv->mon_opaque == opaque) {
+            uint8_t buf[1];
+            /* Send characters to the monitor device */
+            if (mon_priv->fd_can_read(mon_priv->mon_opaque) > 0) {
+                buf[0] = ch;
+                mon_priv->fd_read(mon_priv->mon_opaque, buf, 1);
+            }
+            return 0;
+        }
+        return 1;
+    }
+    return 0;
+}
+
+static int monitor_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MonitorDriver *d = chr->opaque;
+    if (d && d->mon_opaque)
+    {
+        CharDriverState *c = d->mon_opaque;
+        if (c->chr_write)
+            return c->chr_write(c, buf, len);
+    }
+    return len;
+}
+
+static void monitor_chr_add_read_handler(CharDriverState *chr,
+                                    IOCanRWHandler *fd_can_read,
+                                    IOReadHandler *fd_read, void *opaque)
+{
+    MonitorDriver *d = chr->opaque;
+    d->ext_opaque = opaque;
+    d->fd_can_read = fd_can_read;
+    d->fd_read = fd_read;
+}
+
+CharDriverState *qemu_chr_open_monitor(void)
+{
+    CharDriverState *chr;
+    MonitorDriver *d;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr)
+        return NULL;
+    d = qemu_mallocz(sizeof(MonitorDriver));
+    if (!d) {
+        free(chr);
+        return NULL;
+    }
+
+    chr->opaque = d;
+    d->mon_opaque = NULL;
+    chr->chr_write = monitor_chr_write;
+    chr->chr_add_read_handler = monitor_chr_add_read_handler;
+    return chr;
+}
+
 #ifdef _WIN32
 
 static void socket_cleanup(void)
@@ -1219,10 +1373,10 @@ void socket_set_nonblock(int fd)
 #ifndef _WIN32
 
 typedef struct {
-    int fd_in, fd_out;
     IOCanRWHandler *fd_can_read; 
     IOReadHandler *fd_read;
     void *fd_opaque;
+    int fd_in, fd_out;
     int max_size;
 } FDCharDriver;
 
@@ -1328,91 +1482,12 @@ CharDriverState *qemu_chr_open_pipe(cons
 /* for STDIO, we handle the case where several clients use it
    (nographic mode) */
 
-#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
-
 #define TERM_FIFO_MAX_SIZE 1
 
-static int term_got_escape, client_index;
+static int client_index;
 static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
 int term_fifo_size;
 
-void term_print_help(void)
-{
-    printf("\n"
-           "C-a h    print this help\n"
-           "C-a x    exit emulator\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"
-           );
-}
-
-/* called when a char is received */
-static void stdio_received_byte(int ch)
-{
-    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 (client_index < stdio_nb_clients) {
-                CharDriverState *chr;
-                FDCharDriver *s;
-
-                chr = stdio_clients[client_index];
-                s = chr->opaque;
-                chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
-            }
-            break;
-        case 'c':
-            client_index++;
-            if (client_index >= stdio_nb_clients)
-                client_index = 0;
-            if (client_index == 0) {
-                /* send a new line in the monitor to get the prompt */
-                ch = '\r';
-                goto send_char;
-            }
-            break;
-        case TERM_ESCAPE:
-            goto send_char;
-        }
-    } else if (ch == TERM_ESCAPE) {
-        term_got_escape = 1;
-    } else {
-    send_char:
-        if (client_index < stdio_nb_clients) {
-            uint8_t buf[1];
-            CharDriverState *chr;
-            FDCharDriver *s;
-            
-            chr = stdio_clients[client_index];
-            s = chr->opaque;
-            if (s->fd_can_read(s->fd_opaque) > 0) {
-                buf[0] = ch;
-                s->fd_read(s->fd_opaque, buf, 1);
-            } else if (term_fifo_size == 0) {
-                term_fifo[term_fifo_size++] = ch;
-            }
-        }
-    }
-}
-
 static int stdio_read_poll(void *opaque)
 {
     CharDriverState *chr;
@@ -1443,7 +1518,16 @@ static void stdio_read(void *opaque)
     
     size = read(0, buf, 1);
     if (size > 0)
-        stdio_received_byte(buf[0]);
+    {
+        if (proc_received_byte(buf[0], stdio_clients[client_index])) {
+            FDCharDriver *s = stdio_clients[client_index]->opaque;
+            if (s->fd_can_read(s->fd_opaque) > 0) {
+                s->fd_read(s->fd_opaque, buf, 1);
+            } else if (term_fifo_size == 0) {
+                term_fifo[term_fifo_size++] = buf[0];
+            }
+        }
+    }
 }
 
 /* init terminal so that we can grab keys */
@@ -2106,14 +2190,207 @@ CharDriverState *qemu_chr_open_win_file_
 }
 #endif
 
+/***********************************************************/
+/* Net console */
+
+typedef struct {
+    IOCanRWHandler *fd_can_read;
+    IOReadHandler *fd_read;
+    void *fd_opaque;
+    int fd_in, fd_out;
+    void *net_opaque;
+    char buf[1024];
+    int bufcnt;
+    int bufptr;
+    int max_size;
+} NetCharDriver;
+
+static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    NetCharDriver *c = chr->opaque;
+    struct sockaddr_in *s = c->net_opaque;
+
+    return sendto(c->fd_in, buf, len, 0,
+           (struct sockaddr *)s, sizeof(struct sockaddr_in));
+}
+
+static int udp_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    NetCharDriver *s = chr->opaque;
+
+    s->max_size = s->fd_can_read(s->fd_opaque);
+
+    /* If there were any stray characters in the queue process them
+     * first
+     */
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        if (proc_received_byte(s->buf[s->bufptr], opaque)) {
+            s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
+        }
+        s->bufptr++;
+        s->max_size = s->fd_can_read(s->fd_opaque);
+    }
+    return s->max_size;
+}
+
+static void udp_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    NetCharDriver *s = chr->opaque;
+
+    if (s->max_size == 0)
+        return;
+    s->bufcnt = recv(s->fd_in, s->buf, sizeof(s->buf), 0);
+    s->bufptr = s->bufcnt;
+    if (s->bufcnt <= 0)
+        return;
+
+    s->bufptr = 0;
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        if (proc_received_byte(s->buf[s->bufptr], opaque)) {
+            s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
+        }
+        s->bufptr++;
+        s->max_size = s->fd_can_read(s->fd_opaque);
+    }
+}
+
+static void udp_chr_add_read_handler(CharDriverState *chr,
+                                    IOCanRWHandler *fd_can_read,
+                                    IOReadHandler *fd_read, void *opaque)
+{
+    NetCharDriver *s = chr->opaque;
+
+    if (s->fd_in >= 0) {
+        s->fd_can_read = fd_can_read;
+        s->fd_read = fd_read;
+        s->fd_opaque = opaque;
+        qemu_set_fd_handler2(s->fd_in, udp_chr_read_poll,
+                             udp_chr_read, NULL, chr);
+    }
+}
+
+int parse_host_port(struct sockaddr_in *saddr, const char *str);
+
+CharDriverState *qemu_chr_open_udp(const char *def)
+{
+    CharDriverState *chr = NULL;
+    NetCharDriver *s = NULL;
+    struct sockaddr_in *net_opaque = NULL;
+    int fd = -1;
+    int con_type;
+    struct sockaddr_in addr;
+    const char *p, *r;
+    int port;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr)
+        goto return_err;
+    s = qemu_mallocz(sizeof(NetCharDriver));
+    if (!s)
+        goto return_err;
+
+    fd = socket(PF_INET, SOCK_DGRAM, 0);
+    if (fd < 0) {
+        perror("socket(PF_INET, SOCK_DGRAM)");
+        goto return_err;
+    }
+    net_opaque = qemu_mallocz(sizeof(struct sockaddr_in));
+    if (!net_opaque)
+        goto return_err;
+
+    /* There are three types of port definitions
+     * 1) udp:remote_port
+     *    Juse use 0.0.0.0 for the IP and send to remote
+     * 2) udp:remote_host:port
+     *    Use a IP and send traffic to remote
+     * 3) udp:local_port:remote_host:remote_port
+     *    Use local_port as the originator + #2
+     */
+    con_type = 0;
+    p = def;
+    while ((p = strchr(p,':'))) {
+        p++;
+        con_type++;
+    }
+
+    p = def;
+    memset(&addr,0,sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    net_opaque->sin_family = AF_INET;
+    net_opaque->sin_addr.s_addr = htonl(INADDR_ANY);
+
+    switch (con_type) {
+        case 0:
+            port = strtol(p, (char **)&r, 0);
+            if (r == p) {
+                fprintf(stderr, "Error parsing port number\n");
+                goto return_err;
+            }
+            net_opaque->sin_port = htons((short)port);
+            break;
+        case 2:
+            port = strtol(p, (char **)&r, 0);
+            if (r == p) {
+                fprintf(stderr, "Error parsing port number\n");
+                goto return_err;
+            }
+            addr.sin_port = htons((short)port);
+            p = r + 1;
+            /* Fall through to case 1 now that we have the local port */
+        case 1:
+            if (parse_host_port(net_opaque, p) < 0) {
+                fprintf(stderr, "Error parsing host name and port\n");
+                goto return_err;
+            }
+            break;
+        default:
+            fprintf(stderr, "Too many ':' characters\n");
+            goto return_err;
+    }
+
+    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+    {
+        perror("bind");
+        goto return_err;
+    }
+
+    s->fd_in = fd;
+    s->fd_out = fd;
+    s->net_opaque = net_opaque;
+    s->bufcnt = 0;
+    s->bufptr = 0;
+    chr->opaque = s;
+    chr->chr_write = udp_chr_write;
+    chr->chr_add_read_handler = udp_chr_add_read_handler;
+    return chr;
+
+return_err:
+    if (chr)
+        free(chr);
+    if (s)
+        free(s);
+    if (net_opaque)
+        free(net_opaque);
+    if (fd >= 0)
+        closesocket(fd);
+    return NULL;
+}
+
 CharDriverState *qemu_chr_open(const char *filename)
 {
     const char *p;
 
     if (!strcmp(filename, "vc")) {
         return text_console_init(&display_state);
+    } else if (!strcmp(filename, "monitor")) {
+        return qemu_chr_open_monitor();
     } else if (!strcmp(filename, "null")) {
         return qemu_chr_open_null();
+    } else if (strstart(filename, "udp:", &p)) {
+        return qemu_chr_open_udp(p);
     } else 
 #ifndef _WIN32
     if (strstart(filename, "file:", &p)) {
@@ -4763,6 +5040,7 @@ enum {
     QEMU_OPTION_g,
     QEMU_OPTION_std_vga,
     QEMU_OPTION_monitor,
+    QEMU_OPTION_mserial,
     QEMU_OPTION_serial,
     QEMU_OPTION_parallel,
     QEMU_OPTION_loadvm,
@@ -4835,6 +5113,7 @@ const QEMUOption qemu_options[] = {
     { "localtime", 0, QEMU_OPTION_localtime },
     { "std-vga", 0, QEMU_OPTION_std_vga },
     { "monitor", 1, QEMU_OPTION_monitor },
+    { "mserial", 1, QEMU_OPTION_mserial },
     { "serial", 1, QEMU_OPTION_serial },
     { "parallel", 1, QEMU_OPTION_parallel },
     { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
@@ -5063,6 +5342,7 @@ int main(int argc, char **argv)
     CharDriverState *monitor_hd;
     char monitor_device[128];
     char serial_devices[MAX_SERIAL_PORTS][128];
+    int serial_device_monitor[MAX_SERIAL_PORTS];
     int serial_device_index;
     char parallel_devices[MAX_PARALLEL_PORTS][128];
     int parallel_device_index;
@@ -5101,11 +5381,14 @@ int main(int argc, char **argv)
 #endif
     cyls = heads = secs = 0;
     translation = BIOS_ATA_TRANSLATION_AUTO;
-    pstrcpy(monitor_device, sizeof(monitor_device), "vc");
+    monitor_device[0] = '\0';
 
     pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "vc");
     for(i = 1; i < MAX_SERIAL_PORTS; i++)
+    {
         serial_devices[i][0] = '\0';
+        serial_device_monitor[i] = 0;
+    }
     serial_device_index = 0;
     
     pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc");
@@ -5222,7 +5505,6 @@ int main(int argc, char **argv)
                 }
                 break;
             case QEMU_OPTION_nographic:
-                pstrcpy(monitor_device, sizeof(monitor_device), "stdio");
                 pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio");
                 nographic = 1;
                 break;
@@ -5382,6 +5664,15 @@ int main(int argc, char **argv)
             case QEMU_OPTION_monitor:
                 pstrcpy(monitor_device, sizeof(monitor_device), optarg);
                 break;
+            case QEMU_OPTION_mserial:
+                if (serial_device_index >= MAX_SERIAL_PORTS) {
+                    fprintf(stderr, "qemu: too many serial ports\n");
+                    exit(1);
+                }
+                serial_device_monitor[serial_device_index] = 1;
+                /* fall through to normal serial processing
+                 * serial_devices[serial_device_index]
+                 */
             case QEMU_OPTION_serial:
                 if (serial_device_index >= MAX_SERIAL_PORTS) {
                     fprintf(stderr, "qemu: too many serial ports\n");
@@ -5638,13 +5929,7 @@ int main(int argc, char **argv)
 #endif
     }
 
-    monitor_hd = qemu_chr_open(monitor_device);
-    if (!monitor_hd) {
-        fprintf(stderr, "qemu: could not open monitor device '%s'\n", 
monitor_device);
-        exit(1);
-    }
-    monitor_init(monitor_hd, !nographic);
-
+    monitor_hd = NULL;
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_devices[i][0] != '\0') {
             serial_hds[i] = qemu_chr_open(serial_devices[i]);
@@ -5655,9 +5940,50 @@ int main(int argc, char **argv)
             }
             if (!strcmp(serial_devices[i], "vc"))
                 qemu_chr_printf(serial_hds[i], "serial%d console\n", i);
+            if (serial_device_monitor[i] ||
+                (monitor_device[0] == '\0' && nographic &&
+                 strcmp(serial_devices[i], "stdio") == 0)) {
+                serial_hds[i]->monitorEnabled = 1;
+                if (!monitor_hd) {
+                    monitor_hd = qemu_chr_open("monitor");
+                    if (!monitor_hd) {
+                        fprintf(stderr, "qemu: failed internal monitor open");
+                        exit(1);
+                    }
+                }
+            }
         }
     }
 
+    if (!monitor_hd) {
+        if (monitor_device[0] == '\0' && !nographic) {
+            /* Setup defaults because no monitor device was specificed */
+            if (!nographic)
+                pstrcpy(monitor_device, sizeof(monitor_device), "vc");
+        }
+        monitor_hd = qemu_chr_open(monitor_device);
+        if (!monitor_hd) {
+            fprintf(stderr, "qemu: could not open monitor device '%s'\n", 
monitor_device);
+            exit(1);
+        }
+    } else if (monitor_device[0] != '\0') {
+        /* Support a secondary monitor device */
+        CharDriverState *tmp = qemu_chr_open(monitor_device);
+        if (!tmp) {
+            fprintf(stderr, "qemu: could not open 2nd monitor device '%s'\n", 
monitor_device);
+            exit(1);
+        }
+        /* Tell the monitor driver we are going to support sharing and
+         * have a default monitor to an individual terminal
+         */
+        ((MonitorDriver *)monitor_hd->opaque)->mon_orig = tmp;
+        ((MonitorDriver *)monitor_hd->opaque)->mon_opaque = tmp;
+        monitor_init(tmp, 1);
+    }
+
+    monitor_init(monitor_hd, !nographic);
+    mon_priv = monitor_hd->opaque;
+
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
         if (parallel_devices[i][0] != '\0') {
             parallel_hds[i] = qemu_chr_open(parallel_devices[i]);
Index: qemu/monitor.c
===================================================================
--- qemu.orig/monitor.c
+++ qemu/monitor.c
@@ -84,8 +84,19 @@ void term_puts(const char *str)
             break;
         term_outbuf[term_outbuf_index++] = c;
         if (term_outbuf_index >= sizeof(term_outbuf) ||
-            c == '\n')
+            c == '\n') {
             term_flush();
+            /* Tack on an extra \r when we get \n for correct terminal
+             * emulation mainly for telnet.  Most of the time, the
+             * stdio is attached to some type of controlling terminal
+             * and the xterm and vt1xx emulation will automatically
+             * eat these '\r' chars.
+             */
+            if (c == '\n')
+            {
+                term_outbuf[term_outbuf_index++] = '\r';
+            }
+        }
     }
 }
 
Index: qemu/vl.h
===================================================================
--- qemu.orig/vl.h
+++ qemu/vl.h
@@ -253,6 +253,7 @@ typedef struct CharDriverState {
     void (*chr_send_event)(struct CharDriverState *chr, int event);
     void (*chr_close)(struct CharDriverState *chr);
     void *opaque;
+    int monitorEnabled;
 } CharDriverState;
 
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
Index: qemu/qemu-doc.texi
===================================================================
--- qemu.orig/qemu-doc.texi
+++ qemu/qemu-doc.texi
@@ -514,6 +514,12 @@ Write output to filename. No character c
 [Unix only] standard input/output
 @item pipe:filename
 [Unix only] name pipe @var{filename}
address@hidden udp:remote_port
+udp Net Console sent to locahost at remote_port
address@hidden udp:remote_host:remote_port
+udp Net Console sent to remote_host at remote_port
address@hidden udp:src_port:remote_host:remote_port
+udp Net Console sent from src_port to remote_host at the remote_port
 @end table
 The default device is @code{vc} in graphical mode and @code{stdio} in
 non graphical mode.
@@ -521,6 +527,30 @@ non graphical mode.
 This option can be used several times to simulate up to 4 serials
 ports.
 
+The upd:* sub options are primary intended for netconsole.  If you just want a 
simple readonly console you can use @code{netcat} or @code{nc}, by starting 
qemu with: @code{-serial udp:4555} and nc as: @code{nc -u -l -p 4555}. Any time 
qemu writes something to that port it will appear in the netconsole session.
+
+If you plan to send characters back via netconsole or you want to stop and 
start qemu a lot of times, you should have qemu use the same source port each 
time by using something like @code{-serial udp:4556:localhost:4555} to qemu. 
Another approach is to use a patched version of netcat which can listen to a 
TCP port and send and receive characters via udp.  If you have a patched 
version of netcat which activates telnet remote echo and single char transfer, 
then you can use the following options to step up a netcat redirector to allow 
telnet on port 5555 to access the qemu port.
address@hidden @code
address@hidden Qemu Options
+-serial udp:4556:localhost:4555
address@hidden netcat options
+-u -P 4555 -L localhost:4556  -t -p 5555 -I -T
address@hidden table
+
+
address@hidden -mserial dev
+Redirect the virtual serial port to host device @var{dev}.  This option alows 
multiplexing the monitor onto a device.  This option only works with:
address@hidden @code
address@hidden stdio
address@hidden udp:remote_port
address@hidden udp:remote_host:remote_port
address@hidden udp:src_port:remote_host:remote_port
address@hidden table
+
+This option is more or less the same as -serial and has the same semantics, 
but you can switch between the monitor and the serial port.  You do this with 
@key{Ctrl-a} @key{c}. See monitor accesc @ref{pcsys_keys} in the -nographic 
section for more keys.
+
+Additionaly this option will work in conjunction with a dedicated monitor 
specified with @code{-monitor}. When the monitor is active on the port with 
-mserial, it will be temporarily disabled on the dedicated port.
+
 @item -parallel dev
 Redirect the virtual parallel port to host device @var{dev} (same
 devices as the serial port). On Linux hosts, @file{/dev/parportN} can

reply via email to

[Prev in Thread] Current Thread [Next in Thread]