cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

char.c (33702B)


      1/*
      2 * QEMU System Emulator
      3 *
      4 * Copyright (c) 2003-2008 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
     25#include "qemu/osdep.h"
     26#include "qemu/cutils.h"
     27#include "monitor/monitor.h"
     28#include "qemu/config-file.h"
     29#include "qemu/error-report.h"
     30#include "qemu/qemu-print.h"
     31#include "chardev/char.h"
     32#include "qapi/error.h"
     33#include "qapi/qapi-commands-char.h"
     34#include "qapi/qmp/qerror.h"
     35#include "sysemu/replay.h"
     36#include "qemu/help_option.h"
     37#include "qemu/module.h"
     38#include "qemu/option.h"
     39#include "qemu/id.h"
     40#include "qemu/coroutine.h"
     41#include "qemu/yank.h"
     42
     43#include "chardev-internal.h"
     44
     45/***********************************************************/
     46/* character device */
     47
     48Object *get_chardevs_root(void)
     49{
     50    return container_get(object_get_root(), "/chardevs");
     51}
     52
     53static void chr_be_event(Chardev *s, QEMUChrEvent event)
     54{
     55    CharBackend *be = s->be;
     56
     57    if (!be || !be->chr_event) {
     58        return;
     59    }
     60
     61    be->chr_event(be->opaque, event);
     62}
     63
     64void qemu_chr_be_event(Chardev *s, QEMUChrEvent event)
     65{
     66    /* Keep track if the char device is open */
     67    switch (event) {
     68        case CHR_EVENT_OPENED:
     69            s->be_open = 1;
     70            break;
     71        case CHR_EVENT_CLOSED:
     72            s->be_open = 0;
     73            break;
     74    case CHR_EVENT_BREAK:
     75    case CHR_EVENT_MUX_IN:
     76    case CHR_EVENT_MUX_OUT:
     77        /* Ignore */
     78        break;
     79    }
     80
     81    CHARDEV_GET_CLASS(s)->chr_be_event(s, event);
     82}
     83
     84/* Not reporting errors from writing to logfile, as logs are
     85 * defined to be "best effort" only */
     86static void qemu_chr_write_log(Chardev *s, const uint8_t *buf, size_t len)
     87{
     88    size_t done = 0;
     89    ssize_t ret;
     90
     91    if (s->logfd < 0) {
     92        return;
     93    }
     94
     95    while (done < len) {
     96    retry:
     97        ret = write(s->logfd, buf + done, len - done);
     98        if (ret == -1 && errno == EAGAIN) {
     99            g_usleep(100);
    100            goto retry;
    101        }
    102
    103        if (ret <= 0) {
    104            return;
    105        }
    106        done += ret;
    107    }
    108}
    109
    110static int qemu_chr_write_buffer(Chardev *s,
    111                                 const uint8_t *buf, int len,
    112                                 int *offset, bool write_all)
    113{
    114    ChardevClass *cc = CHARDEV_GET_CLASS(s);
    115    int res = 0;
    116    *offset = 0;
    117
    118    qemu_mutex_lock(&s->chr_write_lock);
    119    while (*offset < len) {
    120    retry:
    121        res = cc->chr_write(s, buf + *offset, len - *offset);
    122        if (res < 0 && errno == EAGAIN && write_all) {
    123            if (qemu_in_coroutine()) {
    124                qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
    125            } else {
    126                g_usleep(100);
    127            }
    128            goto retry;
    129        }
    130
    131        if (res <= 0) {
    132            break;
    133        }
    134
    135        *offset += res;
    136        if (!write_all) {
    137            break;
    138        }
    139    }
    140    if (*offset > 0) {
    141        /*
    142         * If some data was written by backend, we should
    143         * only log what was actually written. This method
    144         * may be invoked again to write the remaining
    145         * method, thus we'll log the remainder at that time.
    146         */
    147        qemu_chr_write_log(s, buf, *offset);
    148    } else if (res < 0) {
    149        /*
    150         * If a fatal error was reported by the backend,
    151         * assume this method won't be invoked again with
    152         * this buffer, so log it all right away.
    153         */
    154        qemu_chr_write_log(s, buf, len);
    155    }
    156    qemu_mutex_unlock(&s->chr_write_lock);
    157
    158    return res;
    159}
    160
    161int qemu_chr_write(Chardev *s, const uint8_t *buf, int len, bool write_all)
    162{
    163    int offset = 0;
    164    int res;
    165
    166    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
    167        replay_char_write_event_load(&res, &offset);
    168        assert(offset <= len);
    169        qemu_chr_write_buffer(s, buf, offset, &offset, true);
    170        return res;
    171    }
    172
    173    res = qemu_chr_write_buffer(s, buf, len, &offset, write_all);
    174
    175    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
    176        replay_char_write_event_save(res, offset);
    177    }
    178
    179    if (res < 0) {
    180        return res;
    181    }
    182    return offset;
    183}
    184
    185int qemu_chr_be_can_write(Chardev *s)
    186{
    187    CharBackend *be = s->be;
    188
    189    if (!be || !be->chr_can_read) {
    190        return 0;
    191    }
    192
    193    return be->chr_can_read(be->opaque);
    194}
    195
    196void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len)
    197{
    198    CharBackend *be = s->be;
    199
    200    if (be && be->chr_read) {
    201        be->chr_read(be->opaque, buf, len);
    202    }
    203}
    204
    205void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len)
    206{
    207    if (qemu_chr_replay(s)) {
    208        if (replay_mode == REPLAY_MODE_PLAY) {
    209            return;
    210        }
    211        replay_chr_be_write(s, buf, len);
    212    } else {
    213        qemu_chr_be_write_impl(s, buf, len);
    214    }
    215}
    216
    217void qemu_chr_be_update_read_handlers(Chardev *s,
    218                                      GMainContext *context)
    219{
    220    ChardevClass *cc = CHARDEV_GET_CLASS(s);
    221
    222    assert(qemu_chr_has_feature(s, QEMU_CHAR_FEATURE_GCONTEXT)
    223           || !context);
    224    s->gcontext = context;
    225    if (cc->chr_update_read_handler) {
    226        cc->chr_update_read_handler(s);
    227    }
    228}
    229
    230int qemu_chr_add_client(Chardev *s, int fd)
    231{
    232    return CHARDEV_GET_CLASS(s)->chr_add_client ?
    233        CHARDEV_GET_CLASS(s)->chr_add_client(s, fd) : -1;
    234}
    235
    236static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
    237                           bool *be_opened, Error **errp)
    238{
    239    ChardevClass *cc = CHARDEV_GET_CLASS(chr);
    240    /* Any ChardevCommon member would work */
    241    ChardevCommon *common = backend ? backend->u.null.data : NULL;
    242
    243    if (common && common->has_logfile) {
    244        int flags = O_WRONLY;
    245        if (common->has_logappend &&
    246            common->logappend) {
    247            flags |= O_APPEND;
    248        } else {
    249            flags |= O_TRUNC;
    250        }
    251        chr->logfd = qemu_create(common->logfile, flags, 0666, errp);
    252        if (chr->logfd < 0) {
    253            return;
    254        }
    255    }
    256
    257    if (cc->open) {
    258        cc->open(chr, backend, be_opened, errp);
    259    }
    260}
    261
    262static void char_init(Object *obj)
    263{
    264    Chardev *chr = CHARDEV(obj);
    265
    266    chr->handover_yank_instance = false;
    267    chr->logfd = -1;
    268    qemu_mutex_init(&chr->chr_write_lock);
    269
    270    /*
    271     * Assume if chr_update_read_handler is implemented it will
    272     * take the updated gcontext into account.
    273     */
    274    if (CHARDEV_GET_CLASS(chr)->chr_update_read_handler) {
    275        qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT);
    276    }
    277
    278}
    279
    280static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
    281{
    282    return len;
    283}
    284
    285static void char_class_init(ObjectClass *oc, void *data)
    286{
    287    ChardevClass *cc = CHARDEV_CLASS(oc);
    288
    289    cc->chr_write = null_chr_write;
    290    cc->chr_be_event = chr_be_event;
    291}
    292
    293static void char_finalize(Object *obj)
    294{
    295    Chardev *chr = CHARDEV(obj);
    296
    297    if (chr->be) {
    298        chr->be->chr = NULL;
    299    }
    300    g_free(chr->filename);
    301    g_free(chr->label);
    302    if (chr->logfd != -1) {
    303        close(chr->logfd);
    304    }
    305    qemu_mutex_destroy(&chr->chr_write_lock);
    306}
    307
    308static const TypeInfo char_type_info = {
    309    .name = TYPE_CHARDEV,
    310    .parent = TYPE_OBJECT,
    311    .instance_size = sizeof(Chardev),
    312    .instance_init = char_init,
    313    .instance_finalize = char_finalize,
    314    .abstract = true,
    315    .class_size = sizeof(ChardevClass),
    316    .class_init = char_class_init,
    317};
    318
    319static bool qemu_chr_is_busy(Chardev *s)
    320{
    321    if (CHARDEV_IS_MUX(s)) {
    322        MuxChardev *d = MUX_CHARDEV(s);
    323        return d->mux_cnt >= 0;
    324    } else {
    325        return s->be != NULL;
    326    }
    327}
    328
    329int qemu_chr_wait_connected(Chardev *chr, Error **errp)
    330{
    331    ChardevClass *cc = CHARDEV_GET_CLASS(chr);
    332
    333    if (cc->chr_wait_connected) {
    334        return cc->chr_wait_connected(chr, errp);
    335    }
    336
    337    return 0;
    338}
    339
    340QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
    341                                bool permit_mux_mon)
    342{
    343    char host[65], port[33], width[8], height[8];
    344    int pos;
    345    const char *p;
    346    QemuOpts *opts;
    347    Error *local_err = NULL;
    348
    349    opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, &local_err);
    350    if (local_err) {
    351        error_report_err(local_err);
    352        return NULL;
    353    }
    354
    355    if (strstart(filename, "mon:", &p)) {
    356        if (!permit_mux_mon) {
    357            error_report("mon: isn't supported in this context");
    358            return NULL;
    359        }
    360        filename = p;
    361        qemu_opt_set(opts, "mux", "on", &error_abort);
    362        if (strcmp(filename, "stdio") == 0) {
    363            /* Monitor is muxed to stdio: do not exit on Ctrl+C by default
    364             * but pass it to the guest.  Handle this only for compat syntax,
    365             * for -chardev syntax we have special option for this.
    366             * This is what -nographic did, redirecting+muxing serial+monitor
    367             * to stdio causing Ctrl+C to be passed to guest. */
    368            qemu_opt_set(opts, "signal", "off", &error_abort);
    369        }
    370    }
    371
    372    if (strcmp(filename, "null")    == 0 ||
    373        strcmp(filename, "pty")     == 0 ||
    374        strcmp(filename, "msmouse") == 0 ||
    375        strcmp(filename, "wctablet") == 0 ||
    376        strcmp(filename, "braille") == 0 ||
    377        strcmp(filename, "testdev") == 0 ||
    378        strcmp(filename, "stdio")   == 0) {
    379        qemu_opt_set(opts, "backend", filename, &error_abort);
    380        return opts;
    381    }
    382    if (strstart(filename, "vc", &p)) {
    383        qemu_opt_set(opts, "backend", "vc", &error_abort);
    384        if (*p == ':') {
    385            if (sscanf(p+1, "%7[0-9]x%7[0-9]", width, height) == 2) {
    386                /* pixels */
    387                qemu_opt_set(opts, "width", width, &error_abort);
    388                qemu_opt_set(opts, "height", height, &error_abort);
    389            } else if (sscanf(p+1, "%7[0-9]Cx%7[0-9]C", width, height) == 2) {
    390                /* chars */
    391                qemu_opt_set(opts, "cols", width, &error_abort);
    392                qemu_opt_set(opts, "rows", height, &error_abort);
    393            } else {
    394                goto fail;
    395            }
    396        }
    397        return opts;
    398    }
    399    if (strcmp(filename, "con:") == 0) {
    400        qemu_opt_set(opts, "backend", "console", &error_abort);
    401        return opts;
    402    }
    403    if (strstart(filename, "COM", NULL)) {
    404        qemu_opt_set(opts, "backend", "serial", &error_abort);
    405        qemu_opt_set(opts, "path", filename, &error_abort);
    406        return opts;
    407    }
    408    if (strstart(filename, "file:", &p)) {
    409        qemu_opt_set(opts, "backend", "file", &error_abort);
    410        qemu_opt_set(opts, "path", p, &error_abort);
    411        return opts;
    412    }
    413    if (strstart(filename, "pipe:", &p)) {
    414        qemu_opt_set(opts, "backend", "pipe", &error_abort);
    415        qemu_opt_set(opts, "path", p, &error_abort);
    416        return opts;
    417    }
    418    if (strstart(filename, "tcp:", &p) ||
    419        strstart(filename, "telnet:", &p) ||
    420        strstart(filename, "tn3270:", &p) ||
    421        strstart(filename, "websocket:", &p)) {
    422        if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
    423            host[0] = 0;
    424            if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
    425                goto fail;
    426        }
    427        qemu_opt_set(opts, "backend", "socket", &error_abort);
    428        qemu_opt_set(opts, "host", host, &error_abort);
    429        qemu_opt_set(opts, "port", port, &error_abort);
    430        if (p[pos] == ',') {
    431            if (!qemu_opts_do_parse(opts, p + pos + 1, NULL, &local_err)) {
    432                error_report_err(local_err);
    433                goto fail;
    434            }
    435        }
    436        if (strstart(filename, "telnet:", &p)) {
    437            qemu_opt_set(opts, "telnet", "on", &error_abort);
    438        } else if (strstart(filename, "tn3270:", &p)) {
    439            qemu_opt_set(opts, "tn3270", "on", &error_abort);
    440        } else if (strstart(filename, "websocket:", &p)) {
    441            qemu_opt_set(opts, "websocket", "on", &error_abort);
    442        }
    443        return opts;
    444    }
    445    if (strstart(filename, "udp:", &p)) {
    446        qemu_opt_set(opts, "backend", "udp", &error_abort);
    447        if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
    448            host[0] = 0;
    449            if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) {
    450                goto fail;
    451            }
    452        }
    453        qemu_opt_set(opts, "host", host, &error_abort);
    454        qemu_opt_set(opts, "port", port, &error_abort);
    455        if (p[pos] == '@') {
    456            p += pos + 1;
    457            if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
    458                host[0] = 0;
    459                if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
    460                    goto fail;
    461                }
    462            }
    463            qemu_opt_set(opts, "localaddr", host, &error_abort);
    464            qemu_opt_set(opts, "localport", port, &error_abort);
    465        }
    466        return opts;
    467    }
    468    if (strstart(filename, "unix:", &p)) {
    469        qemu_opt_set(opts, "backend", "socket", &error_abort);
    470        if (!qemu_opts_do_parse(opts, p, "path", &local_err)) {
    471            error_report_err(local_err);
    472            goto fail;
    473        }
    474        return opts;
    475    }
    476    if (strstart(filename, "/dev/parport", NULL) ||
    477        strstart(filename, "/dev/ppi", NULL)) {
    478        qemu_opt_set(opts, "backend", "parallel", &error_abort);
    479        qemu_opt_set(opts, "path", filename, &error_abort);
    480        return opts;
    481    }
    482    if (strstart(filename, "/dev/", NULL)) {
    483        qemu_opt_set(opts, "backend", "serial", &error_abort);
    484        qemu_opt_set(opts, "path", filename, &error_abort);
    485        return opts;
    486    }
    487
    488    error_report("'%s' is not a valid char driver", filename);
    489
    490fail:
    491    qemu_opts_del(opts);
    492    return NULL;
    493}
    494
    495void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
    496{
    497    const char *logfile = qemu_opt_get(opts, "logfile");
    498
    499    backend->has_logfile = logfile != NULL;
    500    backend->logfile = g_strdup(logfile);
    501
    502    backend->has_logappend = true;
    503    backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
    504}
    505
    506static const ChardevClass *char_get_class(const char *driver, Error **errp)
    507{
    508    ObjectClass *oc;
    509    const ChardevClass *cc;
    510    char *typename = g_strdup_printf("chardev-%s", driver);
    511
    512    oc = module_object_class_by_name(typename);
    513    g_free(typename);
    514
    515    if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {
    516        error_setg(errp, "'%s' is not a valid char driver name", driver);
    517        return NULL;
    518    }
    519
    520    if (object_class_is_abstract(oc)) {
    521        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
    522                   "an abstract device type");
    523        return NULL;
    524    }
    525
    526    cc = CHARDEV_CLASS(oc);
    527    if (cc->internal) {
    528        error_setg(errp, "'%s' is not a valid char driver name", driver);
    529        return NULL;
    530    }
    531
    532    return cc;
    533}
    534
    535static struct ChardevAlias {
    536    const char *typename;
    537    const char *alias;
    538    bool deprecation_warning_printed;
    539} chardev_alias_table[] = {
    540#ifdef HAVE_CHARDEV_PARPORT
    541    { "parallel", "parport" },
    542#endif
    543#ifdef HAVE_CHARDEV_SERIAL
    544    { "serial", "tty" },
    545#endif
    546};
    547
    548typedef struct ChadevClassFE {
    549    void (*fn)(const char *name, void *opaque);
    550    void *opaque;
    551} ChadevClassFE;
    552
    553static void
    554chardev_class_foreach(ObjectClass *klass, void *opaque)
    555{
    556    ChadevClassFE *fe = opaque;
    557
    558    assert(g_str_has_prefix(object_class_get_name(klass), "chardev-"));
    559    if (CHARDEV_CLASS(klass)->internal) {
    560        return;
    561    }
    562
    563    fe->fn(object_class_get_name(klass) + 8, fe->opaque);
    564}
    565
    566static void
    567chardev_name_foreach(void (*fn)(const char *name, void *opaque),
    568                     void *opaque)
    569{
    570    ChadevClassFE fe = { .fn = fn, .opaque = opaque };
    571
    572    object_class_foreach(chardev_class_foreach, TYPE_CHARDEV, false, &fe);
    573}
    574
    575static void
    576help_string_append(const char *name, void *opaque)
    577{
    578    GString *str = opaque;
    579
    580    g_string_append_printf(str, "\n  %s", name);
    581}
    582
    583static const char *chardev_alias_translate(const char *name)
    584{
    585    int i;
    586    for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
    587        if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
    588            if (!chardev_alias_table[i].deprecation_warning_printed) {
    589                warn_report("The alias '%s' is deprecated, use '%s' instead",
    590                            name, chardev_alias_table[i].typename);
    591                chardev_alias_table[i].deprecation_warning_printed = true;
    592            }
    593            return chardev_alias_table[i].typename;
    594        }
    595    }
    596    return name;
    597}
    598
    599ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
    600{
    601    Error *local_err = NULL;
    602    const ChardevClass *cc;
    603    ChardevBackend *backend = NULL;
    604    const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
    605
    606    if (name == NULL) {
    607        error_setg(errp, "chardev: \"%s\" missing backend",
    608                   qemu_opts_id(opts));
    609        return NULL;
    610    }
    611
    612    cc = char_get_class(name, errp);
    613    if (cc == NULL) {
    614        return NULL;
    615    }
    616
    617    backend = g_new0(ChardevBackend, 1);
    618    backend->type = CHARDEV_BACKEND_KIND_NULL;
    619
    620    if (cc->parse) {
    621        cc->parse(opts, backend, &local_err);
    622        if (local_err) {
    623            error_propagate(errp, local_err);
    624            qapi_free_ChardevBackend(backend);
    625            return NULL;
    626        }
    627    } else {
    628        ChardevCommon *ccom = g_new0(ChardevCommon, 1);
    629        qemu_chr_parse_common(opts, ccom);
    630        backend->u.null.data = ccom; /* Any ChardevCommon member would work */
    631    }
    632
    633    return backend;
    634}
    635
    636Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
    637                                Error **errp)
    638{
    639    const ChardevClass *cc;
    640    Chardev *chr = NULL;
    641    ChardevBackend *backend = NULL;
    642    const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
    643    const char *id = qemu_opts_id(opts);
    644    char *bid = NULL;
    645
    646    if (name && is_help_option(name)) {
    647        GString *str = g_string_new("");
    648
    649        chardev_name_foreach(help_string_append, str);
    650
    651        qemu_printf("Available chardev backend types: %s\n", str->str);
    652        g_string_free(str, true);
    653        return NULL;
    654    }
    655
    656    if (id == NULL) {
    657        error_setg(errp, "chardev: no id specified");
    658        return NULL;
    659    }
    660
    661    backend = qemu_chr_parse_opts(opts, errp);
    662    if (backend == NULL) {
    663        return NULL;
    664    }
    665
    666    cc = char_get_class(name, errp);
    667    if (cc == NULL) {
    668        goto out;
    669    }
    670
    671    if (qemu_opt_get_bool(opts, "mux", 0)) {
    672        bid = g_strdup_printf("%s-base", id);
    673    }
    674
    675    chr = qemu_chardev_new(bid ? bid : id,
    676                           object_class_get_name(OBJECT_CLASS(cc)),
    677                           backend, context, errp);
    678
    679    if (chr == NULL) {
    680        goto out;
    681    }
    682
    683    if (bid) {
    684        Chardev *mux;
    685        qapi_free_ChardevBackend(backend);
    686        backend = g_new0(ChardevBackend, 1);
    687        backend->type = CHARDEV_BACKEND_KIND_MUX;
    688        backend->u.mux.data = g_new0(ChardevMux, 1);
    689        backend->u.mux.data->chardev = g_strdup(bid);
    690        mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, context, errp);
    691        if (mux == NULL) {
    692            object_unparent(OBJECT(chr));
    693            chr = NULL;
    694            goto out;
    695        }
    696        chr = mux;
    697    }
    698
    699out:
    700    qapi_free_ChardevBackend(backend);
    701    g_free(bid);
    702    return chr;
    703}
    704
    705Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
    706                               bool permit_mux_mon, GMainContext *context)
    707{
    708    const char *p;
    709    Chardev *chr;
    710    QemuOpts *opts;
    711    Error *err = NULL;
    712
    713    if (strstart(filename, "chardev:", &p)) {
    714        return qemu_chr_find(p);
    715    }
    716
    717    opts = qemu_chr_parse_compat(label, filename, permit_mux_mon);
    718    if (!opts)
    719        return NULL;
    720
    721    chr = qemu_chr_new_from_opts(opts, context, &err);
    722    if (!chr) {
    723        error_report_err(err);
    724        goto out;
    725    }
    726
    727    if (qemu_opt_get_bool(opts, "mux", 0)) {
    728        assert(permit_mux_mon);
    729        monitor_init_hmp(chr, true, &err);
    730        if (err) {
    731            error_report_err(err);
    732            object_unparent(OBJECT(chr));
    733            chr = NULL;
    734            goto out;
    735        }
    736    }
    737
    738out:
    739    qemu_opts_del(opts);
    740    return chr;
    741}
    742
    743static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
    744                                          const char *filename,
    745                                          bool permit_mux_mon,
    746                                          GMainContext *context)
    747{
    748    Chardev *chr;
    749    chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon, context);
    750    if (chr) {
    751        if (replay_mode != REPLAY_MODE_NONE) {
    752            qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
    753        }
    754        if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) {
    755            error_report("Replay: ioctl is not supported "
    756                         "for serial devices yet");
    757        }
    758        replay_register_char_driver(chr);
    759    }
    760    return chr;
    761}
    762
    763Chardev *qemu_chr_new(const char *label, const char *filename,
    764                      GMainContext *context)
    765{
    766    return qemu_chr_new_permit_mux_mon(label, filename, false, context);
    767}
    768
    769Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename,
    770                              GMainContext *context)
    771{
    772    return qemu_chr_new_permit_mux_mon(label, filename, true, context);
    773}
    774
    775static int qmp_query_chardev_foreach(Object *obj, void *data)
    776{
    777    Chardev *chr = CHARDEV(obj);
    778    ChardevInfoList **list = data;
    779    ChardevInfo *value = g_malloc0(sizeof(*value));
    780
    781    value->label = g_strdup(chr->label);
    782    value->filename = g_strdup(chr->filename);
    783    value->frontend_open = chr->be && chr->be->fe_open;
    784
    785    QAPI_LIST_PREPEND(*list, value);
    786
    787    return 0;
    788}
    789
    790ChardevInfoList *qmp_query_chardev(Error **errp)
    791{
    792    ChardevInfoList *chr_list = NULL;
    793
    794    object_child_foreach(get_chardevs_root(),
    795                         qmp_query_chardev_foreach, &chr_list);
    796
    797    return chr_list;
    798}
    799
    800static void
    801qmp_prepend_backend(const char *name, void *opaque)
    802{
    803    ChardevBackendInfoList **list = opaque;
    804    ChardevBackendInfo *value;
    805
    806    value = g_new0(ChardevBackendInfo, 1);
    807    value->name = g_strdup(name);
    808    QAPI_LIST_PREPEND(*list, value);
    809}
    810
    811ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
    812{
    813    ChardevBackendInfoList *backend_list = NULL;
    814
    815    chardev_name_foreach(qmp_prepend_backend, &backend_list);
    816
    817    return backend_list;
    818}
    819
    820Chardev *qemu_chr_find(const char *name)
    821{
    822    Object *obj = object_resolve_path_component(get_chardevs_root(), name);
    823
    824    return obj ? CHARDEV(obj) : NULL;
    825}
    826
    827QemuOptsList qemu_chardev_opts = {
    828    .name = "chardev",
    829    .implied_opt_name = "backend",
    830    .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
    831    .desc = {
    832        {
    833            .name = "backend",
    834            .type = QEMU_OPT_STRING,
    835        },{
    836            .name = "path",
    837            .type = QEMU_OPT_STRING,
    838        },{
    839            .name = "host",
    840            .type = QEMU_OPT_STRING,
    841        },{
    842            .name = "port",
    843            .type = QEMU_OPT_STRING,
    844        },{
    845            .name = "fd",
    846            .type = QEMU_OPT_STRING,
    847        },{
    848            .name = "localaddr",
    849            .type = QEMU_OPT_STRING,
    850        },{
    851            .name = "localport",
    852            .type = QEMU_OPT_STRING,
    853        },{
    854            .name = "to",
    855            .type = QEMU_OPT_NUMBER,
    856        },{
    857            .name = "ipv4",
    858            .type = QEMU_OPT_BOOL,
    859        },{
    860            .name = "ipv6",
    861            .type = QEMU_OPT_BOOL,
    862        },{
    863            .name = "wait",
    864            .type = QEMU_OPT_BOOL,
    865        },{
    866            .name = "server",
    867            .type = QEMU_OPT_BOOL,
    868        },{
    869            .name = "delay",
    870            .type = QEMU_OPT_BOOL,
    871        },{
    872            .name = "nodelay",
    873            .type = QEMU_OPT_BOOL,
    874        },{
    875            .name = "reconnect",
    876            .type = QEMU_OPT_NUMBER,
    877        },{
    878            .name = "telnet",
    879            .type = QEMU_OPT_BOOL,
    880        },{
    881            .name = "tn3270",
    882            .type = QEMU_OPT_BOOL,
    883        },{
    884            .name = "tls-creds",
    885            .type = QEMU_OPT_STRING,
    886        },{
    887            .name = "tls-authz",
    888            .type = QEMU_OPT_STRING,
    889        },{
    890            .name = "websocket",
    891            .type = QEMU_OPT_BOOL,
    892        },{
    893            .name = "width",
    894            .type = QEMU_OPT_NUMBER,
    895        },{
    896            .name = "height",
    897            .type = QEMU_OPT_NUMBER,
    898        },{
    899            .name = "cols",
    900            .type = QEMU_OPT_NUMBER,
    901        },{
    902            .name = "rows",
    903            .type = QEMU_OPT_NUMBER,
    904        },{
    905            .name = "mux",
    906            .type = QEMU_OPT_BOOL,
    907        },{
    908            .name = "signal",
    909            .type = QEMU_OPT_BOOL,
    910        },{
    911            .name = "name",
    912            .type = QEMU_OPT_STRING,
    913        },{
    914            .name = "debug",
    915            .type = QEMU_OPT_NUMBER,
    916        },{
    917            .name = "size",
    918            .type = QEMU_OPT_SIZE,
    919        },{
    920            .name = "chardev",
    921            .type = QEMU_OPT_STRING,
    922        },{
    923            .name = "append",
    924            .type = QEMU_OPT_BOOL,
    925        },{
    926            .name = "logfile",
    927            .type = QEMU_OPT_STRING,
    928        },{
    929            .name = "logappend",
    930            .type = QEMU_OPT_BOOL,
    931        },{
    932            .name = "mouse",
    933            .type = QEMU_OPT_BOOL,
    934        },{
    935            .name = "clipboard",
    936            .type = QEMU_OPT_BOOL,
    937#ifdef CONFIG_LINUX
    938        },{
    939            .name = "tight",
    940            .type = QEMU_OPT_BOOL,
    941            .def_value_str = "on",
    942        },{
    943            .name = "abstract",
    944            .type = QEMU_OPT_BOOL,
    945#endif
    946        },
    947        { /* end of list */ }
    948    },
    949};
    950
    951bool qemu_chr_has_feature(Chardev *chr,
    952                          ChardevFeature feature)
    953{
    954    return test_bit(feature, chr->features);
    955}
    956
    957void qemu_chr_set_feature(Chardev *chr,
    958                           ChardevFeature feature)
    959{
    960    return set_bit(feature, chr->features);
    961}
    962
    963static Chardev *chardev_new(const char *id, const char *typename,
    964                            ChardevBackend *backend,
    965                            GMainContext *gcontext,
    966                            bool handover_yank_instance,
    967                            Error **errp)
    968{
    969    Object *obj;
    970    Chardev *chr = NULL;
    971    Error *local_err = NULL;
    972    bool be_opened = true;
    973
    974    assert(g_str_has_prefix(typename, "chardev-"));
    975    assert(id);
    976
    977    obj = object_new(typename);
    978    chr = CHARDEV(obj);
    979    chr->handover_yank_instance = handover_yank_instance;
    980    chr->label = g_strdup(id);
    981    chr->gcontext = gcontext;
    982
    983    qemu_char_open(chr, backend, &be_opened, &local_err);
    984    if (local_err) {
    985        error_propagate(errp, local_err);
    986        object_unref(obj);
    987        return NULL;
    988    }
    989
    990    if (!chr->filename) {
    991        chr->filename = g_strdup(typename + 8);
    992    }
    993    if (be_opened) {
    994        qemu_chr_be_event(chr, CHR_EVENT_OPENED);
    995    }
    996
    997    return chr;
    998}
    999
   1000Chardev *qemu_chardev_new(const char *id, const char *typename,
   1001                          ChardevBackend *backend,
   1002                          GMainContext *gcontext,
   1003                          Error **errp)
   1004{
   1005    Chardev *chr;
   1006    g_autofree char *genid = NULL;
   1007
   1008    if (!id) {
   1009        genid = id_generate(ID_CHR);
   1010        id = genid;
   1011    }
   1012
   1013    chr = chardev_new(id, typename, backend, gcontext, false, errp);
   1014    if (!chr) {
   1015        return NULL;
   1016    }
   1017
   1018    if (!object_property_try_add_child(get_chardevs_root(), id, OBJECT(chr),
   1019                                       errp)) {
   1020        object_unref(OBJECT(chr));
   1021        return NULL;
   1022    }
   1023    object_unref(OBJECT(chr));
   1024
   1025    return chr;
   1026}
   1027
   1028ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
   1029                               Error **errp)
   1030{
   1031    ERRP_GUARD();
   1032    const ChardevClass *cc;
   1033    ChardevReturn *ret;
   1034    g_autoptr(Chardev) chr = NULL;
   1035
   1036    if (qemu_chr_find(id)) {
   1037        error_setg(errp, "Chardev with id '%s' already exists", id);
   1038        return NULL;
   1039    }
   1040
   1041    cc = char_get_class(ChardevBackendKind_str(backend->type), errp);
   1042    if (!cc) {
   1043        goto err;
   1044    }
   1045
   1046    chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
   1047                      backend, NULL, false, errp);
   1048    if (!chr) {
   1049        goto err;
   1050    }
   1051
   1052    if (!object_property_try_add_child(get_chardevs_root(), id, OBJECT(chr),
   1053                                       errp)) {
   1054        goto err;
   1055    }
   1056
   1057    ret = g_new0(ChardevReturn, 1);
   1058    if (CHARDEV_IS_PTY(chr)) {
   1059        ret->pty = g_strdup(chr->filename + 4);
   1060        ret->has_pty = true;
   1061    }
   1062
   1063    return ret;
   1064
   1065err:
   1066    error_prepend(errp, "Failed to add chardev '%s': ", id);
   1067    return NULL;
   1068}
   1069
   1070ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend,
   1071                                  Error **errp)
   1072{
   1073    CharBackend *be;
   1074    const ChardevClass *cc, *cc_new;
   1075    Chardev *chr, *chr_new;
   1076    bool closed_sent = false;
   1077    bool handover_yank_instance;
   1078    ChardevReturn *ret;
   1079
   1080    chr = qemu_chr_find(id);
   1081    if (!chr) {
   1082        error_setg(errp, "Chardev '%s' does not exist", id);
   1083        return NULL;
   1084    }
   1085
   1086    if (CHARDEV_IS_MUX(chr)) {
   1087        error_setg(errp, "Mux device hotswap not supported yet");
   1088        return NULL;
   1089    }
   1090
   1091    if (qemu_chr_replay(chr)) {
   1092        error_setg(errp,
   1093            "Chardev '%s' cannot be changed in record/replay mode", id);
   1094        return NULL;
   1095    }
   1096
   1097    be = chr->be;
   1098    if (!be) {
   1099        /* easy case */
   1100        object_unparent(OBJECT(chr));
   1101        return qmp_chardev_add(id, backend, errp);
   1102    }
   1103
   1104    if (!be->chr_be_change) {
   1105        error_setg(errp, "Chardev user does not support chardev hotswap");
   1106        return NULL;
   1107    }
   1108
   1109    cc = CHARDEV_GET_CLASS(chr);
   1110    cc_new = char_get_class(ChardevBackendKind_str(backend->type), errp);
   1111    if (!cc_new) {
   1112        return NULL;
   1113    }
   1114
   1115    /*
   1116     * The new chardev should not register a yank instance if the current
   1117     * chardev has registered one already.
   1118     */
   1119    handover_yank_instance = cc->supports_yank && cc_new->supports_yank;
   1120
   1121    chr_new = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc_new)),
   1122                          backend, chr->gcontext, handover_yank_instance, errp);
   1123    if (!chr_new) {
   1124        return NULL;
   1125    }
   1126
   1127    if (chr->be_open && !chr_new->be_open) {
   1128        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
   1129        closed_sent = true;
   1130    }
   1131
   1132    chr->be = NULL;
   1133    qemu_chr_fe_init(be, chr_new, &error_abort);
   1134
   1135    if (be->chr_be_change(be->opaque) < 0) {
   1136        error_setg(errp, "Chardev '%s' change failed", chr_new->label);
   1137        chr_new->be = NULL;
   1138        qemu_chr_fe_init(be, chr, &error_abort);
   1139        if (closed_sent) {
   1140            qemu_chr_be_event(chr, CHR_EVENT_OPENED);
   1141        }
   1142        object_unref(OBJECT(chr_new));
   1143        return NULL;
   1144    }
   1145
   1146    /* change successfull, clean up */
   1147    chr_new->handover_yank_instance = false;
   1148
   1149    /*
   1150     * When the old chardev is freed, it should not unregister the yank
   1151     * instance if the new chardev needs it.
   1152     */
   1153    chr->handover_yank_instance = handover_yank_instance;
   1154
   1155    object_unparent(OBJECT(chr));
   1156    object_property_add_child(get_chardevs_root(), chr_new->label,
   1157                              OBJECT(chr_new));
   1158    object_unref(OBJECT(chr_new));
   1159
   1160    ret = g_new0(ChardevReturn, 1);
   1161    if (CHARDEV_IS_PTY(chr_new)) {
   1162        ret->pty = g_strdup(chr_new->filename + 4);
   1163        ret->has_pty = true;
   1164    }
   1165
   1166    return ret;
   1167}
   1168
   1169void qmp_chardev_remove(const char *id, Error **errp)
   1170{
   1171    Chardev *chr;
   1172
   1173    chr = qemu_chr_find(id);
   1174    if (chr == NULL) {
   1175        error_setg(errp, "Chardev '%s' not found", id);
   1176        return;
   1177    }
   1178    if (qemu_chr_is_busy(chr)) {
   1179        error_setg(errp, "Chardev '%s' is busy", id);
   1180        return;
   1181    }
   1182    if (qemu_chr_replay(chr)) {
   1183        error_setg(errp,
   1184            "Chardev '%s' cannot be unplugged in record/replay mode", id);
   1185        return;
   1186    }
   1187    object_unparent(OBJECT(chr));
   1188}
   1189
   1190void qmp_chardev_send_break(const char *id, Error **errp)
   1191{
   1192    Chardev *chr;
   1193
   1194    chr = qemu_chr_find(id);
   1195    if (chr == NULL) {
   1196        error_setg(errp, "Chardev '%s' not found", id);
   1197        return;
   1198    }
   1199    qemu_chr_be_event(chr, CHR_EVENT_BREAK);
   1200}
   1201
   1202/*
   1203 * Add a timeout callback for the chardev (in milliseconds), return
   1204 * the GSource object created. Please use this to add timeout hook for
   1205 * chardev instead of g_timeout_add() and g_timeout_add_seconds(), to
   1206 * make sure the gcontext that the task bound to is correct.
   1207 */
   1208GSource *qemu_chr_timeout_add_ms(Chardev *chr, guint ms,
   1209                                 GSourceFunc func, void *private)
   1210{
   1211    GSource *source = g_timeout_source_new(ms);
   1212
   1213    assert(func);
   1214    g_source_set_callback(source, func, private, NULL);
   1215    g_source_attach(source, chr->gcontext);
   1216
   1217    return source;
   1218}
   1219
   1220void qemu_chr_cleanup(void)
   1221{
   1222    object_unparent(get_chardevs_root());
   1223}
   1224
   1225static void register_types(void)
   1226{
   1227    type_register_static(&char_type_info);
   1228}
   1229
   1230type_init(register_types);