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

virtio-input.c (9850B)


      1/*
      2 * This work is licensed under the terms of the GNU GPL, version 2 or
      3 * (at your option) any later version.  See the COPYING file in the
      4 * top-level directory.
      5 */
      6
      7#include "qemu/osdep.h"
      8#include "qapi/error.h"
      9#include "qemu/iov.h"
     10#include "qemu/module.h"
     11#include "trace.h"
     12
     13#include "hw/virtio/virtio.h"
     14#include "hw/qdev-properties.h"
     15#include "hw/virtio/virtio-input.h"
     16
     17#include "standard-headers/linux/input.h"
     18
     19#define VIRTIO_INPUT_VM_VERSION 1
     20
     21/* ----------------------------------------------------------------- */
     22
     23void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
     24{
     25    VirtQueueElement *elem;
     26    int i, len;
     27
     28    if (!vinput->active) {
     29        return;
     30    }
     31
     32    /* queue up events ... */
     33    if (vinput->qindex == vinput->qsize) {
     34        vinput->qsize++;
     35        vinput->queue = g_realloc(vinput->queue, vinput->qsize *
     36                                  sizeof(vinput->queue[0]));
     37    }
     38    vinput->queue[vinput->qindex++].event = *event;
     39
     40    /* ... until we see a report sync ... */
     41    if (event->type != cpu_to_le16(EV_SYN) ||
     42        event->code != cpu_to_le16(SYN_REPORT)) {
     43        return;
     44    }
     45
     46    /* ... then check available space ... */
     47    for (i = 0; i < vinput->qindex; i++) {
     48        elem = virtqueue_pop(vinput->evt, sizeof(VirtQueueElement));
     49        if (!elem) {
     50            while (--i >= 0) {
     51                virtqueue_unpop(vinput->evt, vinput->queue[i].elem, 0);
     52            }
     53            vinput->qindex = 0;
     54            trace_virtio_input_queue_full();
     55            return;
     56        }
     57        vinput->queue[i].elem = elem;
     58    }
     59
     60    /* ... and finally pass them to the guest */
     61    for (i = 0; i < vinput->qindex; i++) {
     62        elem = vinput->queue[i].elem;
     63        len = iov_from_buf(elem->in_sg, elem->in_num,
     64                           0, &vinput->queue[i].event, sizeof(virtio_input_event));
     65        virtqueue_push(vinput->evt, elem, len);
     66        g_free(elem);
     67    }
     68    virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
     69    vinput->qindex = 0;
     70}
     71
     72static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq)
     73{
     74    /* nothing */
     75}
     76
     77static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
     78{
     79    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
     80    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
     81    virtio_input_event event;
     82    VirtQueueElement *elem;
     83    int len;
     84
     85    for (;;) {
     86        elem = virtqueue_pop(vinput->sts, sizeof(VirtQueueElement));
     87        if (!elem) {
     88            break;
     89        }
     90
     91        memset(&event, 0, sizeof(event));
     92        len = iov_to_buf(elem->out_sg, elem->out_num,
     93                         0, &event, sizeof(event));
     94        if (vic->handle_status) {
     95            vic->handle_status(vinput, &event);
     96        }
     97        virtqueue_push(vinput->sts, elem, len);
     98        g_free(elem);
     99    }
    100    virtio_notify(vdev, vinput->sts);
    101}
    102
    103virtio_input_config *virtio_input_find_config(VirtIOInput *vinput,
    104                                              uint8_t select,
    105                                              uint8_t subsel)
    106{
    107    VirtIOInputConfig *cfg;
    108
    109    QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
    110        if (select == cfg->config.select &&
    111            subsel == cfg->config.subsel) {
    112            return &cfg->config;
    113        }
    114    }
    115    return NULL;
    116}
    117
    118void virtio_input_add_config(VirtIOInput *vinput,
    119                             virtio_input_config *config)
    120{
    121    VirtIOInputConfig *cfg;
    122
    123    if (virtio_input_find_config(vinput, config->select, config->subsel)) {
    124        /* should not happen */
    125        fprintf(stderr, "%s: duplicate config: %d/%d\n",
    126                __func__, config->select, config->subsel);
    127        abort();
    128    }
    129
    130    cfg = g_new0(VirtIOInputConfig, 1);
    131    cfg->config = *config;
    132    QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node);
    133}
    134
    135void virtio_input_init_config(VirtIOInput *vinput,
    136                              virtio_input_config *config)
    137{
    138    int i = 0;
    139
    140    QTAILQ_INIT(&vinput->cfg_list);
    141    while (config[i].select) {
    142        virtio_input_add_config(vinput, config + i);
    143        i++;
    144    }
    145}
    146
    147void virtio_input_idstr_config(VirtIOInput *vinput,
    148                               uint8_t select, const char *string)
    149{
    150    virtio_input_config id;
    151
    152    if (!string) {
    153        return;
    154    }
    155    memset(&id, 0, sizeof(id));
    156    id.select = select;
    157    id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string);
    158    virtio_input_add_config(vinput, &id);
    159}
    160
    161static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data)
    162{
    163    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
    164    virtio_input_config *config;
    165
    166    config = virtio_input_find_config(vinput, vinput->cfg_select,
    167                                      vinput->cfg_subsel);
    168    if (config) {
    169        memcpy(config_data, config, vinput->cfg_size);
    170    } else {
    171        memset(config_data, 0, vinput->cfg_size);
    172    }
    173}
    174
    175static void virtio_input_set_config(VirtIODevice *vdev,
    176                                    const uint8_t *config_data)
    177{
    178    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
    179    virtio_input_config *config = (virtio_input_config *)config_data;
    180
    181    vinput->cfg_select = config->select;
    182    vinput->cfg_subsel = config->subsel;
    183    virtio_notify_config(vdev);
    184}
    185
    186static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f,
    187                                          Error **errp)
    188{
    189    return f;
    190}
    191
    192static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
    193{
    194    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
    195    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
    196
    197    if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
    198        if (!vinput->active) {
    199            vinput->active = true;
    200            if (vic->change_active) {
    201                vic->change_active(vinput);
    202            }
    203        }
    204    }
    205}
    206
    207static void virtio_input_reset(VirtIODevice *vdev)
    208{
    209    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
    210    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
    211
    212    if (vinput->active) {
    213        vinput->active = false;
    214        if (vic->change_active) {
    215            vic->change_active(vinput);
    216        }
    217    }
    218}
    219
    220static int virtio_input_post_load(void *opaque, int version_id)
    221{
    222    VirtIOInput *vinput = opaque;
    223    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput);
    224    VirtIODevice *vdev = VIRTIO_DEVICE(vinput);
    225
    226    vinput->active = vdev->status & VIRTIO_CONFIG_S_DRIVER_OK;
    227    if (vic->change_active) {
    228        vic->change_active(vinput);
    229    }
    230    return 0;
    231}
    232
    233static void virtio_input_device_realize(DeviceState *dev, Error **errp)
    234{
    235    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
    236    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    237    VirtIOInput *vinput = VIRTIO_INPUT(dev);
    238    VirtIOInputConfig *cfg;
    239    Error *local_err = NULL;
    240
    241    if (vic->realize) {
    242        vic->realize(dev, &local_err);
    243        if (local_err) {
    244            error_propagate(errp, local_err);
    245            return;
    246        }
    247    }
    248
    249    virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL,
    250                              vinput->serial);
    251
    252    QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
    253        if (vinput->cfg_size < cfg->config.size) {
    254            vinput->cfg_size = cfg->config.size;
    255        }
    256    }
    257    vinput->cfg_size += 8;
    258    assert(vinput->cfg_size <= sizeof(virtio_input_config));
    259
    260    virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
    261                vinput->cfg_size);
    262    vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
    263    vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
    264}
    265
    266static void virtio_input_finalize(Object *obj)
    267{
    268    VirtIOInput *vinput = VIRTIO_INPUT(obj);
    269    VirtIOInputConfig *cfg, *next;
    270
    271    QTAILQ_FOREACH_SAFE(cfg, &vinput->cfg_list, node, next) {
    272        QTAILQ_REMOVE(&vinput->cfg_list, cfg, node);
    273        g_free(cfg);
    274    }
    275
    276    g_free(vinput->queue);
    277}
    278
    279static void virtio_input_device_unrealize(DeviceState *dev)
    280{
    281    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
    282    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    283    VirtIOInput *vinput = VIRTIO_INPUT(dev);
    284
    285    if (vic->unrealize) {
    286        vic->unrealize(dev);
    287    }
    288    virtio_delete_queue(vinput->evt);
    289    virtio_delete_queue(vinput->sts);
    290    virtio_cleanup(vdev);
    291}
    292
    293static const VMStateDescription vmstate_virtio_input = {
    294    .name = "virtio-input",
    295    .minimum_version_id = VIRTIO_INPUT_VM_VERSION,
    296    .version_id = VIRTIO_INPUT_VM_VERSION,
    297    .fields = (VMStateField[]) {
    298        VMSTATE_VIRTIO_DEVICE,
    299        VMSTATE_END_OF_LIST()
    300    },
    301    .post_load = virtio_input_post_load,
    302};
    303
    304static Property virtio_input_properties[] = {
    305    DEFINE_PROP_STRING("serial", VirtIOInput, serial),
    306    DEFINE_PROP_END_OF_LIST(),
    307};
    308
    309static void virtio_input_class_init(ObjectClass *klass, void *data)
    310{
    311    DeviceClass *dc = DEVICE_CLASS(klass);
    312    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
    313
    314    device_class_set_props(dc, virtio_input_properties);
    315    dc->vmsd           = &vmstate_virtio_input;
    316    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
    317    vdc->realize      = virtio_input_device_realize;
    318    vdc->unrealize    = virtio_input_device_unrealize;
    319    vdc->get_config   = virtio_input_get_config;
    320    vdc->set_config   = virtio_input_set_config;
    321    vdc->get_features = virtio_input_get_features;
    322    vdc->set_status   = virtio_input_set_status;
    323    vdc->reset        = virtio_input_reset;
    324}
    325
    326static const TypeInfo virtio_input_info = {
    327    .name          = TYPE_VIRTIO_INPUT,
    328    .parent        = TYPE_VIRTIO_DEVICE,
    329    .instance_size = sizeof(VirtIOInput),
    330    .class_size    = sizeof(VirtIOInputClass),
    331    .class_init    = virtio_input_class_init,
    332    .abstract      = true,
    333    .instance_finalize = virtio_input_finalize,
    334};
    335
    336/* ----------------------------------------------------------------- */
    337
    338static void virtio_register_types(void)
    339{
    340    type_register_static(&virtio_input_info);
    341}
    342
    343type_init(virtio_register_types)