]> git.proxmox.com Git - qemu.git/blobdiff - qemu-char.c
Merge remote-tracking branch 'afaerber/qom-cpu' into staging
[qemu.git] / qemu-char.c
index 9d1c02cd1d9729563e1df35d91648f3112bf0993..e4b0f5304f505f838fbf7a0d66b4a668a7dedc7d 100644 (file)
@@ -98,7 +98,6 @@
 #include "ui/qemu-spice.h"
 
 #define READ_BUF_LEN 4096
-#define CBUFF_SIZE 65536
 
 /***********************************************************/
 /* character device */
@@ -2645,32 +2644,25 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr)
 }
 
 /*********************************************************/
-/*CircularMemory chardev*/
+/* Ring buffer chardev */
 
 typedef struct {
     size_t size;
     size_t prod;
     size_t cons;
     uint8_t *cbuf;
-} CirMemCharDriver;
+} RingBufCharDriver;
 
-static bool cirmem_chr_is_empty(const CharDriverState *chr)
+static size_t ringbuf_count(const CharDriverState *chr)
 {
-    const CirMemCharDriver *d = chr->opaque;
+    const RingBufCharDriver *d = chr->opaque;
 
-    return d->cons == d->prod;
+    return d->prod - d->cons;
 }
 
-static size_t qemu_chr_cirmem_count(const CharDriverState *chr)
+static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    const CirMemCharDriver *d = chr->opaque;
-
-    return (d->prod - d->cons);
-}
-
-static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    CirMemCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = chr->opaque;
     int i;
 
     if (!buf || (len < 0)) {
@@ -2678,13 +2670,8 @@ static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     }
 
     for (i = 0; i < len; i++ ) {
-        /* Avoid writing the IAC information to the queue. */
-        if ((unsigned char)buf[i] == IAC) {
-            continue;
-        }
-
-        d->cbuf[d->prod++ % d->size] = buf[i];
-        if ((d->prod - d->cons) > d->size) {
+        d->cbuf[d->prod++ & (d->size - 1)] = buf[i];
+        if (d->prod - d->cons > d->size) {
             d->cons = d->prod - d->size;
         }
     }
@@ -2692,43 +2679,43 @@ static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return 0;
 }
 
-static int cirmem_chr_read(CharDriverState *chr, uint8_t *buf, int len)
+static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
 {
-    CirMemCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = chr->opaque;
     int i;
 
-    for (i = 0; i < len && !cirmem_chr_is_empty(chr); i++) {
-        buf[i] = d->cbuf[d->cons++ % d->size];
+    for (i = 0; i < len && d->cons != d->prod; i++) {
+        buf[i] = d->cbuf[d->cons++ & (d->size - 1)];
     }
 
     return i;
 }
 
-static void cirmem_chr_close(struct CharDriverState *chr)
+static void ringbuf_chr_close(struct CharDriverState *chr)
 {
-    CirMemCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = chr->opaque;
 
     g_free(d->cbuf);
     g_free(d);
     chr->opaque = NULL;
 }
 
-static CharDriverState *qemu_chr_open_cirmemchr(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts)
 {
     CharDriverState *chr;
-    CirMemCharDriver *d;
+    RingBufCharDriver *d;
 
     chr = g_malloc0(sizeof(CharDriverState));
     d = g_malloc(sizeof(*d));
 
-    d->size = qemu_opt_get_number(opts, "maxcapacity", 0);
+    d->size = qemu_opt_get_size(opts, "size", 0);
     if (d->size == 0) {
-        d->size = CBUFF_SIZE;
+        d->size = 65536;
     }
 
     /* The size must be power of 2 */
     if (d->size & (d->size - 1)) {
-        fprintf(stderr, "chardev: size of memory device must be power of 2\n");
+        error_report("size of ringbuf device must be power of two");
         goto fail;
     }
 
@@ -2737,8 +2724,8 @@ static CharDriverState *qemu_chr_open_cirmemchr(QemuOpts *opts)
     d->cbuf = g_malloc0(d->size);
 
     chr->opaque = d;
-    chr->chr_write = cirmem_chr_write;
-    chr->chr_close = cirmem_chr_close;
+    chr->chr_write = ringbuf_chr_write;
+    chr->chr_close = ringbuf_chr_close;
 
     return chr;
 
@@ -2748,12 +2735,12 @@ fail:
     return NULL;
 }
 
-static bool qemu_is_chr(const CharDriverState *chr, const char *filename)
+static bool chr_is_ringbuf(const CharDriverState *chr)
 {
-    return strcmp(chr->filename, filename);
+    return chr->chr_write == ringbuf_chr_write;
 }
 
-void qmp_memchar_write(const char *device, const char *data,
+void qmp_ringbuf_write(const char *device, const char *data,
                        bool has_format, enum DataFormat format,
                        Error **errp)
 {
@@ -2768,8 +2755,8 @@ void qmp_memchar_write(const char *device, const char *data,
         return;
     }
 
-    if (qemu_is_chr(chr, "memory")) {
-        error_setg(errp,"%s is not memory char device", device);
+    if (!chr_is_ringbuf(chr)) {
+        error_setg(errp,"%s is not a ringbuf device", device);
         return;
     }
 
@@ -2780,7 +2767,7 @@ void qmp_memchar_write(const char *device, const char *data,
         write_count = strlen(data);
     }
 
-    ret = cirmem_chr_write(chr, write_data, write_count);
+    ret = ringbuf_chr_write(chr, write_data, write_count);
 
     if (write_data != (uint8_t *)data) {
         g_free((void *)write_data);
@@ -2792,7 +2779,7 @@ void qmp_memchar_write(const char *device, const char *data,
     }
 }
 
-char *qmp_memchar_read(const char *device, int64_t size,
+char *qmp_ringbuf_read(const char *device, int64_t size,
                        bool has_format, enum DataFormat format,
                        Error **errp)
 {
@@ -2807,8 +2794,8 @@ char *qmp_memchar_read(const char *device, int64_t size,
         return NULL;
     }
 
-    if (qemu_is_chr(chr, "memory")) {
-        error_setg(errp,"%s is not memory char device", device);
+    if (!chr_is_ringbuf(chr)) {
+        error_setg(errp,"%s is not a ringbuf device", device);
         return NULL;
     }
 
@@ -2817,16 +2804,24 @@ char *qmp_memchar_read(const char *device, int64_t size,
         return NULL;
     }
 
-    count = qemu_chr_cirmem_count(chr);
+    count = ringbuf_count(chr);
     size = size > count ? count : size;
-    read_data = g_malloc0(size + 1);
+    read_data = g_malloc(size + 1);
 
-    cirmem_chr_read(chr, read_data, size);
+    ringbuf_chr_read(chr, read_data, size);
 
     if (has_format && (format == DATA_FORMAT_BASE64)) {
         data = g_base64_encode(read_data, size);
         g_free(read_data);
     } else {
+        /*
+         * FIXME should read only complete, valid UTF-8 characters up
+         * to @size bytes.  Invalid sequences should be replaced by a
+         * suitable replacement character.  Except when (and only
+         * when) ring buffer lost characters since last read, initial
+         * continuation characters should be dropped.
+         */
+        read_data[size] = 0;
         data = (char *)read_data;
     }
 
@@ -2887,11 +2882,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
         qemu_opt_set(opts, "path", filename);
         return opts;
     }
-    if (strstart(filename, "memory", &p)) {
-        qemu_opt_set(opts, "backend", "memory");
-        qemu_opt_set(opts, "maxcapacity", p);
-        return opts;
-    }
     if (strstart(filename, "file:", &p)) {
         qemu_opt_set(opts, "backend", "file");
         qemu_opt_set(opts, "path", p);
@@ -2991,7 +2981,7 @@ static const struct {
     { .name = "udp",       .open = qemu_chr_open_udp },
     { .name = "msmouse",   .open = qemu_chr_open_msmouse },
     { .name = "vc",        .open = text_console_init },
-    { .name = "memory",    .open = qemu_chr_open_cirmemchr },
+    { .name = "memory",    .open = qemu_chr_open_ringbuf },
 #ifdef _WIN32
     { .name = "file",      .open = qemu_chr_open_win_file_out },
     { .name = "pipe",      .open = qemu_chr_open_win_pipe },
@@ -3031,12 +3021,12 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
     int i;
 
     if (qemu_opts_id(opts) == NULL) {
-        error_setg(errp, "chardev: no id specified\n");
+        error_setg(errp, "chardev: no id specified");
         goto err;
     }
 
     if (qemu_opt_get(opts, "backend") == NULL) {
-        error_setg(errp, "chardev: \"%s\" missing backend\n",
+        error_setg(errp, "chardev: \"%s\" missing backend",
                    qemu_opts_id(opts));
         goto err;
     }
@@ -3045,14 +3035,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
             break;
     }
     if (i == ARRAY_SIZE(backend_table)) {
-        error_setg(errp, "chardev: backend \"%s\" not found\n",
+        error_setg(errp, "chardev: backend \"%s\" not found",
                    qemu_opt_get(opts, "backend"));
         goto err;
     }
 
     chr = backend_table[i].open(opts);
     if (!chr) {
-        error_setg(errp, "chardev: opening backend \"%s\" failed\n",
+        error_setg(errp, "chardev: opening backend \"%s\" failed",
                    qemu_opt_get(opts, "backend"));
         goto err;
     }
@@ -3252,8 +3242,8 @@ QemuOptsList qemu_chardev_opts = {
             .name = "debug",
             .type = QEMU_OPT_NUMBER,
         },{
-            .name = "maxcapacity",
-            .type = QEMU_OPT_NUMBER,
+            .name = "size",
+            .type = QEMU_OPT_SIZE,
         },
         { /* end of list */ }
     },
@@ -3279,15 +3269,17 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
     return qemu_chr_open_win_file(out);
 }
 
-static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp)
+static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial,
+                                                Error **errp)
 {
-    switch (port->type) {
-    case CHARDEV_PORT_KIND_SERIAL:
-        return qemu_chr_open_win_path(port->device);
-    default:
-        error_setg(errp, "unknown chardev port (%d)", port->type);
-        return NULL;
-    }
+    return qemu_chr_open_win_path(serial->device);
+}
+
+static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel,
+                                                  Error **errp)
+{
+    error_setg(errp, "character device backend type 'parallel' not supported");
+    return NULL;
 }
 
 #else /* WIN32 */
@@ -3326,38 +3318,39 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
     return qemu_chr_open_fd(in, out);
 }
 
-static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp)
+static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial,
+                                                Error **errp)
 {
-    switch (port->type) {
 #ifdef HAVE_CHARDEV_TTY
-    case CHARDEV_PORT_KIND_SERIAL:
-    {
-        int flags, fd;
-        flags = O_RDWR;
-        fd = qmp_chardev_open_file_source(port->device, flags, errp);
-        if (error_is_set(errp)) {
-            return NULL;
-        }
-        socket_set_nonblock(fd);
-        return qemu_chr_open_tty_fd(fd);
+    int fd;
+
+    fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
+    if (error_is_set(errp)) {
+        return NULL;
     }
+    socket_set_nonblock(fd);
+    return qemu_chr_open_tty_fd(fd);
+#else
+    error_setg(errp, "character device backend type 'serial' not supported");
+    return NULL;
 #endif
+}
+
+static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel,
+                                                  Error **errp)
+{
 #ifdef HAVE_CHARDEV_PARPORT
-    case CHARDEV_PORT_KIND_PARALLEL:
-    {
-        int flags, fd;
-        flags = O_RDWR;
-        fd = qmp_chardev_open_file_source(port->device, flags, errp);
-        if (error_is_set(errp)) {
-            return NULL;
-        }
-        return qemu_chr_open_pp_fd(fd);
-    }
-#endif
-    default:
-        error_setg(errp, "unknown chardev port (%d)", port->type);
+    int fd;
+
+    fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
+    if (error_is_set(errp)) {
         return NULL;
     }
+    return qemu_chr_open_pp_fd(fd);
+#else
+    error_setg(errp, "character device backend type 'parallel' not supported");
+    return NULL;
+#endif
 }
 
 #endif /* WIN32 */
@@ -3401,8 +3394,11 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     case CHARDEV_BACKEND_KIND_FILE:
         chr = qmp_chardev_open_file(backend->file, errp);
         break;
-    case CHARDEV_BACKEND_KIND_PORT:
-        chr = qmp_chardev_open_port(backend->port, errp);
+    case CHARDEV_BACKEND_KIND_SERIAL:
+        chr = qmp_chardev_open_serial(backend->serial, errp);
+        break;
+    case CHARDEV_BACKEND_KIND_PARALLEL:
+        chr = qmp_chardev_open_parallel(backend->parallel, errp);
         break;
     case CHARDEV_BACKEND_KIND_SOCKET:
         chr = qmp_chardev_open_socket(backend->socket, errp);