Add functions to read and write virtio header fields. Add status bit setting in virtio-blk-device.
Signed-off-by: Marc Marí <marc.mari.barc...@gmail.com> --- tests/Makefile | 2 +- tests/libqos/virtio-pci.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/virtio-pci.h | 18 ++++++++++++++ tests/libqos/virtio.c | 55 +++++++++++++++++++++++++++++++++++++++++++ tests/libqos/virtio.h | 30 ++++++++++++++++++++++++ tests/virtio-blk-test.c | 14 +++++++++++ 6 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 tests/libqos/virtio.c diff --git a/tests/Makefile b/tests/Makefile index 7c0f670..e0e203f 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -294,7 +294,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 fde1b1f..f3ab578 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -55,6 +55,51 @@ 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; + return qpci_io_readl(dev->pdev, addr) | qpci_io_readl(dev->pdev, addr+4); +} + +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 val) +{ + QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d; + qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_DEVICE_STATUS, val); +} + +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 +118,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); + 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 5101abb..26f902e 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 0000000..577d679 --- /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 <glib.h> +#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 2a05798..23e975b 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 val); +} 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/virtio-blk-test.c b/tests/virtio-blk-test.c index 4d87a3e..a534521 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -53,6 +53,8 @@ static void pci_basic(void) { QVirtioPCIDevice *dev; QPCIBus *bus; + void *addr; + uint64_t capacity; bus = test_start(); @@ -61,6 +63,18 @@ static void pci_basic(void) 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); + + /* 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(); } -- 1.7.10.4