tests/qtest/libqos/virtio.c | 61 ++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 17 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...
tests/qtest/libqos/virtio.c | 61 ++++++++++++++++++++++++++-----------
1 file changed, 44 insertions(+), 17 deletions(-)
diff --git a/tests/qtest/libqos/virtio.c b/tests/qtest/libqos/virtio.c
index 2e7979652fd..078adf3c8dc 100644
--- a/tests/qtest/libqos/virtio.c
+++ b/tests/qtest/libqos/virtio.c
@@ -25,49 +25,76 @@
*/
static uint16_t qvirtio_readw(QVirtioDevice *d, QTestState *qts, uint64_t addr)
{
- uint16_t val = qtest_readw(qts, addr);
+ uint8_t buf[2];
- 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, buf, sizeof(buf));
+ return (buf[1] << 8) | buf[0];
+ } else {
+ return 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);
+ uint8_t buf[4];
- 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, buf, sizeof(buf));
+ return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ } else {
+ return 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);
+ uint8_t buf[2];
+
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ buf[0] = val;
+ buf[1] = val >> 8;
+ qtest_memwrite(qts, addr, buf, sizeof(buf));
+ } 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);
+ uint8_t buf[4];
+
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ buf[0] = val;
+ buf[1] = val >> 8;
+ buf[2] = val >> 16;
+ buf[3] = val >> 24;
+ qtest_memwrite(qts, addr, buf, sizeof(buf));
+ } 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);
+ uint8_t buf[8];
+
+ if (d->features & (1ull << VIRTIO_F_VERSION_1)) {
+ buf[0] = val;
+ buf[1] = val >> 8;
+ buf[2] = val >> 16;
+ buf[3] = val >> 24;
+ buf[4] = val >> 32;
+ buf[5] = val >> 40;
+ buf[6] = val >> 48;
+ buf[7] = val >> 56;
+ qtest_memwrite(qts, addr, buf, sizeof(buf));
+ } else {
+ qtest_writeq(qts, addr, val);
}
- qtest_writeq(qts, addr, val);
}
uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr)
--
2.49.0
On 30/4/25 09:33, 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.
Thanks for looking at this!
>
> 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...
>
> tests/qtest/libqos/virtio.c | 61 ++++++++++++++++++++++++++-----------
> 1 file changed, 44 insertions(+), 17 deletions(-)
>
> diff --git a/tests/qtest/libqos/virtio.c b/tests/qtest/libqos/virtio.c
> index 2e7979652fd..078adf3c8dc 100644
> --- a/tests/qtest/libqos/virtio.c
> +++ b/tests/qtest/libqos/virtio.c
> @@ -25,49 +25,76 @@
> */
> static uint16_t qvirtio_readw(QVirtioDevice *d, QTestState *qts, uint64_t addr)
> {
> - uint16_t val = qtest_readw(qts, addr);
> + uint8_t buf[2];
>
> - 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, buf, sizeof(buf));
> + return (buf[1] << 8) | buf[0];
> + } else {
> + return qtest_readw(qts, addr);
> }
> - return val;
> }
What about using cpu_to_le() API?
-- >8 --
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));
+ cpu_to_le16s(&val);
+ } else {
+ val = qtest_readw(qts, addr);
}
+
return val;
}
---
On 30/04/2025 10.40, Philippe Mathieu-Daudé wrote:
> On 30/4/25 09:33, 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.
>
> Thanks for looking at this!
>
>>
>> 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...
>>
>> tests/qtest/libqos/virtio.c | 61 ++++++++++++++++++++++++++-----------
>> 1 file changed, 44 insertions(+), 17 deletions(-)
>>
>> diff --git a/tests/qtest/libqos/virtio.c b/tests/qtest/libqos/virtio.c
>> index 2e7979652fd..078adf3c8dc 100644
>> --- a/tests/qtest/libqos/virtio.c
>> +++ b/tests/qtest/libqos/virtio.c
>> @@ -25,49 +25,76 @@
>> */
>> static uint16_t qvirtio_readw(QVirtioDevice *d, QTestState *qts,
>> uint64_t addr)
>> {
>> - uint16_t val = qtest_readw(qts, addr);
>> + uint8_t buf[2];
>> - 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, buf, sizeof(buf));
>> + return (buf[1] << 8) | buf[0];
>> + } else {
>> + return qtest_readw(qts, addr);
>> }
>> - return val;
>> }
>
> What about using cpu_to_le() API?
>
> -- >8 --
> 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));
> + cpu_to_le16s(&val);
> + } else {
> + val = qtest_readw(qts, addr);
> }
> +
> return val;
> }
D'oh, not sure how I could have forgotten about these functions, that's much
nicer indeed! I'll respin my patch with that, thanks for the reminder!
Thomas
© 2016 - 2025 Red Hat, Inc.