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-blk-test.c (24295B)


      1/*
      2 * QTest testcase for VirtIO Block Device
      3 *
      4 * Copyright (c) 2014 SUSE LINUX Products GmbH
      5 * Copyright (c) 2014 Marc MarĂ­
      6 *
      7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      8 * See the COPYING file in the top-level directory.
      9 */
     10
     11#include "qemu/osdep.h"
     12#include "libqtest-single.h"
     13#include "qemu/bswap.h"
     14#include "qemu/module.h"
     15#include "standard-headers/linux/virtio_blk.h"
     16#include "standard-headers/linux/virtio_pci.h"
     17#include "libqos/qgraph.h"
     18#include "libqos/virtio-blk.h"
     19
     20/* TODO actually test the results and get rid of this */
     21#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
     22
     23#define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
     24#define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
     25#define PCI_SLOT_HP             0x06
     26
     27typedef struct QVirtioBlkReq {
     28    uint32_t type;
     29    uint32_t ioprio;
     30    uint64_t sector;
     31    char *data;
     32    uint8_t status;
     33} QVirtioBlkReq;
     34
     35
     36#ifdef HOST_WORDS_BIGENDIAN
     37const bool host_is_big_endian = true;
     38#else
     39const bool host_is_big_endian; /* false */
     40#endif
     41
     42static void drive_destroy(void *path)
     43{
     44    unlink(path);
     45    g_free(path);
     46    qos_invalidate_command_line();
     47}
     48
     49static char *drive_create(void)
     50{
     51    int fd, ret;
     52    char *t_path = g_strdup("/tmp/qtest.XXXXXX");
     53
     54    /* Create a temporary raw image */
     55    fd = mkstemp(t_path);
     56    g_assert_cmpint(fd, >=, 0);
     57    ret = ftruncate(fd, TEST_IMAGE_SIZE);
     58    g_assert_cmpint(ret, ==, 0);
     59    close(fd);
     60
     61    g_test_queue_destroy(drive_destroy, t_path);
     62    return t_path;
     63}
     64
     65static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
     66{
     67    if (qvirtio_is_big_endian(d) != host_is_big_endian) {
     68        req->type = bswap32(req->type);
     69        req->ioprio = bswap32(req->ioprio);
     70        req->sector = bswap64(req->sector);
     71    }
     72}
     73
     74
     75static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
     76    struct virtio_blk_discard_write_zeroes *dwz_hdr)
     77{
     78    if (qvirtio_is_big_endian(d) != host_is_big_endian) {
     79        dwz_hdr->sector = bswap64(dwz_hdr->sector);
     80        dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
     81        dwz_hdr->flags = bswap32(dwz_hdr->flags);
     82    }
     83}
     84
     85static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
     86                                   QVirtioBlkReq *req, uint64_t data_size)
     87{
     88    uint64_t addr;
     89    uint8_t status = 0xFF;
     90
     91    switch (req->type) {
     92    case VIRTIO_BLK_T_IN:
     93    case VIRTIO_BLK_T_OUT:
     94        g_assert_cmpuint(data_size % 512, ==, 0);
     95        break;
     96    case VIRTIO_BLK_T_DISCARD:
     97    case VIRTIO_BLK_T_WRITE_ZEROES:
     98        g_assert_cmpuint(data_size %
     99                         sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
    100        break;
    101    default:
    102        g_assert_cmpuint(data_size, ==, 0);
    103    }
    104
    105    addr = guest_alloc(alloc, sizeof(*req) + data_size);
    106
    107    virtio_blk_fix_request(d, req);
    108
    109    memwrite(addr, req, 16);
    110    memwrite(addr + 16, req->data, data_size);
    111    memwrite(addr + 16 + data_size, &status, sizeof(status));
    112
    113    return addr;
    114}
    115
    116/* Returns the request virtqueue so the caller can perform further tests */
    117static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
    118{
    119    QVirtioBlkReq req;
    120    uint64_t req_addr;
    121    uint64_t capacity;
    122    uint64_t features;
    123    uint32_t free_head;
    124    uint8_t status;
    125    char *data;
    126    QTestState *qts = global_qtest;
    127    QVirtQueue *vq;
    128
    129    features = qvirtio_get_features(dev);
    130    features = features & ~(QVIRTIO_F_BAD_FEATURE |
    131                    (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    132                    (1u << VIRTIO_RING_F_EVENT_IDX) |
    133                    (1u << VIRTIO_BLK_F_SCSI));
    134    qvirtio_set_features(dev, features);
    135
    136    capacity = qvirtio_config_readq(dev, 0);
    137    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
    138
    139    vq = qvirtqueue_setup(dev, alloc, 0);
    140
    141    qvirtio_set_driver_ok(dev);
    142
    143    /* Write and read with 3 descriptor layout */
    144    /* Write request */
    145    req.type = VIRTIO_BLK_T_OUT;
    146    req.ioprio = 1;
    147    req.sector = 0;
    148    req.data = g_malloc0(512);
    149    strcpy(req.data, "TEST");
    150
    151    req_addr = virtio_blk_request(alloc, dev, &req, 512);
    152
    153    g_free(req.data);
    154
    155    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    156    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
    157    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    158
    159    qvirtqueue_kick(qts, dev, vq, free_head);
    160
    161    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    162                           QVIRTIO_BLK_TIMEOUT_US);
    163    status = readb(req_addr + 528);
    164    g_assert_cmpint(status, ==, 0);
    165
    166    guest_free(alloc, req_addr);
    167
    168    /* Read request */
    169    req.type = VIRTIO_BLK_T_IN;
    170    req.ioprio = 1;
    171    req.sector = 0;
    172    req.data = g_malloc0(512);
    173
    174    req_addr = virtio_blk_request(alloc, dev, &req, 512);
    175
    176    g_free(req.data);
    177
    178    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    179    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
    180    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    181
    182    qvirtqueue_kick(qts, dev, vq, free_head);
    183
    184    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    185                           QVIRTIO_BLK_TIMEOUT_US);
    186    status = readb(req_addr + 528);
    187    g_assert_cmpint(status, ==, 0);
    188
    189    data = g_malloc0(512);
    190    memread(req_addr + 16, data, 512);
    191    g_assert_cmpstr(data, ==, "TEST");
    192    g_free(data);
    193
    194    guest_free(alloc, req_addr);
    195
    196    if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
    197        struct virtio_blk_discard_write_zeroes dwz_hdr;
    198        void *expected;
    199
    200        /*
    201         * WRITE_ZEROES request on the same sector of previous test where
    202         * we wrote "TEST".
    203         */
    204        req.type = VIRTIO_BLK_T_WRITE_ZEROES;
    205        req.data = (char *) &dwz_hdr;
    206        dwz_hdr.sector = 0;
    207        dwz_hdr.num_sectors = 1;
    208        dwz_hdr.flags = 0;
    209
    210        virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
    211
    212        req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
    213
    214        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    215        qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
    216        qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
    217                       false);
    218
    219        qvirtqueue_kick(qts, dev, vq, free_head);
    220
    221        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    222                               QVIRTIO_BLK_TIMEOUT_US);
    223        status = readb(req_addr + 16 + sizeof(dwz_hdr));
    224        g_assert_cmpint(status, ==, 0);
    225
    226        guest_free(alloc, req_addr);
    227
    228        /* Read request to check if the sector contains all zeroes */
    229        req.type = VIRTIO_BLK_T_IN;
    230        req.ioprio = 1;
    231        req.sector = 0;
    232        req.data = g_malloc0(512);
    233
    234        req_addr = virtio_blk_request(alloc, dev, &req, 512);
    235
    236        g_free(req.data);
    237
    238        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    239        qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
    240        qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    241
    242        qvirtqueue_kick(qts, dev, vq, free_head);
    243
    244        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    245                               QVIRTIO_BLK_TIMEOUT_US);
    246        status = readb(req_addr + 528);
    247        g_assert_cmpint(status, ==, 0);
    248
    249        data = g_malloc(512);
    250        expected = g_malloc0(512);
    251        memread(req_addr + 16, data, 512);
    252        g_assert_cmpmem(data, 512, expected, 512);
    253        g_free(expected);
    254        g_free(data);
    255
    256        guest_free(alloc, req_addr);
    257    }
    258
    259    if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
    260        struct virtio_blk_discard_write_zeroes dwz_hdr;
    261
    262        req.type = VIRTIO_BLK_T_DISCARD;
    263        req.data = (char *) &dwz_hdr;
    264        dwz_hdr.sector = 0;
    265        dwz_hdr.num_sectors = 1;
    266        dwz_hdr.flags = 0;
    267
    268        virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
    269
    270        req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
    271
    272        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    273        qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
    274        qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
    275
    276        qvirtqueue_kick(qts, dev, vq, free_head);
    277
    278        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    279                               QVIRTIO_BLK_TIMEOUT_US);
    280        status = readb(req_addr + 16 + sizeof(dwz_hdr));
    281        g_assert_cmpint(status, ==, 0);
    282
    283        guest_free(alloc, req_addr);
    284    }
    285
    286    if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
    287        /* Write and read with 2 descriptor layout */
    288        /* Write request */
    289        req.type = VIRTIO_BLK_T_OUT;
    290        req.ioprio = 1;
    291        req.sector = 1;
    292        req.data = g_malloc0(512);
    293        strcpy(req.data, "TEST");
    294
    295        req_addr = virtio_blk_request(alloc, dev, &req, 512);
    296
    297        g_free(req.data);
    298
    299        free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
    300        qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    301        qvirtqueue_kick(qts, dev, vq, free_head);
    302
    303        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    304                               QVIRTIO_BLK_TIMEOUT_US);
    305        status = readb(req_addr + 528);
    306        g_assert_cmpint(status, ==, 0);
    307
    308        guest_free(alloc, req_addr);
    309
    310        /* Read request */
    311        req.type = VIRTIO_BLK_T_IN;
    312        req.ioprio = 1;
    313        req.sector = 1;
    314        req.data = g_malloc0(512);
    315
    316        req_addr = virtio_blk_request(alloc, dev, &req, 512);
    317
    318        g_free(req.data);
    319
    320        free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    321        qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
    322
    323        qvirtqueue_kick(qts, dev, vq, free_head);
    324
    325        qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    326                               QVIRTIO_BLK_TIMEOUT_US);
    327        status = readb(req_addr + 528);
    328        g_assert_cmpint(status, ==, 0);
    329
    330        data = g_malloc0(512);
    331        memread(req_addr + 16, data, 512);
    332        g_assert_cmpstr(data, ==, "TEST");
    333        g_free(data);
    334
    335        guest_free(alloc, req_addr);
    336    }
    337
    338    return vq;
    339}
    340
    341static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
    342{
    343    QVirtioBlk *blk_if = obj;
    344    QVirtQueue *vq;
    345
    346    vq = test_basic(blk_if->vdev, t_alloc);
    347    qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
    348
    349}
    350
    351static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
    352{
    353    QVirtQueue *vq;
    354    QVirtioBlk *blk_if = obj;
    355    QVirtioDevice *dev = blk_if->vdev;
    356    QVirtioBlkReq req;
    357    QVRingIndirectDesc *indirect;
    358    uint64_t req_addr;
    359    uint64_t capacity;
    360    uint64_t features;
    361    uint32_t free_head;
    362    uint8_t status;
    363    char *data;
    364    QTestState *qts = global_qtest;
    365
    366    features = qvirtio_get_features(dev);
    367    g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
    368    features = features & ~(QVIRTIO_F_BAD_FEATURE |
    369                            (1u << VIRTIO_RING_F_EVENT_IDX) |
    370                            (1u << VIRTIO_BLK_F_SCSI));
    371    qvirtio_set_features(dev, features);
    372
    373    capacity = qvirtio_config_readq(dev, 0);
    374    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
    375
    376    vq = qvirtqueue_setup(dev, t_alloc, 0);
    377    qvirtio_set_driver_ok(dev);
    378
    379    /* Write request */
    380    req.type = VIRTIO_BLK_T_OUT;
    381    req.ioprio = 1;
    382    req.sector = 0;
    383    req.data = g_malloc0(512);
    384    strcpy(req.data, "TEST");
    385
    386    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    387
    388    g_free(req.data);
    389
    390    indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
    391    qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
    392    qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
    393    free_head = qvirtqueue_add_indirect(qts, vq, indirect);
    394    qvirtqueue_kick(qts, dev, vq, free_head);
    395
    396    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    397                           QVIRTIO_BLK_TIMEOUT_US);
    398    status = readb(req_addr + 528);
    399    g_assert_cmpint(status, ==, 0);
    400
    401    g_free(indirect);
    402    guest_free(t_alloc, req_addr);
    403
    404    /* Read request */
    405    req.type = VIRTIO_BLK_T_IN;
    406    req.ioprio = 1;
    407    req.sector = 0;
    408    req.data = g_malloc0(512);
    409    strcpy(req.data, "TEST");
    410
    411    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    412
    413    g_free(req.data);
    414
    415    indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
    416    qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
    417    qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
    418    free_head = qvirtqueue_add_indirect(qts, vq, indirect);
    419    qvirtqueue_kick(qts, dev, vq, free_head);
    420
    421    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    422                           QVIRTIO_BLK_TIMEOUT_US);
    423    status = readb(req_addr + 528);
    424    g_assert_cmpint(status, ==, 0);
    425
    426    data = g_malloc0(512);
    427    memread(req_addr + 16, data, 512);
    428    g_assert_cmpstr(data, ==, "TEST");
    429    g_free(data);
    430
    431    g_free(indirect);
    432    guest_free(t_alloc, req_addr);
    433    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
    434}
    435
    436static void config(void *obj, void *data, QGuestAllocator *t_alloc)
    437{
    438    QVirtioBlk *blk_if = obj;
    439    QVirtioDevice *dev = blk_if->vdev;
    440    int n_size = TEST_IMAGE_SIZE / 2;
    441    uint64_t features;
    442    uint64_t capacity;
    443
    444    features = qvirtio_get_features(dev);
    445    features = features & ~(QVIRTIO_F_BAD_FEATURE |
    446                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    447                            (1u << VIRTIO_RING_F_EVENT_IDX) |
    448                            (1u << VIRTIO_BLK_F_SCSI));
    449    qvirtio_set_features(dev, features);
    450
    451    capacity = qvirtio_config_readq(dev, 0);
    452    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
    453
    454    qvirtio_set_driver_ok(dev);
    455
    456    qmp_discard_response("{ 'execute': 'block_resize', "
    457                         " 'arguments': { 'device': 'drive0', "
    458                         " 'size': %d } }", n_size);
    459    qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
    460
    461    capacity = qvirtio_config_readq(dev, 0);
    462    g_assert_cmpint(capacity, ==, n_size / 512);
    463}
    464
    465static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
    466{
    467    QVirtQueue *vq;
    468    QVirtioBlkPCI *blk = obj;
    469    QVirtioPCIDevice *pdev = &blk->pci_vdev;
    470    QVirtioDevice *dev = &pdev->vdev;
    471    QVirtioBlkReq req;
    472    int n_size = TEST_IMAGE_SIZE / 2;
    473    uint64_t req_addr;
    474    uint64_t capacity;
    475    uint64_t features;
    476    uint32_t free_head;
    477    uint8_t status;
    478    char *data;
    479    QOSGraphObject *blk_object = obj;
    480    QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
    481    QTestState *qts = global_qtest;
    482
    483    if (qpci_check_buggy_msi(pci_dev)) {
    484        return;
    485    }
    486
    487    qpci_msix_enable(pdev->pdev);
    488    qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
    489
    490    features = qvirtio_get_features(dev);
    491    features = features & ~(QVIRTIO_F_BAD_FEATURE |
    492                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    493                            (1u << VIRTIO_RING_F_EVENT_IDX) |
    494                            (1u << VIRTIO_BLK_F_SCSI));
    495    qvirtio_set_features(dev, features);
    496
    497    capacity = qvirtio_config_readq(dev, 0);
    498    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
    499
    500    vq = qvirtqueue_setup(dev, t_alloc, 0);
    501    qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
    502
    503    qvirtio_set_driver_ok(dev);
    504
    505    qmp_discard_response("{ 'execute': 'block_resize', "
    506                         " 'arguments': { 'device': 'drive0', "
    507                         " 'size': %d } }", n_size);
    508
    509    qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
    510
    511    capacity = qvirtio_config_readq(dev, 0);
    512    g_assert_cmpint(capacity, ==, n_size / 512);
    513
    514    /* Write request */
    515    req.type = VIRTIO_BLK_T_OUT;
    516    req.ioprio = 1;
    517    req.sector = 0;
    518    req.data = g_malloc0(512);
    519    strcpy(req.data, "TEST");
    520
    521    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    522
    523    g_free(req.data);
    524
    525    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    526    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
    527    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    528    qvirtqueue_kick(qts, dev, vq, free_head);
    529
    530    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    531                           QVIRTIO_BLK_TIMEOUT_US);
    532
    533    status = readb(req_addr + 528);
    534    g_assert_cmpint(status, ==, 0);
    535
    536    guest_free(t_alloc, req_addr);
    537
    538    /* Read request */
    539    req.type = VIRTIO_BLK_T_IN;
    540    req.ioprio = 1;
    541    req.sector = 0;
    542    req.data = g_malloc0(512);
    543
    544    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    545
    546    g_free(req.data);
    547
    548    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    549    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
    550    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    551
    552    qvirtqueue_kick(qts, dev, vq, free_head);
    553
    554
    555    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    556                           QVIRTIO_BLK_TIMEOUT_US);
    557
    558    status = readb(req_addr + 528);
    559    g_assert_cmpint(status, ==, 0);
    560
    561    data = g_malloc0(512);
    562    memread(req_addr + 16, data, 512);
    563    g_assert_cmpstr(data, ==, "TEST");
    564    g_free(data);
    565
    566    guest_free(t_alloc, req_addr);
    567
    568    /* End test */
    569    qpci_msix_disable(pdev->pdev);
    570    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
    571}
    572
    573static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
    574{
    575    QVirtQueue *vq;
    576    QVirtioBlkPCI *blk = obj;
    577    QVirtioPCIDevice *pdev = &blk->pci_vdev;
    578    QVirtioDevice *dev = &pdev->vdev;
    579    QVirtioBlkReq req;
    580    uint64_t req_addr;
    581    uint64_t capacity;
    582    uint64_t features;
    583    uint32_t free_head;
    584    uint32_t write_head;
    585    uint32_t desc_idx;
    586    uint8_t status;
    587    char *data;
    588    QOSGraphObject *blk_object = obj;
    589    QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
    590    QTestState *qts = global_qtest;
    591
    592    if (qpci_check_buggy_msi(pci_dev)) {
    593        return;
    594    }
    595
    596    qpci_msix_enable(pdev->pdev);
    597    qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
    598
    599    features = qvirtio_get_features(dev);
    600    features = features & ~(QVIRTIO_F_BAD_FEATURE |
    601                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    602                            (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
    603                            (1u << VIRTIO_BLK_F_SCSI));
    604    qvirtio_set_features(dev, features);
    605
    606    capacity = qvirtio_config_readq(dev, 0);
    607    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
    608
    609    vq = qvirtqueue_setup(dev, t_alloc, 0);
    610    qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
    611
    612    qvirtio_set_driver_ok(dev);
    613
    614    /* Write request */
    615    req.type = VIRTIO_BLK_T_OUT;
    616    req.ioprio = 1;
    617    req.sector = 0;
    618    req.data = g_malloc0(512);
    619    strcpy(req.data, "TEST");
    620
    621    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    622
    623    g_free(req.data);
    624
    625    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    626    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
    627    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    628    qvirtqueue_kick(qts, dev, vq, free_head);
    629
    630    qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    631                           QVIRTIO_BLK_TIMEOUT_US);
    632
    633    /* Write request */
    634    req.type = VIRTIO_BLK_T_OUT;
    635    req.ioprio = 1;
    636    req.sector = 1;
    637    req.data = g_malloc0(512);
    638    strcpy(req.data, "TEST");
    639
    640    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    641
    642    g_free(req.data);
    643
    644    /* Notify after processing the third request */
    645    qvirtqueue_set_used_event(qts, vq, 2);
    646    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    647    qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
    648    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    649    qvirtqueue_kick(qts, dev, vq, free_head);
    650    write_head = free_head;
    651
    652    /* No notification expected */
    653    status = qvirtio_wait_status_byte_no_isr(qts, dev,
    654                                             vq, req_addr + 528,
    655                                             QVIRTIO_BLK_TIMEOUT_US);
    656    g_assert_cmpint(status, ==, 0);
    657
    658    guest_free(t_alloc, req_addr);
    659
    660    /* Read request */
    661    req.type = VIRTIO_BLK_T_IN;
    662    req.ioprio = 1;
    663    req.sector = 1;
    664    req.data = g_malloc0(512);
    665
    666    req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    667
    668    g_free(req.data);
    669
    670    free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    671    qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
    672    qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    673
    674    qvirtqueue_kick(qts, dev, vq, free_head);
    675
    676    /* We get just one notification for both requests */
    677    qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
    678                           QVIRTIO_BLK_TIMEOUT_US);
    679    g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
    680    g_assert_cmpint(desc_idx, ==, free_head);
    681
    682    status = readb(req_addr + 528);
    683    g_assert_cmpint(status, ==, 0);
    684
    685    data = g_malloc0(512);
    686    memread(req_addr + 16, data, 512);
    687    g_assert_cmpstr(data, ==, "TEST");
    688    g_free(data);
    689
    690    guest_free(t_alloc, req_addr);
    691
    692    /* End test */
    693    qpci_msix_disable(pdev->pdev);
    694
    695    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
    696}
    697
    698static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
    699{
    700    QVirtioPCIDevice *dev1 = obj;
    701    QVirtioPCIDevice *dev;
    702    QTestState *qts = dev1->pdev->bus->qts;
    703
    704    /* plug secondary disk */
    705    qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1",
    706                         "{'addr': %s, 'drive': 'drive1'}",
    707                         stringify(PCI_SLOT_HP) ".0");
    708
    709    dev = virtio_pci_new(dev1->pdev->bus,
    710                         &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) });
    711    g_assert_nonnull(dev);
    712    g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
    713    qvirtio_pci_device_disable(dev);
    714    qos_object_destroy((QOSGraphObject *)dev);
    715
    716    /* unplug secondary disk */
    717    qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
    718}
    719
    720/*
    721 * Check that setting the vring addr on a non-existent virtqueue does
    722 * not crash.
    723 */
    724static void test_nonexistent_virtqueue(void *obj, void *data,
    725                                       QGuestAllocator *t_alloc)
    726{
    727    QVirtioBlkPCI *blk = obj;
    728    QVirtioPCIDevice *pdev = &blk->pci_vdev;
    729    QPCIBar bar0;
    730    QPCIDevice *dev;
    731
    732    dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
    733    g_assert(dev != NULL);
    734    qpci_device_enable(dev);
    735
    736    bar0 = qpci_iomap(dev, 0, NULL);
    737
    738    qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
    739    qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
    740
    741
    742    g_free(dev);
    743}
    744
    745static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
    746{
    747    QVirtioBlk *blk_if = obj;
    748    QVirtioDevice *dev = blk_if->vdev;
    749    int n_size = TEST_IMAGE_SIZE / 2;
    750    uint64_t capacity;
    751    QVirtQueue *vq;
    752    QTestState *qts = global_qtest;
    753
    754    vq = test_basic(dev, t_alloc);
    755
    756    qmp_discard_response("{ 'execute': 'block_resize', "
    757                         " 'arguments': { 'device': 'drive0', "
    758                         " 'size': %d } }", n_size);
    759
    760    qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
    761
    762    capacity = qvirtio_config_readq(dev, 0);
    763    g_assert_cmpint(capacity, ==, n_size / 512);
    764
    765    qvirtqueue_cleanup(dev->bus, vq, t_alloc);
    766
    767}
    768
    769static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
    770{
    771    char *tmp_path = drive_create();
    772
    773    g_string_append_printf(cmd_line,
    774                           " -drive if=none,id=drive0,file=%s,"
    775                           "format=raw,auto-read-only=off "
    776                           "-drive if=none,id=drive1,file=null-co://,"
    777                           "file.read-zeroes=on,format=raw ",
    778                           tmp_path);
    779
    780    return arg;
    781}
    782
    783static void register_virtio_blk_test(void)
    784{
    785    QOSGraphTestOptions opts = {
    786        .before = virtio_blk_test_setup,
    787    };
    788
    789    qos_add_test("indirect", "virtio-blk", indirect, &opts);
    790    qos_add_test("config", "virtio-blk", config, &opts);
    791    qos_add_test("basic", "virtio-blk", basic, &opts);
    792    qos_add_test("resize", "virtio-blk", resize, &opts);
    793
    794    /* tests just for virtio-blk-pci */
    795    qos_add_test("msix", "virtio-blk-pci", msix, &opts);
    796    qos_add_test("idx", "virtio-blk-pci", idx, &opts);
    797    qos_add_test("nxvirtq", "virtio-blk-pci",
    798                      test_nonexistent_virtqueue, &opts);
    799    qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug, &opts);
    800}
    801
    802libqos_init(register_virtio_blk_test);