X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-char.c;h=574d3d292fe64fa248abc8720ac2f28929665c60;hb=7ce4106c2125eca8f7f61f460456a49074c13e56;hp=80458697f20ad420a9a19ca69f8b783cef4c1e8a;hpb=51767e7cf2c3abc07d30009ab3d6262bdfd89b8b;p=qemu.git diff --git a/qemu-char.c b/qemu-char.c index 80458697f..574d3d292 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -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,6 +2735,99 @@ fail: return NULL; } +static bool chr_is_ringbuf(const CharDriverState *chr) +{ + return chr->chr_write == ringbuf_chr_write; +} + +void qmp_ringbuf_write(const char *device, const char *data, + bool has_format, enum DataFormat format, + Error **errp) +{ + CharDriverState *chr; + const uint8_t *write_data; + int ret; + size_t write_count; + + chr = qemu_chr_find(device); + if (!chr) { + error_setg(errp, "Device '%s' not found", device); + return; + } + + if (!chr_is_ringbuf(chr)) { + error_setg(errp,"%s is not a ringbuf device", device); + return; + } + + if (has_format && (format == DATA_FORMAT_BASE64)) { + write_data = g_base64_decode(data, &write_count); + } else { + write_data = (uint8_t *)data; + write_count = strlen(data); + } + + ret = ringbuf_chr_write(chr, write_data, write_count); + + if (write_data != (uint8_t *)data) { + g_free((void *)write_data); + } + + if (ret < 0) { + error_setg(errp, "Failed to write to device %s", device); + return; + } +} + +char *qmp_ringbuf_read(const char *device, int64_t size, + bool has_format, enum DataFormat format, + Error **errp) +{ + CharDriverState *chr; + uint8_t *read_data; + size_t count; + char *data; + + chr = qemu_chr_find(device); + if (!chr) { + error_setg(errp, "Device '%s' not found", device); + return NULL; + } + + if (!chr_is_ringbuf(chr)) { + error_setg(errp,"%s is not a ringbuf device", device); + return NULL; + } + + if (size <= 0) { + error_setg(errp, "size must be greater than zero"); + return NULL; + } + + count = ringbuf_count(chr); + size = size > count ? count : size; + read_data = g_malloc(size + 1); + + 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; + } + + return data; +} + QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; @@ -2802,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); @@ -2906,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 }, @@ -2946,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; } @@ -2960,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; } @@ -3167,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 */ } }, @@ -3243,11 +3318,11 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) { - int flags, fd; - 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)) { @@ -3255,15 +3330,19 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) } socket_set_nonblock(fd); return qemu_chr_open_tty_fd(fd); + } #endif #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);