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-pci.c (14667B)


      1/*
      2 * libqos virtio PCI driver
      3 *
      4 * Copyright (c) 2014 Marc MarĂ­
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7 * See the COPYING file in the top-level directory.
      8 */
      9
     10#include "qemu/osdep.h"
     11#include "libqtest.h"
     12#include "virtio.h"
     13#include "virtio-pci.h"
     14#include "pci.h"
     15#include "pci-pc.h"
     16#include "malloc.h"
     17#include "malloc-pc.h"
     18#include "qgraph.h"
     19#include "standard-headers/linux/virtio_ring.h"
     20#include "standard-headers/linux/virtio_pci.h"
     21
     22#include "hw/pci/pci.h"
     23#include "hw/pci/pci_regs.h"
     24
     25#include "virtio-pci-modern.h"
     26
     27/* virtio-pci is a superclass of all virtio-xxx-pci devices;
     28 * the relation between virtio-pci and virtio-xxx-pci is implicit,
     29 * and therefore virtio-pci does not produce virtio and is not
     30 * reached by any edge, not even as a "contains" edge.
     31 * In facts, every device is a QVirtioPCIDevice with
     32 * additional fields, since every one has its own
     33 * number of queues and various attributes.
     34 * Virtio-pci provides default functions to start the
     35 * hw and destroy the object, and nodes that want to
     36 * override them should always remember to call the
     37 * original qvirtio_pci_destructor and qvirtio_pci_start_hw.
     38 */
     39
     40#define CONFIG_BASE(dev) (VIRTIO_PCI_CONFIG_OFF((dev)->pdev->msix_enabled))
     41
     42static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t off)
     43{
     44    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     45    return qpci_io_readb(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
     46}
     47
     48/* PCI is always read in little-endian order
     49 * but virtio ( < 1.0) is in guest order
     50 * so with a big-endian guest the order has been reversed,
     51 * reverse it again
     52 * virtio-1.0 is always little-endian, like PCI
     53 */
     54
     55static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t off)
     56{
     57    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     58    uint16_t value;
     59
     60    value = qpci_io_readw(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
     61    if (qvirtio_is_big_endian(d)) {
     62        value = bswap16(value);
     63    }
     64    return value;
     65}
     66
     67static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t off)
     68{
     69    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     70    uint32_t value;
     71
     72    value = qpci_io_readl(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
     73    if (qvirtio_is_big_endian(d)) {
     74        value = bswap32(value);
     75    }
     76    return value;
     77}
     78
     79static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off)
     80{
     81    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     82    uint64_t val;
     83
     84    val = qpci_io_readq(dev->pdev, dev->bar, CONFIG_BASE(dev) + off);
     85    if (qvirtio_is_big_endian(d)) {
     86        val = bswap64(val);
     87    }
     88
     89    return val;
     90}
     91
     92static uint64_t qvirtio_pci_get_features(QVirtioDevice *d)
     93{
     94    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
     95    return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_HOST_FEATURES);
     96}
     97
     98static void qvirtio_pci_set_features(QVirtioDevice *d, uint64_t features)
     99{
    100    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    101    qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES, features);
    102}
    103
    104static uint64_t qvirtio_pci_get_guest_features(QVirtioDevice *d)
    105{
    106    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    107    return qpci_io_readl(dev->pdev, dev->bar, VIRTIO_PCI_GUEST_FEATURES);
    108}
    109
    110static uint8_t qvirtio_pci_get_status(QVirtioDevice *d)
    111{
    112    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    113    return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS);
    114}
    115
    116static void qvirtio_pci_set_status(QVirtioDevice *d, uint8_t status)
    117{
    118    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    119    qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_STATUS, status);
    120}
    121
    122static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
    123{
    124    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    125    QVirtQueuePCI *vqpci = (QVirtQueuePCI *)vq;
    126    uint32_t data;
    127
    128    if (dev->pdev->msix_enabled) {
    129        g_assert_cmpint(vqpci->msix_entry, !=, -1);
    130        if (qpci_msix_masked(dev->pdev, vqpci->msix_entry)) {
    131            /* No ISR checking should be done if masked, but read anyway */
    132            return qpci_msix_pending(dev->pdev, vqpci->msix_entry);
    133        } else {
    134            data = qtest_readl(dev->pdev->bus->qts, vqpci->msix_addr);
    135            if (data == vqpci->msix_data) {
    136                qtest_writel(dev->pdev->bus->qts, vqpci->msix_addr, 0);
    137                return true;
    138            } else {
    139                return false;
    140            }
    141        }
    142    } else {
    143        return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_ISR) & 1;
    144    }
    145}
    146
    147static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d)
    148{
    149    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    150    uint32_t data;
    151
    152    if (dev->pdev->msix_enabled) {
    153        g_assert_cmpint(dev->config_msix_entry, !=, -1);
    154        if (qpci_msix_masked(dev->pdev, dev->config_msix_entry)) {
    155            /* No ISR checking should be done if masked, but read anyway */
    156            return qpci_msix_pending(dev->pdev, dev->config_msix_entry);
    157        } else {
    158            data = qtest_readl(dev->pdev->bus->qts, dev->config_msix_addr);
    159            if (data == dev->config_msix_data) {
    160                qtest_writel(dev->pdev->bus->qts, dev->config_msix_addr, 0);
    161                return true;
    162            } else {
    163                return false;
    164            }
    165        }
    166    } else {
    167        return qpci_io_readb(dev->pdev, dev->bar, VIRTIO_PCI_ISR) & 2;
    168    }
    169}
    170
    171static void qvirtio_pci_wait_config_isr_status(QVirtioDevice *d,
    172                                               gint64 timeout_us)
    173{
    174    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    175    gint64 start_time = g_get_monotonic_time();
    176
    177    do {
    178        g_assert(g_get_monotonic_time() - start_time <= timeout_us);
    179        qtest_clock_step(dev->pdev->bus->qts, 100);
    180    } while (!qvirtio_pci_get_config_isr_status(d));
    181}
    182
    183static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index)
    184{
    185    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    186    qpci_io_writeb(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_SEL, index);
    187}
    188
    189static uint16_t qvirtio_pci_get_queue_size(QVirtioDevice *d)
    190{
    191    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    192    return qpci_io_readw(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NUM);
    193}
    194
    195static void qvirtio_pci_set_queue_address(QVirtioDevice *d, QVirtQueue *vq)
    196{
    197    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    198    uint64_t pfn = vq->desc / VIRTIO_PCI_VRING_ALIGN;
    199
    200    qpci_io_writel(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_PFN, pfn);
    201}
    202
    203QVirtQueue *qvirtio_pci_virtqueue_setup_common(QVirtioDevice *d,
    204                                               QGuestAllocator *alloc,
    205                                               uint16_t index)
    206{
    207    uint64_t feat;
    208    uint64_t addr;
    209    QVirtQueuePCI *vqpci;
    210    QVirtioPCIDevice *qvpcidev = container_of(d, QVirtioPCIDevice, vdev);
    211
    212    vqpci = g_malloc0(sizeof(*vqpci));
    213    feat = d->bus->get_guest_features(d);
    214
    215    d->bus->queue_select(d, index);
    216    vqpci->vq.vdev = d;
    217    vqpci->vq.index = index;
    218    vqpci->vq.size = d->bus->get_queue_size(d);
    219    vqpci->vq.free_head = 0;
    220    vqpci->vq.num_free = vqpci->vq.size;
    221    vqpci->vq.align = VIRTIO_PCI_VRING_ALIGN;
    222    vqpci->vq.indirect = feat & (1ull << VIRTIO_RING_F_INDIRECT_DESC);
    223    vqpci->vq.event = feat & (1ull << VIRTIO_RING_F_EVENT_IDX);
    224
    225    vqpci->msix_entry = -1;
    226    vqpci->msix_addr = 0;
    227    vqpci->msix_data = 0x12345678;
    228
    229    /* Check different than 0 */
    230    g_assert_cmpint(vqpci->vq.size, !=, 0);
    231
    232    /* Check power of 2 */
    233    g_assert_cmpint(vqpci->vq.size & (vqpci->vq.size - 1), ==, 0);
    234
    235    addr = guest_alloc(alloc, qvring_size(vqpci->vq.size,
    236                                          VIRTIO_PCI_VRING_ALIGN));
    237    qvring_init(qvpcidev->pdev->bus->qts, alloc, &vqpci->vq, addr);
    238    d->bus->set_queue_address(d, &vqpci->vq);
    239
    240    return &vqpci->vq;
    241}
    242
    243void qvirtio_pci_virtqueue_cleanup_common(QVirtQueue *vq,
    244                                          QGuestAllocator *alloc)
    245{
    246    QVirtQueuePCI *vqpci = container_of(vq, QVirtQueuePCI, vq);
    247
    248    guest_free(alloc, vq->desc);
    249    g_free(vqpci);
    250}
    251
    252static void qvirtio_pci_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq)
    253{
    254    QVirtioPCIDevice *dev = container_of(d, QVirtioPCIDevice, vdev);
    255    qpci_io_writew(dev->pdev, dev->bar, VIRTIO_PCI_QUEUE_NOTIFY, vq->index);
    256}
    257
    258static const QVirtioBus qvirtio_pci_legacy = {
    259    .config_readb = qvirtio_pci_config_readb,
    260    .config_readw = qvirtio_pci_config_readw,
    261    .config_readl = qvirtio_pci_config_readl,
    262    .config_readq = qvirtio_pci_config_readq,
    263    .get_features = qvirtio_pci_get_features,
    264    .set_features = qvirtio_pci_set_features,
    265    .get_guest_features = qvirtio_pci_get_guest_features,
    266    .get_status = qvirtio_pci_get_status,
    267    .set_status = qvirtio_pci_set_status,
    268    .get_queue_isr_status = qvirtio_pci_get_queue_isr_status,
    269    .wait_config_isr_status = qvirtio_pci_wait_config_isr_status,
    270    .queue_select = qvirtio_pci_queue_select,
    271    .get_queue_size = qvirtio_pci_get_queue_size,
    272    .set_queue_address = qvirtio_pci_set_queue_address,
    273    .virtqueue_setup = qvirtio_pci_virtqueue_setup_common,
    274    .virtqueue_cleanup = qvirtio_pci_virtqueue_cleanup_common,
    275    .virtqueue_kick = qvirtio_pci_virtqueue_kick,
    276};
    277
    278static void qvirtio_pci_set_config_vector(QVirtioPCIDevice *d, uint16_t entry)
    279{
    280    uint16_t vector;
    281
    282    qpci_io_writew(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR, entry);
    283    vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_CONFIG_VECTOR);
    284    g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR);
    285}
    286
    287static void qvirtio_pci_set_queue_vector(QVirtioPCIDevice *d, uint16_t vq_idx,
    288                                         uint16_t entry)
    289{
    290    uint16_t vector;
    291
    292    qvirtio_pci_queue_select(&d->vdev, vq_idx);
    293    qpci_io_writew(d->pdev, d->bar, VIRTIO_MSI_QUEUE_VECTOR, entry);
    294    vector = qpci_io_readw(d->pdev, d->bar, VIRTIO_MSI_QUEUE_VECTOR);
    295    g_assert_cmphex(vector, !=, VIRTIO_MSI_NO_VECTOR);
    296}
    297
    298static const QVirtioPCIMSIXOps qvirtio_pci_msix_ops_legacy = {
    299    .set_config_vector = qvirtio_pci_set_config_vector,
    300    .set_queue_vector = qvirtio_pci_set_queue_vector,
    301};
    302
    303void qvirtio_pci_device_enable(QVirtioPCIDevice *d)
    304{
    305    qpci_device_enable(d->pdev);
    306    d->bar = qpci_iomap(d->pdev, d->bar_idx, NULL);
    307}
    308
    309void qvirtio_pci_device_disable(QVirtioPCIDevice *d)
    310{
    311    qpci_iounmap(d->pdev, d->bar);
    312}
    313
    314void qvirtqueue_pci_msix_setup(QVirtioPCIDevice *d, QVirtQueuePCI *vqpci,
    315                                        QGuestAllocator *alloc, uint16_t entry)
    316{
    317    uint32_t control;
    318    uint64_t off;
    319
    320    g_assert(d->pdev->msix_enabled);
    321    off = d->pdev->msix_table_off + (entry * 16);
    322
    323    g_assert_cmpint(entry, >=, 0);
    324    g_assert_cmpint(entry, <, qpci_msix_table_size(d->pdev));
    325    vqpci->msix_entry = entry;
    326
    327    vqpci->msix_addr = guest_alloc(alloc, 4);
    328    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
    329                   off + PCI_MSIX_ENTRY_LOWER_ADDR, vqpci->msix_addr & ~0UL);
    330    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
    331                   off + PCI_MSIX_ENTRY_UPPER_ADDR,
    332                   (vqpci->msix_addr >> 32) & ~0UL);
    333    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
    334                   off + PCI_MSIX_ENTRY_DATA, vqpci->msix_data);
    335
    336    control = qpci_io_readl(d->pdev, d->pdev->msix_table_bar,
    337                            off + PCI_MSIX_ENTRY_VECTOR_CTRL);
    338    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
    339                   off + PCI_MSIX_ENTRY_VECTOR_CTRL,
    340                   control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
    341
    342    d->msix_ops->set_queue_vector(d, vqpci->vq.index, entry);
    343}
    344
    345void qvirtio_pci_set_msix_configuration_vector(QVirtioPCIDevice *d,
    346                                        QGuestAllocator *alloc, uint16_t entry)
    347{
    348    uint32_t control;
    349    uint64_t off;
    350
    351    g_assert(d->pdev->msix_enabled);
    352    off = d->pdev->msix_table_off + (entry * 16);
    353
    354    g_assert_cmpint(entry, >=, 0);
    355    g_assert_cmpint(entry, <, qpci_msix_table_size(d->pdev));
    356    d->config_msix_entry = entry;
    357
    358    d->config_msix_data = 0x12345678;
    359    d->config_msix_addr = guest_alloc(alloc, 4);
    360
    361    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
    362                   off + PCI_MSIX_ENTRY_LOWER_ADDR, d->config_msix_addr & ~0UL);
    363    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
    364                   off + PCI_MSIX_ENTRY_UPPER_ADDR,
    365                   (d->config_msix_addr >> 32) & ~0UL);
    366    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
    367                   off + PCI_MSIX_ENTRY_DATA, d->config_msix_data);
    368
    369    control = qpci_io_readl(d->pdev, d->pdev->msix_table_bar,
    370                            off + PCI_MSIX_ENTRY_VECTOR_CTRL);
    371    qpci_io_writel(d->pdev, d->pdev->msix_table_bar,
    372                   off + PCI_MSIX_ENTRY_VECTOR_CTRL,
    373                   control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
    374
    375    d->msix_ops->set_config_vector(d, entry);
    376}
    377
    378void qvirtio_pci_destructor(QOSGraphObject *obj)
    379{
    380    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)obj;
    381    qvirtio_pci_device_disable(dev);
    382    g_free(dev->pdev);
    383}
    384
    385void qvirtio_pci_start_hw(QOSGraphObject *obj)
    386{
    387    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)obj;
    388    qvirtio_pci_device_enable(dev);
    389    qvirtio_start_device(&dev->vdev);
    390}
    391
    392static void qvirtio_pci_init_legacy(QVirtioPCIDevice *dev)
    393{
    394    dev->vdev.device_type = qpci_config_readw(dev->pdev, PCI_SUBSYSTEM_ID);
    395    dev->bar_idx = 0;
    396    dev->vdev.bus = &qvirtio_pci_legacy;
    397    dev->msix_ops = &qvirtio_pci_msix_ops_legacy;
    398    dev->vdev.big_endian = qtest_big_endian(dev->pdev->bus->qts);
    399}
    400
    401static void qvirtio_pci_init_from_pcidev(QVirtioPCIDevice *dev, QPCIDevice *pci_dev)
    402{
    403    dev->pdev = pci_dev;
    404    dev->config_msix_entry = -1;
    405
    406    if (!qvirtio_pci_init_virtio_1(dev)) {
    407        qvirtio_pci_init_legacy(dev);
    408    }
    409
    410    /* each virtio-xxx-pci device should override at least this function */
    411    dev->obj.get_driver = NULL;
    412    dev->obj.start_hw = qvirtio_pci_start_hw;
    413    dev->obj.destructor = qvirtio_pci_destructor;
    414}
    415
    416void virtio_pci_init(QVirtioPCIDevice *dev, QPCIBus *bus, QPCIAddress * addr)
    417{
    418    QPCIDevice *pci_dev = qpci_device_find(bus, addr->devfn);
    419    g_assert_nonnull(pci_dev);
    420    qvirtio_pci_init_from_pcidev(dev, pci_dev);
    421}
    422
    423QVirtioPCIDevice *virtio_pci_new(QPCIBus *bus, QPCIAddress * addr)
    424{
    425    QVirtioPCIDevice *dev;
    426    QPCIDevice *pci_dev = qpci_device_find(bus, addr->devfn);
    427    if (!pci_dev) {
    428        return NULL;
    429    }
    430
    431    dev = g_new0(QVirtioPCIDevice, 1);
    432    qvirtio_pci_init_from_pcidev(dev, pci_dev);
    433    dev->obj.free = g_free;
    434    return dev;
    435}