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

pci-testdev.c (10053B)


      1/*
      2 * QEMU PCI test device
      3 *
      4 * Copyright (c) 2012 Red Hat Inc.
      5 * Author: Michael S. Tsirkin <mst@redhat.com>
      6 *
      7 * This program is free software; you can redistribute it and/or modify
      8 * it under the terms of the GNU General Public License as published by
      9 * the Free Software Foundation; either version 2 of the License, or
     10 * (at your option) any later version.
     11 *
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU General Public License along
     18 * with this program; if not, see <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "hw/pci/pci.h"
     23#include "hw/qdev-properties.h"
     24#include "qemu/event_notifier.h"
     25#include "qemu/module.h"
     26#include "sysemu/kvm.h"
     27#include "qom/object.h"
     28
     29typedef struct PCITestDevHdr {
     30    uint8_t test;
     31    uint8_t width;
     32    uint8_t pad0[2];
     33    uint32_t offset;
     34    uint8_t data;
     35    uint8_t pad1[3];
     36    uint32_t count;
     37    uint8_t name[];
     38} PCITestDevHdr;
     39
     40typedef struct IOTest {
     41    MemoryRegion *mr;
     42    EventNotifier notifier;
     43    bool hasnotifier;
     44    unsigned size;
     45    bool match_data;
     46    PCITestDevHdr *hdr;
     47    unsigned bufsize;
     48} IOTest;
     49
     50#define IOTEST_DATAMATCH 0xFA
     51#define IOTEST_NOMATCH   0xCE
     52
     53#define IOTEST_IOSIZE 128
     54#define IOTEST_MEMSIZE 2048
     55
     56static const char *iotest_test[] = {
     57    "no-eventfd",
     58    "wildcard-eventfd",
     59    "datamatch-eventfd"
     60};
     61
     62static const char *iotest_type[] = {
     63    "mmio",
     64    "portio"
     65};
     66
     67#define IOTEST_TEST(i) (iotest_test[((i) % ARRAY_SIZE(iotest_test))])
     68#define IOTEST_TYPE(i) (iotest_type[((i) / ARRAY_SIZE(iotest_test))])
     69#define IOTEST_MAX_TEST (ARRAY_SIZE(iotest_test))
     70#define IOTEST_MAX_TYPE (ARRAY_SIZE(iotest_type))
     71#define IOTEST_MAX (IOTEST_MAX_TEST * IOTEST_MAX_TYPE)
     72
     73enum {
     74    IOTEST_ACCESS_NAME,
     75    IOTEST_ACCESS_DATA,
     76    IOTEST_ACCESS_MAX,
     77};
     78
     79#define IOTEST_ACCESS_TYPE uint8_t
     80#define IOTEST_ACCESS_WIDTH (sizeof(uint8_t))
     81
     82struct PCITestDevState {
     83    /*< private >*/
     84    PCIDevice parent_obj;
     85    /*< public >*/
     86
     87    MemoryRegion mmio;
     88    MemoryRegion portio;
     89    IOTest *tests;
     90    int current;
     91
     92    uint64_t membar_size;
     93    MemoryRegion membar;
     94};
     95
     96#define TYPE_PCI_TEST_DEV "pci-testdev"
     97
     98OBJECT_DECLARE_SIMPLE_TYPE(PCITestDevState, PCI_TEST_DEV)
     99
    100#define IOTEST_IS_MEM(i) (strcmp(IOTEST_TYPE(i), "portio"))
    101#define IOTEST_REGION(d, i) (IOTEST_IS_MEM(i) ?  &(d)->mmio : &(d)->portio)
    102#define IOTEST_SIZE(i) (IOTEST_IS_MEM(i) ? IOTEST_MEMSIZE : IOTEST_IOSIZE)
    103#define IOTEST_PCI_BAR(i) (IOTEST_IS_MEM(i) ? PCI_BASE_ADDRESS_SPACE_MEMORY : \
    104                           PCI_BASE_ADDRESS_SPACE_IO)
    105
    106static int pci_testdev_start(IOTest *test)
    107{
    108    test->hdr->count = 0;
    109    if (!test->hasnotifier) {
    110        return 0;
    111    }
    112    event_notifier_test_and_clear(&test->notifier);
    113    memory_region_add_eventfd(test->mr,
    114                              le32_to_cpu(test->hdr->offset),
    115                              test->size,
    116                              test->match_data,
    117                              test->hdr->data,
    118                              &test->notifier);
    119    return 0;
    120}
    121
    122static void pci_testdev_stop(IOTest *test)
    123{
    124    if (!test->hasnotifier) {
    125        return;
    126    }
    127    memory_region_del_eventfd(test->mr,
    128                              le32_to_cpu(test->hdr->offset),
    129                              test->size,
    130                              test->match_data,
    131                              test->hdr->data,
    132                              &test->notifier);
    133}
    134
    135static void
    136pci_testdev_reset(PCITestDevState *d)
    137{
    138    if (d->current == -1) {
    139        return;
    140    }
    141    pci_testdev_stop(&d->tests[d->current]);
    142    d->current = -1;
    143}
    144
    145static void pci_testdev_inc(IOTest *test, unsigned inc)
    146{
    147    uint32_t c = le32_to_cpu(test->hdr->count);
    148    test->hdr->count = cpu_to_le32(c + inc);
    149}
    150
    151static void
    152pci_testdev_write(void *opaque, hwaddr addr, uint64_t val,
    153                  unsigned size, int type)
    154{
    155    PCITestDevState *d = opaque;
    156    IOTest *test;
    157    int t, r;
    158
    159    if (addr == offsetof(PCITestDevHdr, test)) {
    160        pci_testdev_reset(d);
    161        if (val >= IOTEST_MAX_TEST) {
    162            return;
    163        }
    164        t = type * IOTEST_MAX_TEST + val;
    165        r = pci_testdev_start(&d->tests[t]);
    166        if (r < 0) {
    167            return;
    168        }
    169        d->current = t;
    170        return;
    171    }
    172    if (d->current < 0) {
    173        return;
    174    }
    175    test = &d->tests[d->current];
    176    if (addr != le32_to_cpu(test->hdr->offset)) {
    177        return;
    178    }
    179    if (test->match_data && test->size != size) {
    180        return;
    181    }
    182    if (test->match_data && val != test->hdr->data) {
    183        return;
    184    }
    185    pci_testdev_inc(test, 1);
    186}
    187
    188static uint64_t
    189pci_testdev_read(void *opaque, hwaddr addr, unsigned size)
    190{
    191    PCITestDevState *d = opaque;
    192    const char *buf;
    193    IOTest *test;
    194    if (d->current < 0) {
    195        return 0;
    196    }
    197    test = &d->tests[d->current];
    198    buf = (const char *)test->hdr;
    199    if (addr + size >= test->bufsize) {
    200        return 0;
    201    }
    202    if (test->hasnotifier) {
    203        event_notifier_test_and_clear(&test->notifier);
    204    }
    205    return buf[addr];
    206}
    207
    208static void
    209pci_testdev_mmio_write(void *opaque, hwaddr addr, uint64_t val,
    210                       unsigned size)
    211{
    212    pci_testdev_write(opaque, addr, val, size, 0);
    213}
    214
    215static void
    216pci_testdev_pio_write(void *opaque, hwaddr addr, uint64_t val,
    217                       unsigned size)
    218{
    219    pci_testdev_write(opaque, addr, val, size, 1);
    220}
    221
    222static const MemoryRegionOps pci_testdev_mmio_ops = {
    223    .read = pci_testdev_read,
    224    .write = pci_testdev_mmio_write,
    225    .endianness = DEVICE_LITTLE_ENDIAN,
    226    .impl = {
    227        .min_access_size = 1,
    228        .max_access_size = 1,
    229    },
    230};
    231
    232static const MemoryRegionOps pci_testdev_pio_ops = {
    233    .read = pci_testdev_read,
    234    .write = pci_testdev_pio_write,
    235    .endianness = DEVICE_LITTLE_ENDIAN,
    236    .impl = {
    237        .min_access_size = 1,
    238        .max_access_size = 1,
    239    },
    240};
    241
    242static void pci_testdev_realize(PCIDevice *pci_dev, Error **errp)
    243{
    244    PCITestDevState *d = PCI_TEST_DEV(pci_dev);
    245    uint8_t *pci_conf;
    246    char *name;
    247    int r, i;
    248    bool fastmmio = kvm_ioeventfd_any_length_enabled();
    249
    250    pci_conf = pci_dev->config;
    251
    252    pci_conf[PCI_INTERRUPT_PIN] = 0; /* no interrupt pin */
    253
    254    memory_region_init_io(&d->mmio, OBJECT(d), &pci_testdev_mmio_ops, d,
    255                          "pci-testdev-mmio", IOTEST_MEMSIZE * 2);
    256    memory_region_init_io(&d->portio, OBJECT(d), &pci_testdev_pio_ops, d,
    257                          "pci-testdev-portio", IOTEST_IOSIZE * 2);
    258    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
    259    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->portio);
    260
    261    if (d->membar_size) {
    262        memory_region_init(&d->membar, OBJECT(d), "pci-testdev-membar",
    263                           d->membar_size);
    264        pci_register_bar(pci_dev, 2,
    265                         PCI_BASE_ADDRESS_SPACE_MEMORY |
    266                         PCI_BASE_ADDRESS_MEM_PREFETCH |
    267                         PCI_BASE_ADDRESS_MEM_TYPE_64,
    268                         &d->membar);
    269    }
    270
    271    d->current = -1;
    272    d->tests = g_malloc0(IOTEST_MAX * sizeof *d->tests);
    273    for (i = 0; i < IOTEST_MAX; ++i) {
    274        IOTest *test = &d->tests[i];
    275        name = g_strdup_printf("%s-%s", IOTEST_TYPE(i), IOTEST_TEST(i));
    276        test->bufsize = sizeof(PCITestDevHdr) + strlen(name) + 1;
    277        test->hdr = g_malloc0(test->bufsize);
    278        memcpy(test->hdr->name, name, strlen(name) + 1);
    279        g_free(name);
    280        test->hdr->offset = cpu_to_le32(IOTEST_SIZE(i) + i * IOTEST_ACCESS_WIDTH);
    281        test->match_data = strcmp(IOTEST_TEST(i), "wildcard-eventfd");
    282        if (fastmmio && IOTEST_IS_MEM(i) && !test->match_data) {
    283            test->size = 0;
    284        } else {
    285            test->size = IOTEST_ACCESS_WIDTH;
    286        }
    287        test->hdr->test = i;
    288        test->hdr->data = test->match_data ? IOTEST_DATAMATCH : IOTEST_NOMATCH;
    289        test->hdr->width = IOTEST_ACCESS_WIDTH;
    290        test->mr = IOTEST_REGION(d, i);
    291        if (!strcmp(IOTEST_TEST(i), "no-eventfd")) {
    292            test->hasnotifier = false;
    293            continue;
    294        }
    295        r = event_notifier_init(&test->notifier, 0);
    296        assert(r >= 0);
    297        test->hasnotifier = true;
    298    }
    299}
    300
    301static void
    302pci_testdev_uninit(PCIDevice *dev)
    303{
    304    PCITestDevState *d = PCI_TEST_DEV(dev);
    305    int i;
    306
    307    pci_testdev_reset(d);
    308    for (i = 0; i < IOTEST_MAX; ++i) {
    309        if (d->tests[i].hasnotifier) {
    310            event_notifier_cleanup(&d->tests[i].notifier);
    311        }
    312        g_free(d->tests[i].hdr);
    313    }
    314    g_free(d->tests);
    315}
    316
    317static void qdev_pci_testdev_reset(DeviceState *dev)
    318{
    319    PCITestDevState *d = PCI_TEST_DEV(dev);
    320    pci_testdev_reset(d);
    321}
    322
    323static Property pci_testdev_properties[] = {
    324    DEFINE_PROP_SIZE("membar", PCITestDevState, membar_size, 0),
    325    DEFINE_PROP_END_OF_LIST(),
    326};
    327
    328static void pci_testdev_class_init(ObjectClass *klass, void *data)
    329{
    330    DeviceClass *dc = DEVICE_CLASS(klass);
    331    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    332
    333    k->realize = pci_testdev_realize;
    334    k->exit = pci_testdev_uninit;
    335    k->vendor_id = PCI_VENDOR_ID_REDHAT;
    336    k->device_id = PCI_DEVICE_ID_REDHAT_TEST;
    337    k->revision = 0x00;
    338    k->class_id = PCI_CLASS_OTHERS;
    339    dc->desc = "PCI Test Device";
    340    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    341    dc->reset = qdev_pci_testdev_reset;
    342    device_class_set_props(dc, pci_testdev_properties);
    343}
    344
    345static const TypeInfo pci_testdev_info = {
    346    .name          = TYPE_PCI_TEST_DEV,
    347    .parent        = TYPE_PCI_DEVICE,
    348    .instance_size = sizeof(PCITestDevState),
    349    .class_init    = pci_testdev_class_init,
    350    .interfaces = (InterfaceInfo[]) {
    351        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
    352        { },
    353    },
    354};
    355
    356static void pci_testdev_register_types(void)
    357{
    358    type_register_static(&pci_testdev_info);
    359}
    360
    361type_init(pci_testdev_register_types)