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-bus.c (10290B)


      1/*
      2 * VirtioBus
      3 *
      4 *  Copyright (C) 2012 : GreenSocs Ltd
      5 *      http://www.greensocs.com/ , email: info@greensocs.com
      6 *
      7 *  Developed by :
      8 *  Frederic Konrad   <fred.konrad@greensocs.com>
      9 *
     10 * This program is free software; you can redistribute it and/or modify
     11 * it under the terms of the GNU General Public License as published by
     12 * the Free Software Foundation, either version 2 of the License, or
     13 * (at your option) any later version.
     14 *
     15 * This program is distributed in the hope that it will be useful,
     16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18 * GNU General Public License for more details.
     19 *
     20 * You should have received a copy of the GNU General Public License along
     21 * with this program; if not, see <http://www.gnu.org/licenses/>.
     22 *
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "qemu/error-report.h"
     27#include "qemu/module.h"
     28#include "qapi/error.h"
     29#include "hw/virtio/virtio-bus.h"
     30#include "hw/virtio/virtio.h"
     31#include "exec/address-spaces.h"
     32
     33/* #define DEBUG_VIRTIO_BUS */
     34
     35#ifdef DEBUG_VIRTIO_BUS
     36#define DPRINTF(fmt, ...) \
     37do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
     38#else
     39#define DPRINTF(fmt, ...) do { } while (0)
     40#endif
     41
     42/* A VirtIODevice is being plugged */
     43void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
     44{
     45    DeviceState *qdev = DEVICE(vdev);
     46    BusState *qbus = BUS(qdev_get_parent_bus(qdev));
     47    VirtioBusState *bus = VIRTIO_BUS(qbus);
     48    VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
     49    VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
     50    bool has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
     51    Error *local_err = NULL;
     52
     53    DPRINTF("%s: plug device.\n", qbus->name);
     54
     55    if (klass->pre_plugged != NULL) {
     56        klass->pre_plugged(qbus->parent, &local_err);
     57        if (local_err) {
     58            error_propagate(errp, local_err);
     59            return;
     60        }
     61    }
     62
     63    /* Get the features of the plugged device. */
     64    assert(vdc->get_features != NULL);
     65    vdev->host_features = vdc->get_features(vdev, vdev->host_features,
     66                                            &local_err);
     67    if (local_err) {
     68        error_propagate(errp, local_err);
     69        return;
     70    }
     71
     72    if (has_iommu && !virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
     73        error_setg(errp, "iommu_platform=true is not supported by the device");
     74        return;
     75    }
     76
     77    if (klass->device_plugged != NULL) {
     78        klass->device_plugged(qbus->parent, &local_err);
     79    }
     80    if (local_err) {
     81        error_propagate(errp, local_err);
     82        return;
     83    }
     84
     85    if (klass->get_dma_as != NULL && has_iommu) {
     86        virtio_add_feature(&vdev->host_features, VIRTIO_F_IOMMU_PLATFORM);
     87        vdev->dma_as = klass->get_dma_as(qbus->parent);
     88    } else {
     89        vdev->dma_as = &address_space_memory;
     90    }
     91}
     92
     93/* Reset the virtio_bus */
     94void virtio_bus_reset(VirtioBusState *bus)
     95{
     96    VirtIODevice *vdev = virtio_bus_get_device(bus);
     97
     98    DPRINTF("%s: reset device.\n", BUS(bus)->name);
     99    if (vdev != NULL) {
    100        virtio_reset(vdev);
    101    }
    102}
    103
    104/* A VirtIODevice is being unplugged */
    105void virtio_bus_device_unplugged(VirtIODevice *vdev)
    106{
    107    DeviceState *qdev = DEVICE(vdev);
    108    BusState *qbus = BUS(qdev_get_parent_bus(qdev));
    109    VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus);
    110
    111    DPRINTF("%s: remove device.\n", qbus->name);
    112
    113    if (vdev != NULL) {
    114        if (klass->device_unplugged != NULL) {
    115            klass->device_unplugged(qbus->parent);
    116        }
    117    }
    118}
    119
    120/* Get the device id of the plugged device. */
    121uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus)
    122{
    123    VirtIODevice *vdev = virtio_bus_get_device(bus);
    124    assert(vdev != NULL);
    125    return vdev->device_id;
    126}
    127
    128/* Get the config_len field of the plugged device. */
    129size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
    130{
    131    VirtIODevice *vdev = virtio_bus_get_device(bus);
    132    assert(vdev != NULL);
    133    return vdev->config_len;
    134}
    135
    136/* Get bad features of the plugged device. */
    137uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
    138{
    139    VirtIODevice *vdev = virtio_bus_get_device(bus);
    140    VirtioDeviceClass *k;
    141
    142    assert(vdev != NULL);
    143    k = VIRTIO_DEVICE_GET_CLASS(vdev);
    144    if (k->bad_features != NULL) {
    145        return k->bad_features(vdev);
    146    } else {
    147        return 0;
    148    }
    149}
    150
    151/* Get config of the plugged device. */
    152void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config)
    153{
    154    VirtIODevice *vdev = virtio_bus_get_device(bus);
    155    VirtioDeviceClass *k;
    156
    157    assert(vdev != NULL);
    158    k = VIRTIO_DEVICE_GET_CLASS(vdev);
    159    if (k->get_config != NULL) {
    160        k->get_config(vdev, config);
    161    }
    162}
    163
    164/* Set config of the plugged device. */
    165void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config)
    166{
    167    VirtIODevice *vdev = virtio_bus_get_device(bus);
    168    VirtioDeviceClass *k;
    169
    170    assert(vdev != NULL);
    171    k = VIRTIO_DEVICE_GET_CLASS(vdev);
    172    if (k->set_config != NULL) {
    173        k->set_config(vdev, config);
    174    }
    175}
    176
    177/* On success, ioeventfd ownership belongs to the caller.  */
    178int virtio_bus_grab_ioeventfd(VirtioBusState *bus)
    179{
    180    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
    181
    182    /* vhost can be used even if ioeventfd=off in the proxy device,
    183     * so do not check k->ioeventfd_enabled.
    184     */
    185    if (!k->ioeventfd_assign) {
    186        return -ENOSYS;
    187    }
    188
    189    if (bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) {
    190        virtio_bus_stop_ioeventfd(bus);
    191        /* Remember that we need to restart ioeventfd
    192         * when ioeventfd_grabbed becomes zero.
    193         */
    194        bus->ioeventfd_started = true;
    195    }
    196    bus->ioeventfd_grabbed++;
    197    return 0;
    198}
    199
    200void virtio_bus_release_ioeventfd(VirtioBusState *bus)
    201{
    202    assert(bus->ioeventfd_grabbed != 0);
    203    if (--bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) {
    204        /* Force virtio_bus_start_ioeventfd to act.  */
    205        bus->ioeventfd_started = false;
    206        virtio_bus_start_ioeventfd(bus);
    207    }
    208}
    209
    210int virtio_bus_start_ioeventfd(VirtioBusState *bus)
    211{
    212    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
    213    DeviceState *proxy = DEVICE(BUS(bus)->parent);
    214    VirtIODevice *vdev = virtio_bus_get_device(bus);
    215    VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
    216    int r;
    217
    218    if (!k->ioeventfd_assign || !k->ioeventfd_enabled(proxy)) {
    219        return -ENOSYS;
    220    }
    221    if (bus->ioeventfd_started) {
    222        return 0;
    223    }
    224
    225    /* Only set our notifier if we have ownership.  */
    226    if (!bus->ioeventfd_grabbed) {
    227        r = vdc->start_ioeventfd(vdev);
    228        if (r < 0) {
    229            error_report("%s: failed. Fallback to userspace (slower).", __func__);
    230            return r;
    231        }
    232    }
    233    bus->ioeventfd_started = true;
    234    return 0;
    235}
    236
    237void virtio_bus_stop_ioeventfd(VirtioBusState *bus)
    238{
    239    VirtIODevice *vdev;
    240    VirtioDeviceClass *vdc;
    241
    242    if (!bus->ioeventfd_started) {
    243        return;
    244    }
    245
    246    /* Only remove our notifier if we have ownership.  */
    247    if (!bus->ioeventfd_grabbed) {
    248        vdev = virtio_bus_get_device(bus);
    249        vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
    250        vdc->stop_ioeventfd(vdev);
    251    }
    252    bus->ioeventfd_started = false;
    253}
    254
    255bool virtio_bus_ioeventfd_enabled(VirtioBusState *bus)
    256{
    257    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
    258    DeviceState *proxy = DEVICE(BUS(bus)->parent);
    259
    260    return k->ioeventfd_assign && k->ioeventfd_enabled(proxy);
    261}
    262
    263/*
    264 * This function switches ioeventfd on/off in the device.
    265 * The caller must set or clear the handlers for the EventNotifier.
    266 */
    267int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign)
    268{
    269    VirtIODevice *vdev = virtio_bus_get_device(bus);
    270    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
    271    DeviceState *proxy = DEVICE(BUS(bus)->parent);
    272    VirtQueue *vq = virtio_get_queue(vdev, n);
    273    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
    274    int r = 0;
    275
    276    if (!k->ioeventfd_assign) {
    277        return -ENOSYS;
    278    }
    279
    280    if (assign) {
    281        r = event_notifier_init(notifier, 1);
    282        if (r < 0) {
    283            error_report("%s: unable to init event notifier: %s (%d)",
    284                         __func__, strerror(-r), r);
    285            return r;
    286        }
    287        r = k->ioeventfd_assign(proxy, notifier, n, true);
    288        if (r < 0) {
    289            error_report("%s: unable to assign ioeventfd: %d", __func__, r);
    290            virtio_bus_cleanup_host_notifier(bus, n);
    291        }
    292    } else {
    293        k->ioeventfd_assign(proxy, notifier, n, false);
    294    }
    295
    296    if (r == 0) {
    297        virtio_queue_set_host_notifier_enabled(vq, assign);
    298    }
    299
    300    return r;
    301}
    302
    303void virtio_bus_cleanup_host_notifier(VirtioBusState *bus, int n)
    304{
    305    VirtIODevice *vdev = virtio_bus_get_device(bus);
    306    VirtQueue *vq = virtio_get_queue(vdev, n);
    307    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
    308
    309    /* Test and clear notifier after disabling event,
    310     * in case poll callback didn't have time to run.
    311     */
    312    virtio_queue_host_notifier_read(notifier);
    313    event_notifier_cleanup(notifier);
    314}
    315
    316static char *virtio_bus_get_dev_path(DeviceState *dev)
    317{
    318    BusState *bus = qdev_get_parent_bus(dev);
    319    DeviceState *proxy = DEVICE(bus->parent);
    320    return qdev_get_dev_path(proxy);
    321}
    322
    323static char *virtio_bus_get_fw_dev_path(DeviceState *dev)
    324{
    325    return NULL;
    326}
    327
    328bool virtio_bus_device_iommu_enabled(VirtIODevice *vdev)
    329{
    330    DeviceState *qdev = DEVICE(vdev);
    331    BusState *qbus = BUS(qdev_get_parent_bus(qdev));
    332    VirtioBusState *bus = VIRTIO_BUS(qbus);
    333    VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
    334
    335    if (!klass->iommu_enabled) {
    336        return false;
    337    }
    338
    339    return klass->iommu_enabled(qbus->parent);
    340}
    341
    342static void virtio_bus_class_init(ObjectClass *klass, void *data)
    343{
    344    BusClass *bus_class = BUS_CLASS(klass);
    345    bus_class->get_dev_path = virtio_bus_get_dev_path;
    346    bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
    347}
    348
    349static const TypeInfo virtio_bus_info = {
    350    .name = TYPE_VIRTIO_BUS,
    351    .parent = TYPE_BUS,
    352    .instance_size = sizeof(VirtioBusState),
    353    .abstract = true,
    354    .class_size = sizeof(VirtioBusClass),
    355    .class_init = virtio_bus_class_init
    356};
    357
    358static void virtio_register_types(void)
    359{
    360    type_register_static(&virtio_bus_info);
    361}
    362
    363type_init(virtio_register_types)