aboutsummaryrefslogtreecommitdiff
path: root/tests/libqos/virtio.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/libqos/virtio.c')
-rw-r--r--tests/libqos/virtio.c131
1 files changed, 97 insertions, 34 deletions
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index fa597c2481..9aa360620c 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -8,11 +8,68 @@
*/
#include "qemu/osdep.h"
+#include "qemu/bswap.h"
#include "libqtest.h"
#include "libqos/virtio.h"
#include "standard-headers/linux/virtio_config.h"
#include "standard-headers/linux/virtio_ring.h"
+/*
+ * qtest_readX/writeX() functions transfer host endian from/to guest endian.
+ * This works great for Legacy VIRTIO devices where we need guest endian
+ * accesses. For VIRTIO 1.0 the vring is little-endian so the automatic guest
+ * endianness conversion is not wanted.
+ *
+ * The following qvirtio_readX/writeX() functions handle Legacy and VIRTIO 1.0
+ * accesses seamlessly.
+ */
+static uint16_t qvirtio_readw(QVirtioDevice *d, QTestState *qts, uint64_t addr)
+{
+ uint16_t val = qtest_readw(qts, addr);
+
+ if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
+ val = bswap16(val);
+ }
+ return val;
+}
+
+static uint32_t qvirtio_readl(QVirtioDevice *d, QTestState *qts, uint64_t addr)
+{
+ uint32_t val = qtest_readl(qts, addr);
+
+ if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
+ val = bswap32(val);
+ }
+ return val;
+}
+
+static void qvirtio_writew(QVirtioDevice *d, QTestState *qts,
+ uint64_t addr, uint16_t val)
+{
+ if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
+ val = bswap16(val);
+ }
+ qtest_writew(qts, addr, val);
+}
+
+static void qvirtio_writel(QVirtioDevice *d, QTestState *qts,
+ uint64_t addr, uint32_t val)
+{
+ if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
+ val = bswap32(val);
+ }
+ qtest_writel(qts, addr, val);
+}
+
+static void qvirtio_writeq(QVirtioDevice *d, QTestState *qts,
+ uint64_t addr, uint64_t val)
+{
+ if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
+ val = bswap64(val);
+ }
+ qtest_writeq(qts, addr, val);
+}
+
uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr)
{
g_assert_true(d->features_negotiated);
@@ -189,23 +246,23 @@ void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq,
for (i = 0; i < vq->size - 1; i++) {
/* vq->desc[i].addr */
- qtest_writeq(qts, vq->desc + (16 * i), 0);
+ qvirtio_writeq(vq->vdev, qts, vq->desc + (16 * i), 0);
/* vq->desc[i].next */
- qtest_writew(qts, vq->desc + (16 * i) + 14, i + 1);
+ qvirtio_writew(vq->vdev, qts, vq->desc + (16 * i) + 14, i + 1);
}
/* vq->avail->flags */
- qtest_writew(qts, vq->avail, 0);
+ qvirtio_writew(vq->vdev, qts, vq->avail, 0);
/* vq->avail->idx */
- qtest_writew(qts, vq->avail + 2, 0);
+ qvirtio_writew(vq->vdev, qts, vq->avail + 2, 0);
/* vq->avail->used_event */
- qtest_writew(qts, vq->avail + 4 + (2 * vq->size), 0);
+ qvirtio_writew(vq->vdev, qts, vq->avail + 4 + (2 * vq->size), 0);
/* vq->used->flags */
- qtest_writew(qts, vq->used, 0);
+ qvirtio_writew(vq->vdev, qts, vq->used, 0);
/* vq->used->avail_event */
- qtest_writew(qts, vq->used + 2 + sizeof(struct vring_used_elem) * vq->size,
- 0);
+ qvirtio_writew(vq->vdev, qts, vq->used + 2 +
+ sizeof(struct vring_used_elem) * vq->size, 0);
}
QVRingIndirectDesc *qvring_indirect_desc_setup(QTestState *qs, QVirtioDevice *d,
@@ -221,35 +278,39 @@ QVRingIndirectDesc *qvring_indirect_desc_setup(QTestState *qs, QVirtioDevice *d,
for (i = 0; i < elem - 1; ++i) {
/* indirect->desc[i].addr */
- qtest_writeq(qs, indirect->desc + (16 * i), 0);
+ qvirtio_writeq(d, qs, indirect->desc + (16 * i), 0);
/* indirect->desc[i].flags */
- qtest_writew(qs, indirect->desc + (16 * i) + 12, VRING_DESC_F_NEXT);
+ qvirtio_writew(d, qs, indirect->desc + (16 * i) + 12,
+ VRING_DESC_F_NEXT);
/* indirect->desc[i].next */
- qtest_writew(qs, indirect->desc + (16 * i) + 14, i + 1);
+ qvirtio_writew(d, qs, indirect->desc + (16 * i) + 14, i + 1);
}
return indirect;
}
-void qvring_indirect_desc_add(QTestState *qts, QVRingIndirectDesc *indirect,
+void qvring_indirect_desc_add(QVirtioDevice *d, QTestState *qts,
+ QVRingIndirectDesc *indirect,
uint64_t data, uint32_t len, bool write)
{
uint16_t flags;
g_assert_cmpint(indirect->index, <, indirect->elem);
- flags = qtest_readw(qts, indirect->desc + (16 * indirect->index) + 12);
+ flags = qvirtio_readw(d, qts, indirect->desc +
+ (16 * indirect->index) + 12);
if (write) {
flags |= VRING_DESC_F_WRITE;
}
/* indirect->desc[indirect->index].addr */
- qtest_writeq(qts, indirect->desc + (16 * indirect->index), data);
+ qvirtio_writeq(d, qts, indirect->desc + (16 * indirect->index), data);
/* indirect->desc[indirect->index].len */
- qtest_writel(qts, indirect->desc + (16 * indirect->index) + 8, len);
+ qvirtio_writel(d, qts, indirect->desc + (16 * indirect->index) + 8, len);
/* indirect->desc[indirect->index].flags */
- qtest_writew(qts, indirect->desc + (16 * indirect->index) + 12, flags);
+ qvirtio_writew(d, qts, indirect->desc + (16 * indirect->index) + 12,
+ flags);
indirect->index++;
}
@@ -269,11 +330,11 @@ uint32_t qvirtqueue_add(QTestState *qts, QVirtQueue *vq, uint64_t data,
}
/* vq->desc[vq->free_head].addr */
- qtest_writeq(qts, vq->desc + (16 * vq->free_head), data);
+ qvirtio_writeq(vq->vdev, qts, vq->desc + (16 * vq->free_head), data);
/* vq->desc[vq->free_head].len */
- qtest_writel(qts, vq->desc + (16 * vq->free_head) + 8, len);
+ qvirtio_writel(vq->vdev, qts, vq->desc + (16 * vq->free_head) + 8, len);
/* vq->desc[vq->free_head].flags */
- qtest_writew(qts, vq->desc + (16 * vq->free_head) + 12, flags);
+ qvirtio_writew(vq->vdev, qts, vq->desc + (16 * vq->free_head) + 12, flags);
return vq->free_head++; /* Return and increase, in this order */
}
@@ -288,13 +349,14 @@ uint32_t qvirtqueue_add_indirect(QTestState *qts, QVirtQueue *vq,
vq->num_free--;
/* vq->desc[vq->free_head].addr */
- qtest_writeq(qts, vq->desc + (16 * vq->free_head), indirect->desc);
+ qvirtio_writeq(vq->vdev, qts, vq->desc + (16 * vq->free_head),
+ indirect->desc);
/* vq->desc[vq->free_head].len */
- qtest_writel(qts, vq->desc + (16 * vq->free_head) + 8,
- sizeof(struct vring_desc) * indirect->elem);
+ qvirtio_writel(vq->vdev, qts, vq->desc + (16 * vq->free_head) + 8,
+ sizeof(struct vring_desc) * indirect->elem);
/* vq->desc[vq->free_head].flags */
- qtest_writew(qts, vq->desc + (16 * vq->free_head) + 12,
- VRING_DESC_F_INDIRECT);
+ qvirtio_writew(vq->vdev, qts, vq->desc + (16 * vq->free_head) + 12,
+ VRING_DESC_F_INDIRECT);
return vq->free_head++; /* Return and increase, in this order */
}
@@ -303,21 +365,21 @@ void qvirtqueue_kick(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq,
uint32_t free_head)
{
/* vq->avail->idx */
- uint16_t idx = qtest_readw(qts, vq->avail + 2);
+ uint16_t idx = qvirtio_readw(d, qts, vq->avail + 2);
/* vq->used->flags */
uint16_t flags;
/* vq->used->avail_event */
uint16_t avail_event;
/* vq->avail->ring[idx % vq->size] */
- qtest_writew(qts, vq->avail + 4 + (2 * (idx % vq->size)), free_head);
+ qvirtio_writew(d, qts, vq->avail + 4 + (2 * (idx % vq->size)), free_head);
/* vq->avail->idx */
- qtest_writew(qts, vq->avail + 2, idx + 1);
+ qvirtio_writew(d, qts, vq->avail + 2, idx + 1);
/* Must read after idx is updated */
- flags = qtest_readw(qts, vq->avail);
- avail_event = qtest_readw(qts, vq->used + 4 +
- sizeof(struct vring_used_elem) * vq->size);
+ flags = qvirtio_readw(d, qts, vq->avail);
+ avail_event = qvirtio_readw(d, qts, vq->used + 4 +
+ sizeof(struct vring_used_elem) * vq->size);
/* < 1 because we add elements to avail queue one by one */
if ((flags & VRING_USED_F_NO_NOTIFY) == 0 &&
@@ -342,7 +404,8 @@ bool qvirtqueue_get_buf(QTestState *qts, QVirtQueue *vq, uint32_t *desc_idx,
uint16_t idx;
uint64_t elem_addr, addr;
- idx = qtest_readw(qts, vq->used + offsetof(struct vring_used, idx));
+ idx = qvirtio_readw(vq->vdev, qts,
+ vq->used + offsetof(struct vring_used, idx));
if (idx == vq->last_used_idx) {
return false;
}
@@ -354,12 +417,12 @@ bool qvirtqueue_get_buf(QTestState *qts, QVirtQueue *vq, uint32_t *desc_idx,
if (desc_idx) {
addr = elem_addr + offsetof(struct vring_used_elem, id);
- *desc_idx = qtest_readl(qts, addr);
+ *desc_idx = qvirtio_readl(vq->vdev, qts, addr);
}
if (len) {
addr = elem_addr + offsetof(struct vring_used_elem, len);
- *len = qtest_readw(qts, addr);
+ *len = qvirtio_readw(vq->vdev, qts, addr);
}
vq->last_used_idx++;
@@ -371,7 +434,7 @@ void qvirtqueue_set_used_event(QTestState *qts, QVirtQueue *vq, uint16_t idx)
g_assert(vq->event);
/* vq->avail->used_event */
- qtest_writew(qts, vq->avail + 4 + (2 * vq->size), idx);
+ qvirtio_writew(vq->vdev, qts, vq->avail + 4 + (2 * vq->size), idx);
}
void qvirtio_start_device(QVirtioDevice *vdev)