From 46e0cf762985e0a85529efd454402998c5021212 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marc=20Mar=C3=AD?= Date: Mon, 1 Sep 2014 12:07:55 +0200 Subject: [PATCH] tests: Add virtio device initialization MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add functions to read and write virtio header fields. Add status bit setting in virtio-blk-device. Signed-off-by: Marc Marí Signed-off-by: Stefan Hajnoczi --- tests/Makefile | 2 +- tests/libqos/virtio-pci.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/virtio-pci.h | 18 ++++++++++++ tests/libqos/virtio.c | 55 ++++++++++++++++++++++++++++++++++++ tests/libqos/virtio.h | 30 ++++++++++++++++++++ tests/libqtest.c | 48 ++++++++++++++++++++++++++++++++ tests/libqtest.h | 7 +++++ tests/virtio-blk-test.c | 31 ++++++++++++++++++--- 8 files changed, 257 insertions(+), 5 deletions(-) create mode 100644 tests/libqos/virtio.c diff --git a/tests/Makefile b/tests/Makefile index 0572633774..d5db97ba63 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -299,7 +299,7 @@ libqos-obj-y += tests/libqos/i2c.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o -libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio-pci.o +libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index fde1b1f747..1a37620001 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -8,6 +8,7 @@ */ #include +#include #include "libqtest.h" #include "libqos/virtio.h" #include "libqos/virtio-pci.h" @@ -55,6 +56,64 @@ static void qvirtio_pci_assign_device(QVirtioDevice *d, void *data) *vpcidev = (QVirtioPCIDevice *)d; } +static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, void *addr) +{ + QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; + return qpci_io_readb(dev->pdev, addr); +} + +static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, void *addr) +{ + QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; + return qpci_io_readw(dev->pdev, addr); +} + +static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, void *addr) +{ + QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; + return qpci_io_readl(dev->pdev, addr); +} + +static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, void *addr) +{ + QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; + int i; + uint64_t u64 = 0; + + if (qtest_big_endian()) { + for (i = 0; i < 8; ++i) { + u64 |= (uint64_t)qpci_io_readb(dev->pdev, addr + i) << (7 - i) * 8; + } + } else { + for (i = 0; i < 8; ++i) { + u64 |= (uint64_t)qpci_io_readb(dev->pdev, addr + i) << i * 8; + } + } + + return u64; +} + +static uint8_t qvirtio_pci_get_status(QVirtioDevice *d) +{ + QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; + return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_DEVICE_STATUS); +} + +static void qvirtio_pci_set_status(QVirtioDevice *d, uint8_t status) +{ + QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; + qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_DEVICE_STATUS, status); +} + +const QVirtioBus qvirtio_pci = { + .config_readb = qvirtio_pci_config_readb, + .config_readw = qvirtio_pci_config_readw, + .config_readl = qvirtio_pci_config_readl, + .config_readq = qvirtio_pci_config_readq, + .get_status = qvirtio_pci_get_status, + .set_status = qvirtio_pci_set_status, +}; + void qvirtio_pci_foreach(QPCIBus *bus, uint16_t device_type, void (*func)(QVirtioDevice *d, void *data), void *data) { @@ -73,3 +132,15 @@ QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type) return dev; } + +void qvirtio_pci_device_enable(QVirtioPCIDevice *d) +{ + qpci_device_enable(d->pdev); + d->addr = qpci_iomap(d->pdev, 0, NULL); + g_assert(d->addr != NULL); +} + +void qvirtio_pci_device_disable(QVirtioPCIDevice *d) +{ + qpci_iounmap(d->pdev, d->addr); +} diff --git a/tests/libqos/virtio-pci.h b/tests/libqos/virtio-pci.h index 5101abb0ec..26f902ecb6 100644 --- a/tests/libqos/virtio-pci.h +++ b/tests/libqos/virtio-pci.h @@ -13,12 +13,30 @@ #include "libqos/virtio.h" #include "libqos/pci.h" +#define QVIRTIO_DEVICE_FEATURES 0x00 +#define QVIRTIO_GUEST_FEATURES 0x04 +#define QVIRTIO_QUEUE_ADDRESS 0x08 +#define QVIRTIO_QUEUE_SIZE 0x0C +#define QVIRTIO_QUEUE_SELECT 0x0E +#define QVIRTIO_QUEUE_NOTIFY 0x10 +#define QVIRTIO_DEVICE_STATUS 0x12 +#define QVIRTIO_ISR_STATUS 0x13 +#define QVIRTIO_MSIX_CONF_VECTOR 0x14 +#define QVIRTIO_MSIX_QUEUE_VECTOR 0x16 +#define QVIRTIO_DEVICE_SPECIFIC_MSIX 0x18 +#define QVIRTIO_DEVICE_SPECIFIC_NO_MSIX 0x14 + typedef struct QVirtioPCIDevice { QVirtioDevice vdev; QPCIDevice *pdev; + void *addr; } QVirtioPCIDevice; +extern const QVirtioBus qvirtio_pci; + void qvirtio_pci_foreach(QPCIBus *bus, uint16_t device_type, void (*func)(QVirtioDevice *d, void *data), void *data); QVirtioPCIDevice *qvirtio_pci_device_find(QPCIBus *bus, uint16_t device_type); +void qvirtio_pci_device_enable(QVirtioPCIDevice *d); +void qvirtio_pci_device_disable(QVirtioPCIDevice *d); #endif diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c new file mode 100644 index 0000000000..577d679136 --- /dev/null +++ b/tests/libqos/virtio.c @@ -0,0 +1,55 @@ +/* + * libqos virtio driver + * + * Copyright (c) 2014 Marc Marí + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include "libqtest.h" +#include "libqos/virtio.h" + +uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d, + void *addr) +{ + return bus->config_readb(d, addr); +} + +uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d, + void *addr) +{ + return bus->config_readw(d, addr); +} + +uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d, + void *addr) +{ + return bus->config_readl(d, addr); +} + +uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d, + void *addr) +{ + return bus->config_readq(d, addr); +} + +void qvirtio_reset(const QVirtioBus *bus, QVirtioDevice *d) +{ + bus->set_status(d, QVIRTIO_RESET); + g_assert_cmphex(bus->get_status(d), ==, QVIRTIO_RESET); +} + +void qvirtio_set_acknowledge(const QVirtioBus *bus, QVirtioDevice *d) +{ + bus->set_status(d, bus->get_status(d) | QVIRTIO_ACKNOWLEDGE); + g_assert_cmphex(bus->get_status(d), ==, QVIRTIO_ACKNOWLEDGE); +} + +void qvirtio_set_driver(const QVirtioBus *bus, QVirtioDevice *d) +{ + bus->set_status(d, bus->get_status(d) | QVIRTIO_DRIVER); + g_assert_cmphex(bus->get_status(d), ==, + QVIRTIO_DRIVER | QVIRTIO_ACKNOWLEDGE); +} diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 2a05798ca7..8d7238bd91 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -12,6 +12,10 @@ #define QVIRTIO_VENDOR_ID 0x1AF4 +#define QVIRTIO_RESET 0x0 +#define QVIRTIO_ACKNOWLEDGE 0x1 +#define QVIRTIO_DRIVER 0x2 + #define QVIRTIO_NET_DEVICE_ID 0x1 #define QVIRTIO_BLK_DEVICE_ID 0x2 @@ -20,4 +24,30 @@ typedef struct QVirtioDevice { uint16_t device_type; } QVirtioDevice; +typedef struct QVirtioBus { + uint8_t (*config_readb)(QVirtioDevice *d, void *addr); + uint16_t (*config_readw)(QVirtioDevice *d, void *addr); + uint32_t (*config_readl)(QVirtioDevice *d, void *addr); + uint64_t (*config_readq)(QVirtioDevice *d, void *addr); + + /* Get status of the device */ + uint8_t (*get_status)(QVirtioDevice *d); + + /* Set status of the device */ + void (*set_status)(QVirtioDevice *d, uint8_t status); +} QVirtioBus; + +uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d, + void *addr); +uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d, + void *addr); +uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d, + void *addr); +uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d, + void *addr); + +void qvirtio_reset(const QVirtioBus *bus, QVirtioDevice *d); +void qvirtio_set_acknowledge(const QVirtioBus *bus, QVirtioDevice *d); +void qvirtio_set_driver(const QVirtioBus *bus, QVirtioDevice *d); + #endif diff --git a/tests/libqtest.c b/tests/libqtest.c index 5e458e884e..9a92aa70e4 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -696,3 +696,51 @@ void qmp_discard_response(const char *fmt, ...) qtest_qmpv_discard_response(global_qtest, fmt, ap); va_end(ap); } + +bool qtest_big_endian(void) +{ + const char *arch = qtest_get_arch(); + int i; + + static const struct { + const char *arch; + bool big_endian; + } endianness[] = { + { "aarch64", false }, + { "alpha", false }, + { "arm", false }, + { "cris", false }, + { "i386", false }, + { "lm32", true }, + { "m68k", true }, + { "microblaze", true }, + { "microblazeel", false }, + { "mips", true }, + { "mips64", true }, + { "mips64el", false }, + { "mipsel", false }, + { "moxie", true }, + { "or32", true }, + { "ppc", true }, + { "ppc64", true }, + { "ppcemb", true }, + { "s390x", true }, + { "sh4", false }, + { "sh4eb", true }, + { "sparc", true }, + { "sparc64", true }, + { "unicore32", false }, + { "x86_64", false }, + { "xtensa", false }, + { "xtensaeb", true }, + {}, + }; + + for (i = 0; endianness[i].arch; i++) { + if (strcmp(endianness[i].arch, arch) == 0) { + return endianness[i].big_endian; + } + } + + return false; +} diff --git a/tests/libqtest.h b/tests/libqtest.h index 1be0934f07..3e12cab2f2 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -682,4 +682,11 @@ static inline int64_t clock_set(int64_t val) return qtest_clock_set(global_qtest, val); } +/** + * qtest_big_endian: + * + * Returns: True if the architecture under test has a big endian configuration. + */ +bool qtest_big_endian(void); + #endif diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 4d87a3e538..649f7cf94f 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -49,18 +49,41 @@ static void test_end(void) qtest_end(); } -static void pci_basic(void) +static QVirtioPCIDevice *virtio_blk_init(QPCIBus *bus) { QVirtioPCIDevice *dev; - QPCIBus *bus; - - bus = test_start(); dev = qvirtio_pci_device_find(bus, QVIRTIO_BLK_DEVICE_ID); g_assert(dev != NULL); g_assert_cmphex(dev->vdev.device_type, ==, QVIRTIO_BLK_DEVICE_ID); g_assert_cmphex(dev->pdev->devfn, ==, ((PCI_SLOT << 3) | PCI_FN)); + qvirtio_pci_device_enable(dev); + qvirtio_reset(&qvirtio_pci, &dev->vdev); + qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev); + qvirtio_set_driver(&qvirtio_pci, &dev->vdev); + + return dev; +} + +static void pci_basic(void) +{ + QVirtioPCIDevice *dev; + QPCIBus *bus; + void *addr; + uint64_t capacity; + + bus = test_start(); + + dev = virtio_blk_init(bus); + + /* MSI-X is not enabled */ + addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX; + + capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr); + g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512); + + qvirtio_pci_device_disable(dev); g_free(dev); test_end(); } -- 2.11.0