From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45903) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XPw9Y-0003uO-NG for qemu-devel@nongnu.org; Fri, 05 Sep 2014 12:14:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XPw9S-0005ra-GK for qemu-devel@nongnu.org; Fri, 05 Sep 2014 12:14:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:24967) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XPw9S-0005rQ-9c for qemu-devel@nongnu.org; Fri, 05 Sep 2014 12:14:18 -0400 From: Stefan Hajnoczi Date: Fri, 5 Sep 2014 17:13:35 +0100 Message-Id: <1409933634-11331-8-git-send-email-stefanha@redhat.com> In-Reply-To: <1409933634-11331-1-git-send-email-stefanha@redhat.com> References: <1409933634-11331-1-git-send-email-stefanha@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PULL 07/26] tests: Add virtio device initialization List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc=20Mar=C3=AD?= , Peter Maydell , Stefan Hajnoczi From: Marc Mar=C3=AD Add functions to read and write virtio header fields. Add status bit setting in virtio-blk-device. Signed-off-by: Marc Mar=C3=AD 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 0572633..d5db97b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -299,7 +299,7 @@ libqos-obj-y +=3D tests/libqos/i2c.o libqos-pc-obj-y =3D $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y +=3D tests/libqos/malloc-pc.o libqos-omap-obj-y =3D $(libqos-obj-y) tests/libqos/i2c-omap.o -libqos-virtio-obj-y =3D $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/= virtio-pci.o +libqos-virtio-obj-y =3D $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/= virtio.o tests/libqos/virtio-pci.o =20 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..1a37620 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -8,6 +8,7 @@ */ =20 #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 =3D (QVirtioPCIDevice *)d; } =20 +static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, void *addr) +{ + QVirtioPCIDevice *dev =3D (QVirtioPCIDevice *)d; + return qpci_io_readb(dev->pdev, addr); +} + +static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, void *addr) +{ + QVirtioPCIDevice *dev =3D (QVirtioPCIDevice *)d; + return qpci_io_readw(dev->pdev, addr); +} + +static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, void *addr) +{ + QVirtioPCIDevice *dev =3D (QVirtioPCIDevice *)d; + return qpci_io_readl(dev->pdev, addr); +} + +static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, void *addr) +{ + QVirtioPCIDevice *dev =3D (QVirtioPCIDevice *)d; + int i; + uint64_t u64 =3D 0; + + if (qtest_big_endian()) { + for (i =3D 0; i < 8; ++i) { + u64 |=3D (uint64_t)qpci_io_readb(dev->pdev, addr + i) << (7 = - i) * 8; + } + } else { + for (i =3D 0; i < 8; ++i) { + u64 |=3D (uint64_t)qpci_io_readb(dev->pdev, addr + i) << i *= 8; + } + } + + return u64; +} + +static uint8_t qvirtio_pci_get_status(QVirtioDevice *d) +{ + QVirtioPCIDevice *dev =3D (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 =3D (QVirtioPCIDevice *)d; + qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_DEVICE_STATUS, status)= ; +} + +const QVirtioBus qvirtio_pci =3D { + .config_readb =3D qvirtio_pci_config_readb, + .config_readw =3D qvirtio_pci_config_readw, + .config_readl =3D qvirtio_pci_config_readl, + .config_readq =3D qvirtio_pci_config_readq, + .get_status =3D qvirtio_pci_get_status, + .set_status =3D 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 *bu= s, uint16_t device_type) =20 return dev; } + +void qvirtio_pci_device_enable(QVirtioPCIDevice *d) +{ + qpci_device_enable(d->pdev); + d->addr =3D qpci_iomap(d->pdev, 0, NULL); + g_assert(d->addr !=3D 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" =20 +#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; =20 +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=C3=AD + * + * This work is licensed under the terms of the GNU GPL, version 2 or la= ter. + * 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 *ad= dr) +{ + return bus->config_readb(d, addr); +} + +uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d, + void *ad= dr) +{ + return bus->config_readw(d, addr); +} + +uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d, + void *ad= dr) +{ + return bus->config_readl(d, addr); +} + +uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d, + void *ad= dr) +{ + 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), =3D=3D, 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), =3D=3D, 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), =3D=3D, + QVIRTIO_DRIVER | QVIRTIO_ACKNOWLEDGE= ); +} diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 2a05798..8d7238b 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -12,6 +12,10 @@ =20 #define QVIRTIO_VENDOR_ID 0x1AF4 =20 +#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 @@ -20,4 +24,30 @@ typedef struct QVirtioDevice { uint16_t device_type; } QVirtioDevice; =20 +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 *ad= dr); +uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d, + void *ad= dr); +uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d, + void *ad= dr); +uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d, + void *ad= dr); + +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 5e458e8..9a92aa7 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 =3D qtest_get_arch(); + int i; + + static const struct { + const char *arch; + bool big_endian; + } endianness[] =3D { + { "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 =3D 0; endianness[i].arch; i++) { + if (strcmp(endianness[i].arch, arch) =3D=3D 0) { + return endianness[i].big_endian; + } + } + + return false; +} diff --git a/tests/libqtest.h b/tests/libqtest.h index 1be0934..3e12cab 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); } =20 +/** + * qtest_big_endian: + * + * Returns: True if the architecture under test has a big endian configu= ration. + */ +bool qtest_big_endian(void); + #endif diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 4d87a3e..649f7cf 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -49,18 +49,41 @@ static void test_end(void) qtest_end(); } =20 -static void pci_basic(void) +static QVirtioPCIDevice *virtio_blk_init(QPCIBus *bus) { QVirtioPCIDevice *dev; - QPCIBus *bus; - - bus =3D test_start(); =20 dev =3D qvirtio_pci_device_find(bus, QVIRTIO_BLK_DEVICE_ID); g_assert(dev !=3D NULL); g_assert_cmphex(dev->vdev.device_type, =3D=3D, QVIRTIO_BLK_DEVICE_ID= ); g_assert_cmphex(dev->pdev->devfn, =3D=3D, ((PCI_SLOT << 3) | PCI_FN)= ); =20 + 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 =3D test_start(); + + dev =3D virtio_blk_init(bus); + + /* MSI-X is not enabled */ + addr =3D dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX; + + capacity =3D qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr); + g_assert_cmpint(capacity, =3D=3D, TEST_IMAGE_SIZE / 512); + + qvirtio_pci_device_disable(dev); g_free(dev); test_end(); } --=20 1.9.3