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-fd.c (6977B)


      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-common.h"
     27#include "qemu/module.h"
     28#include "qemu/sockets.h"
     29#include "qapi/error.h"
     30#include "chardev/char.h"
     31#include "chardev/char-fe.h"
     32#include "io/channel-file.h"
     33
     34#include "chardev/char-fd.h"
     35#include "chardev/char-io.h"
     36
     37/* Called with chr_write_lock held.  */
     38static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
     39{
     40    FDChardev *s = FD_CHARDEV(chr);
     41
     42    if (!s->ioc_out) {
     43        return -1;
     44    }
     45
     46    return io_channel_send(s->ioc_out, buf, len);
     47}
     48
     49static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     50{
     51    Chardev *chr = CHARDEV(opaque);
     52    FDChardev *s = FD_CHARDEV(opaque);
     53    int len;
     54    uint8_t buf[CHR_READ_BUF_LEN];
     55    ssize_t ret;
     56
     57    len = sizeof(buf);
     58    if (len > s->max_size) {
     59        len = s->max_size;
     60    }
     61    if (len == 0) {
     62        return TRUE;
     63    }
     64
     65    ret = qio_channel_read(
     66        chan, (gchar *)buf, len, NULL);
     67    if (ret == 0) {
     68        remove_fd_in_watch(chr);
     69        qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
     70        return FALSE;
     71    }
     72    if (ret > 0) {
     73        qemu_chr_be_write(chr, buf, ret);
     74    }
     75
     76    return TRUE;
     77}
     78
     79static int fd_chr_read_poll(void *opaque)
     80{
     81    Chardev *chr = CHARDEV(opaque);
     82    FDChardev *s = FD_CHARDEV(opaque);
     83
     84    s->max_size = qemu_chr_be_can_write(chr);
     85    return s->max_size;
     86}
     87
     88typedef struct FDSource {
     89    GSource parent;
     90
     91    GIOCondition cond;
     92} FDSource;
     93
     94static gboolean
     95fd_source_prepare(GSource *source,
     96                  gint *timeout_)
     97{
     98    FDSource *src = (FDSource *)source;
     99
    100    return src->cond != 0;
    101}
    102
    103static gboolean
    104fd_source_check(GSource *source)
    105{
    106    FDSource *src = (FDSource *)source;
    107
    108    return src->cond != 0;
    109}
    110
    111static gboolean
    112fd_source_dispatch(GSource *source, GSourceFunc callback,
    113                   gpointer user_data)
    114{
    115    FDSource *src = (FDSource *)source;
    116    FEWatchFunc func = (FEWatchFunc)callback;
    117    gboolean ret = G_SOURCE_CONTINUE;
    118
    119    if (src->cond) {
    120        ret = func(NULL, src->cond, user_data);
    121        src->cond = 0;
    122    }
    123
    124    return ret;
    125}
    126
    127static GSourceFuncs fd_source_funcs = {
    128  fd_source_prepare,
    129  fd_source_check,
    130  fd_source_dispatch,
    131  NULL, NULL, NULL
    132};
    133
    134static GSource *fd_source_new(FDChardev *chr)
    135{
    136    return g_source_new(&fd_source_funcs, sizeof(FDSource));
    137}
    138
    139static gboolean child_func(GIOChannel *source,
    140                           GIOCondition condition,
    141                           gpointer data)
    142{
    143    FDSource *parent = data;
    144
    145    parent->cond |= condition;
    146
    147    return G_SOURCE_CONTINUE;
    148}
    149
    150static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
    151{
    152    FDChardev *s = FD_CHARDEV(chr);
    153    g_autoptr(GSource) source = fd_source_new(s);
    154
    155    if (s->ioc_out) {
    156        g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_out, cond & ~G_IO_IN);
    157        g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
    158        g_source_add_child_source(source, child);
    159    }
    160    if (s->ioc_in) {
    161        g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_in, cond & ~G_IO_OUT);
    162        g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
    163        g_source_add_child_source(source, child);
    164    }
    165
    166    return g_steal_pointer(&source);
    167}
    168
    169static void fd_chr_update_read_handler(Chardev *chr)
    170{
    171    FDChardev *s = FD_CHARDEV(chr);
    172
    173    remove_fd_in_watch(chr);
    174    if (s->ioc_in) {
    175        chr->gsource = io_add_watch_poll(chr, s->ioc_in,
    176                                           fd_chr_read_poll,
    177                                           fd_chr_read, chr,
    178                                           chr->gcontext);
    179    }
    180}
    181
    182static void char_fd_finalize(Object *obj)
    183{
    184    Chardev *chr = CHARDEV(obj);
    185    FDChardev *s = FD_CHARDEV(obj);
    186
    187    remove_fd_in_watch(chr);
    188    if (s->ioc_in) {
    189        object_unref(OBJECT(s->ioc_in));
    190    }
    191    if (s->ioc_out) {
    192        object_unref(OBJECT(s->ioc_out));
    193    }
    194
    195    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
    196}
    197
    198int qmp_chardev_open_file_source(char *src, int flags, Error **errp)
    199{
    200    int fd = -1;
    201
    202    TFR(fd = qemu_open_old(src, flags, 0666));
    203    if (fd == -1) {
    204        error_setg_file_open(errp, errno, src);
    205    }
    206    return fd;
    207}
    208
    209/* open a character device to a unix fd */
    210void qemu_chr_open_fd(Chardev *chr,
    211                      int fd_in, int fd_out)
    212{
    213    FDChardev *s = FD_CHARDEV(chr);
    214    g_autofree char *name = NULL;
    215
    216    if (fd_out >= 0) {
    217        qemu_set_nonblock(fd_out);
    218    }
    219
    220    if (fd_out == fd_in && fd_in >= 0) {
    221        s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
    222        name = g_strdup_printf("chardev-file-%s", chr->label);
    223        qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
    224        s->ioc_out = QIO_CHANNEL(object_ref(s->ioc_in));
    225        return;
    226    }
    227
    228    if (fd_in >= 0) {
    229        s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
    230        name = g_strdup_printf("chardev-file-in-%s", chr->label);
    231        qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
    232    }
    233
    234    if (fd_out >= 0) {
    235        s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
    236        g_free(name);
    237        name = g_strdup_printf("chardev-file-out-%s", chr->label);
    238        qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
    239    }
    240}
    241
    242static void char_fd_class_init(ObjectClass *oc, void *data)
    243{
    244    ChardevClass *cc = CHARDEV_CLASS(oc);
    245
    246    cc->chr_add_watch = fd_chr_add_watch;
    247    cc->chr_write = fd_chr_write;
    248    cc->chr_update_read_handler = fd_chr_update_read_handler;
    249}
    250
    251static const TypeInfo char_fd_type_info = {
    252    .name = TYPE_CHARDEV_FD,
    253    .parent = TYPE_CHARDEV,
    254    .instance_size = sizeof(FDChardev),
    255    .instance_finalize = char_fd_finalize,
    256    .class_init = char_fd_class_init,
    257    .abstract = true,
    258};
    259
    260static void register_types(void)
    261{
    262    type_register_static(&char_fd_type_info);
    263}
    264
    265type_init(register_types);