qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     29 typedef 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 
     40 typedef 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 
     56 static const char *iotest_test[] = {
     57     "no-eventfd",
     58     "wildcard-eventfd",
     59     "datamatch-eventfd"
     60 };
     61 
     62 static 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 
     73 enum {
     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 
     82 struct 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 
     98 OBJECT_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 
    106 static 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 
    122 static 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 
    135 static void
    136 pci_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 
    145 static 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 
    151 static void
    152 pci_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 
    188 static uint64_t
    189 pci_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 
    208 static void
    209 pci_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 
    215 static void
    216 pci_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 
    222 static 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 
    232 static 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 
    242 static 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 
    301 static void
    302 pci_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 
    317 static void qdev_pci_testdev_reset(DeviceState *dev)
    318 {
    319     PCITestDevState *d = PCI_TEST_DEV(dev);
    320     pci_testdev_reset(d);
    321 }
    322 
    323 static Property pci_testdev_properties[] = {
    324     DEFINE_PROP_SIZE("membar", PCITestDevState, membar_size, 0),
    325     DEFINE_PROP_END_OF_LIST(),
    326 };
    327 
    328 static 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 
    345 static 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 
    356 static void pci_testdev_register_types(void)
    357 {
    358     type_register_static(&pci_testdev_info);
    359 }
    360 
    361 type_init(pci_testdev_register_types)