tests/qtest/libqos/virtio.c | 44 ++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 15 deletions(-)
From: Thomas Huth <thuth@redhat.com>
The logic in the qvirtio_read/write function is rather a headache,
involving byte-swapping when the target is big endian, just to
maybe involve another byte-swapping in the qtest_read/write
function immediately afterwards (on the QEMU side). Let's do it in
a more obvious way here: For virtio 1.0, we know that the values have
to be little endian, so let's read/write the bytes in that well known
order here.
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
This also decreases our usage of qtest_big_endian() which might (or
might not) get helpful for the universal binary one day...
v2: Use leXX_to_cpu() / cpu_to_leXX() instead of doing it manually
tests/qtest/libqos/virtio.c | 44 ++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 15 deletions(-)
diff --git a/tests/qtest/libqos/virtio.c b/tests/qtest/libqos/virtio.c
index 2e7979652fd..5a709d0bc59 100644
--- a/tests/qtest/libqos/virtio.c
+++ b/tests/qtest/libqos/virtio.c
@@ -25,49 +25,63 @@
*/
static uint16_t qvirtio_readw(QVirtioDevice *d, QTestState *qts, uint64_t addr)
{
- uint16_t val = qtest_readw(qts, addr);
+ uint16_t val;
- if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
- val = bswap16(val);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ qtest_memread(qts, addr, &val, sizeof(val));
+ val = le16_to_cpu(val);
+ } else {
+ val = qtest_readw(qts, addr);
}
+
return val;
}
static uint32_t qvirtio_readl(QVirtioDevice *d, QTestState *qts, uint64_t addr)
{
- uint32_t val = qtest_readl(qts, addr);
+ uint32_t val;
- if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
- val = bswap32(val);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ qtest_memread(qts, addr, &val, sizeof(val));
+ val = le32_to_cpu(val);
+ } else {
+ val = qtest_readl(qts, addr);
}
+
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);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ val = cpu_to_le16(val);
+ qtest_memwrite(qts, addr, &val, sizeof(val));
+ } else {
+ qtest_writew(qts, addr, 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);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ val = cpu_to_le32(val);
+ qtest_memwrite(qts, addr, &val, sizeof(val));
+ } else {
+ qtest_writel(qts, addr, 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);
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ val = cpu_to_le64(val);
+ qtest_memwrite(qts, addr, &val, sizeof(val));
+ } else {
+ qtest_writeq(qts, addr, val);
}
- qtest_writeq(qts, addr, val);
}
uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr)
--
2.49.0
Thomas Huth <thuth@redhat.com> writes:
> From: Thomas Huth <thuth@redhat.com>
>
> The logic in the qvirtio_read/write function is rather a headache,
> involving byte-swapping when the target is big endian, just to
> maybe involve another byte-swapping in the qtest_read/write
> function immediately afterwards (on the QEMU side). Let's do it in
> a more obvious way here: For virtio 1.0, we know that the values have
> to be little endian, so let's read/write the bytes in that well known
> order here.
>
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
> This also decreases our usage of qtest_big_endian() which might (or
> might not) get helpful for the universal binary one day...
>
> v2: Use leXX_to_cpu() / cpu_to_leXX() instead of doing it manually
>
> tests/qtest/libqos/virtio.c | 44 ++++++++++++++++++++++++-------------
> 1 file changed, 29 insertions(+), 15 deletions(-)
>
> diff --git a/tests/qtest/libqos/virtio.c b/tests/qtest/libqos/virtio.c
> index 2e7979652fd..5a709d0bc59 100644
> --- a/tests/qtest/libqos/virtio.c
> +++ b/tests/qtest/libqos/virtio.c
> @@ -25,49 +25,63 @@
> */
> static uint16_t qvirtio_readw(QVirtioDevice *d, QTestState *qts, uint64_t addr)
> {
> - uint16_t val = qtest_readw(qts, addr);
> + uint16_t val;
>
> - if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
> - val = bswap16(val);
> + if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
> + qtest_memread(qts, addr, &val, sizeof(val));
> + val = le16_to_cpu(val);
> + } else {
> + val = qtest_readw(qts, addr);
> }
> +
> return val;
> }
>
> static uint32_t qvirtio_readl(QVirtioDevice *d, QTestState *qts, uint64_t addr)
> {
> - uint32_t val = qtest_readl(qts, addr);
> + uint32_t val;
>
> - if (d->features & (1ull << VIRTIO_F_VERSION_1) && qtest_big_endian(qts)) {
> - val = bswap32(val);
> + if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
> + qtest_memread(qts, addr, &val, sizeof(val));
> + val = le32_to_cpu(val);
> + } else {
> + val = qtest_readl(qts, addr);
> }
> +
> 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);
> + if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
> + val = cpu_to_le16(val);
> + qtest_memwrite(qts, addr, &val, sizeof(val));
> + } else {
> + qtest_writew(qts, addr, 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);
> + if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
> + val = cpu_to_le32(val);
> + qtest_memwrite(qts, addr, &val, sizeof(val));
> + } else {
> + qtest_writel(qts, addr, 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);
> + if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
> + val = cpu_to_le64(val);
> + qtest_memwrite(qts, addr, &val, sizeof(val));
> + } else {
> + qtest_writeq(qts, addr, val);
> }
> - qtest_writeq(qts, addr, val);
> }
>
> uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr)
Queued to qtest-next, thanks!
Thomas Huth <thuth@redhat.com> writes: > From: Thomas Huth <thuth@redhat.com> > > The logic in the qvirtio_read/write function is rather a headache, > involving byte-swapping when the target is big endian, just to > maybe involve another byte-swapping in the qtest_read/write > function immediately afterwards (on the QEMU side). Let's do it in > a more obvious way here: For virtio 1.0, we know that the values have > to be little endian, so let's read/write the bytes in that well known > order here. > > Signed-off-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Alex Bennée <alex.bennee@linaro.org> -- Alex Bennée Virtualisation Tech Lead @ Linaro
On 30/4/25 15:28, Thomas Huth wrote:
> From: Thomas Huth <thuth@redhat.com>
>
> The logic in the qvirtio_read/write function is rather a headache,
> involving byte-swapping when the target is big endian, just to
> maybe involve another byte-swapping in the qtest_read/write
> function immediately afterwards (on the QEMU side). Let's do it in
> a more obvious way here: For virtio 1.0, we know that the values have
> to be little endian, so let's read/write the bytes in that well known
> order here.
>
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
> This also decreases our usage of qtest_big_endian() which might (or
> might not) get helpful for the universal binary one day...
>
> v2: Use leXX_to_cpu() / cpu_to_leXX() instead of doing it manually
>
> tests/qtest/libqos/virtio.c | 44 ++++++++++++++++++++++++-------------
> 1 file changed, 29 insertions(+), 15 deletions(-)
Thanks!
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
I tried this on top:
-- >8 --
diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index 930a91dcb7d..5e01c1effc7 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -731,8 +730,0 @@ int64_t qtest_clock_set(QTestState *s, int64_t val);
-/**
- * qtest_big_endian:
- * @s: QTestState instance to operate on.
- *
- * Returns: True if the architecture under test has a big endian
configuration.
- */
-bool qtest_big_endian(QTestState *s);
-
diff --git a/tests/qtest/libqos/virtio-pci.c
b/tests/qtest/libqos/virtio-pci.c
index 002bf8b8c2d..98b35ceb9e3 100644
--- a/tests/qtest/libqos/virtio-pci.c
+++ b/tests/qtest/libqos/virtio-pci.c
@@ -389,0 +390,20 @@ void qvirtio_pci_start_hw(QOSGraphObject *obj)
+/**
+ * qvirtio_pci_query_legacy_endianness:
+ * @s: QTestState instance to operate on.
+ *
+ * Returns: True if the architecture under test has a big endian
configuration.
+ */
+static int qvirtio_pci_query_legacy_endianness(QTestState *s)
+{
+ gchar **args;
+ int big_endian;
+
+ qtest_sendf(s, "endianness\n");
+ args = qtest_rsp_args(s, 1);
+ g_assert(strcmp(args[1], "big") == 0 || strcmp(args[1], "little")
== 0);
+ big_endian = strcmp(args[1], "big") == 0;
+ g_strfreev(args);
+
+ return big_endian;
+}
+
@@ -391,0 +412,2 @@ static void qvirtio_pci_init_legacy(QVirtioPCIDevice
*dev)
+ bool big_endian =
qvirtio_pci_query_legacy_endianness(dev->pdev->bus->qts);
+
@@ -396 +418 @@ static void qvirtio_pci_init_legacy(QVirtioPCIDevice *dev)
- dev->vdev.big_endian = qtest_big_endian(dev->pdev->bus->qts);
+ dev->vdev.big_endian = big_endian;
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 358580361d3..4a29a8fd750 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -87 +86,0 @@ struct QTestState
- bool big_endian;
@@ -552,2 +550,0 @@ void qtest_connect(QTestState *s)
- /* ask endianness of the target */
- s->big_endian = qtest_query_target_endianness(s);
@@ -779,14 +775,0 @@ static void qtest_rsp(QTestState *s)
-static int qtest_query_target_endianness(QTestState *s)
-{
- gchar **args;
- int big_endian;
-
- qtest_sendf(s, "endianness\n");
- args = qtest_rsp_args(s, 1);
- g_assert(strcmp(args[1], "big") == 0 || strcmp(args[1], "little")
== 0);
- big_endian = strcmp(args[1], "big") == 0;
- g_strfreev(args);
-
- return big_endian;
-}
-
@@ -1561,5 +1543,0 @@ void qtest_qmp_fds_assert_success(QTestState *qts,
int *fds, size_t nfds,
-bool qtest_big_endian(QTestState *s)
-{
- return s->big_endian;
-}
-
@@ -2000,2 +1977,0 @@ QTestState *qtest_inproc_init(QTestState **s, bool
log, const char* arch,
- qts->big_endian = qtest_query_target_endianness(qts);
-
---
But it doesn't work due to qtest_sendf() and qtest_rsp_args() being
local to tests/qtest/libqtest.c:
../../tests/qtest/libqos/virtio-pci.c:401:5: error: call to undeclared
function 'qtest_sendf'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
401 | qtest_sendf(s, "endianness\n");
| ^
../../tests/qtest/libqos/virtio-pci.c:402:12: error: call to undeclared
function 'qtest_rsp_args'; ISO C99 and later do not support implicit
function declarations [-Wimplicit-function-declaration]
402 | args = qtest_rsp_args(s, 1);
| ^
On 30/04/2025 15.50, Philippe Mathieu-Daudé wrote: > On 30/4/25 15:28, Thomas Huth wrote: >> From: Thomas Huth <thuth@redhat.com> >> >> The logic in the qvirtio_read/write function is rather a headache, >> involving byte-swapping when the target is big endian, just to >> maybe involve another byte-swapping in the qtest_read/write >> function immediately afterwards (on the QEMU side). Let's do it in >> a more obvious way here: For virtio 1.0, we know that the values have >> to be little endian, so let's read/write the bytes in that well known >> order here. >> >> Signed-off-by: Thomas Huth <thuth@redhat.com> >> --- >> This also decreases our usage of qtest_big_endian() which might (or >> might not) get helpful for the universal binary one day... >> >> v2: Use leXX_to_cpu() / cpu_to_leXX() instead of doing it manually >> >> tests/qtest/libqos/virtio.c | 44 ++++++++++++++++++++++++------------- >> 1 file changed, 29 insertions(+), 15 deletions(-) > > Thanks! > > Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> > > I tried this on top: > > -- >8 -- > diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h > index 930a91dcb7d..5e01c1effc7 100644 > --- a/tests/qtest/libqtest.h > +++ b/tests/qtest/libqtest.h > @@ -731,8 +730,0 @@ int64_t qtest_clock_set(QTestState *s, int64_t val); > -/** > - * qtest_big_endian: > - * @s: QTestState instance to operate on. > - * > - * Returns: True if the architecture under test has a big endian > configuration. > - */ > -bool qtest_big_endian(QTestState *s); I think you might be able to get rid of the big_endian stuff there completely if we can be sure that all tests run with VIRTIO_1. As far as I can see, the PCI-based tests should be fine, but the MMIO-based tests still seem to run in legacy mode. Maybe this could be fixed by adding a "-global virtio-mmio.force-legacy=false" somewhere in the right spot? Or could we set force-legacy to false by default in the QEMU binary nowadays? Thomas
© 2016 - 2025 Red Hat, Inc.