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-fe.c (9663B)


      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#include "qemu/osdep.h"
     25#include "qemu/error-report.h"
     26#include "qapi/error.h"
     27#include "qapi/qmp/qerror.h"
     28#include "sysemu/replay.h"
     29
     30#include "chardev/char-fe.h"
     31#include "chardev/char-io.h"
     32#include "chardev-internal.h"
     33
     34int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
     35{
     36    Chardev *s = be->chr;
     37
     38    if (!s) {
     39        return 0;
     40    }
     41
     42    return qemu_chr_write(s, buf, len, false);
     43}
     44
     45int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
     46{
     47    Chardev *s = be->chr;
     48
     49    if (!s) {
     50        return 0;
     51    }
     52
     53    return qemu_chr_write(s, buf, len, true);
     54}
     55
     56int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
     57{
     58    Chardev *s = be->chr;
     59    int offset = 0;
     60    int res;
     61
     62    if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) {
     63        return 0;
     64    }
     65
     66    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
     67        return replay_char_read_all_load(buf);
     68    }
     69
     70    while (offset < len) {
     71    retry:
     72        res = CHARDEV_GET_CLASS(s)->chr_sync_read(s, buf + offset,
     73                                                  len - offset);
     74        if (res == -1 && errno == EAGAIN) {
     75            g_usleep(100);
     76            goto retry;
     77        }
     78
     79        if (res == 0) {
     80            break;
     81        }
     82
     83        if (res < 0) {
     84            if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
     85                replay_char_read_all_save_error(res);
     86            }
     87            return res;
     88        }
     89
     90        offset += res;
     91    }
     92
     93    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
     94        replay_char_read_all_save_buf(buf, offset);
     95    }
     96    return offset;
     97}
     98
     99int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
    100{
    101    Chardev *s = be->chr;
    102    int res;
    103
    104    if (!s || !CHARDEV_GET_CLASS(s)->chr_ioctl || qemu_chr_replay(s)) {
    105        res = -ENOTSUP;
    106    } else {
    107        res = CHARDEV_GET_CLASS(s)->chr_ioctl(s, cmd, arg);
    108    }
    109
    110    return res;
    111}
    112
    113int qemu_chr_fe_get_msgfd(CharBackend *be)
    114{
    115    Chardev *s = be->chr;
    116    int fd;
    117    int res = (qemu_chr_fe_get_msgfds(be, &fd, 1) == 1) ? fd : -1;
    118    if (s && qemu_chr_replay(s)) {
    119        error_report("Replay: get msgfd is not supported "
    120                     "for serial devices yet");
    121        exit(1);
    122    }
    123    return res;
    124}
    125
    126int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
    127{
    128    Chardev *s = be->chr;
    129
    130    if (!s) {
    131        return -1;
    132    }
    133
    134    return CHARDEV_GET_CLASS(s)->get_msgfds ?
    135        CHARDEV_GET_CLASS(s)->get_msgfds(s, fds, len) : -1;
    136}
    137
    138int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
    139{
    140    Chardev *s = be->chr;
    141
    142    if (!s) {
    143        return -1;
    144    }
    145
    146    return CHARDEV_GET_CLASS(s)->set_msgfds ?
    147        CHARDEV_GET_CLASS(s)->set_msgfds(s, fds, num) : -1;
    148}
    149
    150void qemu_chr_fe_accept_input(CharBackend *be)
    151{
    152    Chardev *s = be->chr;
    153
    154    if (!s) {
    155        return;
    156    }
    157
    158    if (CHARDEV_GET_CLASS(s)->chr_accept_input) {
    159        CHARDEV_GET_CLASS(s)->chr_accept_input(s);
    160    }
    161    qemu_notify_event();
    162}
    163
    164void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
    165{
    166    char buf[CHR_READ_BUF_LEN];
    167    va_list ap;
    168    va_start(ap, fmt);
    169    vsnprintf(buf, sizeof(buf), fmt, ap);
    170    /* XXX this blocks entire thread. Rewrite to use
    171     * qemu_chr_fe_write and background I/O callbacks */
    172    qemu_chr_fe_write_all(be, (uint8_t *)buf, strlen(buf));
    173    va_end(ap);
    174}
    175
    176Chardev *qemu_chr_fe_get_driver(CharBackend *be)
    177{
    178    /* this is unsafe for the users that support chardev hotswap */
    179    assert(be->chr_be_change == NULL);
    180    return be->chr;
    181}
    182
    183bool qemu_chr_fe_backend_connected(CharBackend *be)
    184{
    185    return !!be->chr;
    186}
    187
    188bool qemu_chr_fe_backend_open(CharBackend *be)
    189{
    190    return be->chr && be->chr->be_open;
    191}
    192
    193bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
    194{
    195    int tag = 0;
    196
    197    if (s) {
    198        if (CHARDEV_IS_MUX(s)) {
    199            MuxChardev *d = MUX_CHARDEV(s);
    200
    201            if (d->mux_cnt >= MAX_MUX) {
    202                goto unavailable;
    203            }
    204
    205            d->backends[d->mux_cnt] = b;
    206            tag = d->mux_cnt++;
    207        } else if (s->be) {
    208            goto unavailable;
    209        } else {
    210            s->be = b;
    211        }
    212    }
    213
    214    b->fe_open = false;
    215    b->tag = tag;
    216    b->chr = s;
    217    return true;
    218
    219unavailable:
    220    error_setg(errp, QERR_DEVICE_IN_USE, s->label);
    221    return false;
    222}
    223
    224void qemu_chr_fe_deinit(CharBackend *b, bool del)
    225{
    226    assert(b);
    227
    228    if (b->chr) {
    229        qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, NULL, true);
    230        if (b->chr->be == b) {
    231            b->chr->be = NULL;
    232        }
    233        if (CHARDEV_IS_MUX(b->chr)) {
    234            MuxChardev *d = MUX_CHARDEV(b->chr);
    235            d->backends[b->tag] = NULL;
    236        }
    237        if (del) {
    238            Object *obj = OBJECT(b->chr);
    239            if (obj->parent) {
    240                object_unparent(obj);
    241            } else {
    242                object_unref(obj);
    243            }
    244        }
    245        b->chr = NULL;
    246    }
    247}
    248
    249void qemu_chr_fe_set_handlers_full(CharBackend *b,
    250                                   IOCanReadHandler *fd_can_read,
    251                                   IOReadHandler *fd_read,
    252                                   IOEventHandler *fd_event,
    253                                   BackendChangeHandler *be_change,
    254                                   void *opaque,
    255                                   GMainContext *context,
    256                                   bool set_open,
    257                                   bool sync_state)
    258{
    259    Chardev *s;
    260    int fe_open;
    261
    262    s = b->chr;
    263    if (!s) {
    264        return;
    265    }
    266
    267    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
    268        fe_open = 0;
    269        remove_fd_in_watch(s);
    270    } else {
    271        fe_open = 1;
    272    }
    273    b->chr_can_read = fd_can_read;
    274    b->chr_read = fd_read;
    275    b->chr_event = fd_event;
    276    b->chr_be_change = be_change;
    277    b->opaque = opaque;
    278
    279    qemu_chr_be_update_read_handlers(s, context);
    280
    281    if (set_open) {
    282        qemu_chr_fe_set_open(b, fe_open);
    283    }
    284
    285    if (fe_open) {
    286        qemu_chr_fe_take_focus(b);
    287        /* We're connecting to an already opened device, so let's make sure we
    288           also get the open event */
    289        if (sync_state && s->be_open) {
    290            qemu_chr_be_event(s, CHR_EVENT_OPENED);
    291        }
    292    }
    293}
    294
    295void qemu_chr_fe_set_handlers(CharBackend *b,
    296                              IOCanReadHandler *fd_can_read,
    297                              IOReadHandler *fd_read,
    298                              IOEventHandler *fd_event,
    299                              BackendChangeHandler *be_change,
    300                              void *opaque,
    301                              GMainContext *context,
    302                              bool set_open)
    303{
    304    qemu_chr_fe_set_handlers_full(b, fd_can_read, fd_read, fd_event, be_change,
    305                                  opaque, context, set_open,
    306                                  true);
    307}
    308
    309void qemu_chr_fe_take_focus(CharBackend *b)
    310{
    311    if (!b->chr) {
    312        return;
    313    }
    314
    315    if (CHARDEV_IS_MUX(b->chr)) {
    316        mux_set_focus(b->chr, b->tag);
    317    }
    318}
    319
    320int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
    321{
    322    if (!be->chr) {
    323        error_setg(errp, "missing associated backend");
    324        return -1;
    325    }
    326
    327    return qemu_chr_wait_connected(be->chr, errp);
    328}
    329
    330void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
    331{
    332    Chardev *chr = be->chr;
    333
    334    if (chr && CHARDEV_GET_CLASS(chr)->chr_set_echo) {
    335        CHARDEV_GET_CLASS(chr)->chr_set_echo(chr, echo);
    336    }
    337}
    338
    339void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
    340{
    341    Chardev *chr = be->chr;
    342
    343    if (!chr) {
    344        return;
    345    }
    346
    347    if (be->fe_open == fe_open) {
    348        return;
    349    }
    350    be->fe_open = fe_open;
    351    if (CHARDEV_GET_CLASS(chr)->chr_set_fe_open) {
    352        CHARDEV_GET_CLASS(chr)->chr_set_fe_open(chr, fe_open);
    353    }
    354}
    355
    356guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
    357                            FEWatchFunc func, void *user_data)
    358{
    359    Chardev *s = be->chr;
    360    GSource *src;
    361    guint tag;
    362
    363    if (!s || CHARDEV_GET_CLASS(s)->chr_add_watch == NULL) {
    364        return 0;
    365    }
    366
    367    src = CHARDEV_GET_CLASS(s)->chr_add_watch(s, cond);
    368    if (!src) {
    369        return 0;
    370    }
    371
    372    g_source_set_callback(src, (GSourceFunc)func, user_data, NULL);
    373    tag = g_source_attach(src, s->gcontext);
    374    g_source_unref(src);
    375
    376    return tag;
    377}
    378
    379void qemu_chr_fe_disconnect(CharBackend *be)
    380{
    381    Chardev *chr = be->chr;
    382
    383    if (chr && CHARDEV_GET_CLASS(chr)->chr_disconnect) {
    384        CHARDEV_GET_CLASS(chr)->chr_disconnect(chr);
    385    }
    386}