mirror of https://github.com/xemu-project/xemu.git
tests: Add virtio device initialization
Add functions to read and write virtio header fields. Add status bit setting in virtio-blk-device. Signed-off-by: Marc Marí <marc.mari.barcelo@gmail.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
311e666aea
commit
46e0cf7629
|
@ -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
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue