提交 46e0cf76 编写于 作者: M Marc Marí 提交者: Stefan Hajnoczi

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: NMarc Marí <marc.mari.barcelo@gmail.com>
Signed-off-by: NStefan Hajnoczi <stefanha@redhat.com>
上级 311e666a
......@@ -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
/*
* 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();
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册