If the host supports 128 bit-wide features, and the driver use any of them, serialize the full features range leveraging newly introduced 128bits integer helpers.
Signed-off-by: Paolo Abeni <pab...@redhat.com> --- hw/virtio/virtio.c | 76 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 701f59884d..ef15a1835e 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2982,6 +2982,26 @@ static const VMStateDescription vmstate_virtio_disabled = { } }; +#ifdef CONFIG_INT128 +static bool virtio_128bit_features_needed(void *opaque) +{ + VirtIODevice *vdev = opaque; + + return (vdev->host_features_ex >> 64) != 0; +} + +static const VMStateDescription vmstate_virtio_128bit_features = { + .name = "virtio/128bit_features", + .version_id = 1, + .minimum_version_id = 1, + .needed = &virtio_128bit_features_needed, + .fields = (const VMStateField[]) { + VMSTATE_UINT128(guest_features_ex, VirtIODevice), + VMSTATE_END_OF_LIST() + } +}; +#endif + static const VMStateDescription vmstate_virtio = { .name = "virtio", .version_id = 1, @@ -2991,6 +3011,9 @@ static const VMStateDescription vmstate_virtio = { }, .subsections = (const VMStateDescription * const []) { &vmstate_virtio_device_endian, +#ifdef CONFIG_INT128 + &vmstate_virtio_128bit_features, +#endif &vmstate_virtio_64bit_features, &vmstate_virtio_virtqueues, &vmstate_virtio_ringsize, @@ -3087,7 +3110,8 @@ const VMStateInfo virtio_vmstate_info = { .put = virtio_device_put, }; -static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) +static int virtio_set_features_nocheck(VirtIODevice *vdev, + virtio_features_t val) { VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); bool bad = (val & ~(vdev->host_features)) != 0; @@ -3133,6 +3157,42 @@ virtio_set_features_nocheck_maybe_co(VirtIODevice *vdev, uint64_t val) } } +#ifdef CONFIG_INT128 +typedef struct VirtioSetFeaturesExNocheckData { + Coroutine *co; + VirtIODevice *vdev; + __uint128_t val; + int ret; +} VirtioSetFeaturesExNocheckData; + +static void virtio_set_features_ex_nocheck_bh(void *opaque) +{ + VirtioSetFeaturesExNocheckData *data = opaque; + + data->ret = virtio_set_features_nocheck(data->vdev, data->val); + aio_co_wake(data->co); +} + +static int coroutine_mixed_fn +virtio_set_features_ex_nocheck_maybe_co(VirtIODevice *vdev, __uint128_t val) +{ + if (qemu_in_coroutine()) { + VirtioSetFeaturesExNocheckData data = { + .co = qemu_coroutine_self(), + .vdev = vdev, + .val = val, + }; + aio_bh_schedule_oneshot(qemu_get_current_aio_context(), + virtio_set_features_ex_nocheck_bh, &data); + qemu_coroutine_yield(); + return data.ret; + } else { + return virtio_set_features_nocheck(vdev, val); + } +} + +#endif + int virtio_set_features(VirtIODevice *vdev, uint64_t val) { int ret; @@ -3318,6 +3378,20 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) vdev->device_endian = virtio_default_endian(); } +#ifdef CONFIG_INT128 + if (virtio_128bit_features_needed(vdev)) { + __int128_t features128 = vdev->guest_features_ex; + if (virtio_set_features_ex_nocheck_maybe_co(vdev, features128) < 0) { + error_report("Features 0x" VIRTIO_FEATURES_FMT " unsupported. " + "Allowed features: 0x" VIRTIO_FEATURES_FMT, + VIRTIO_FEATURES_HI(features128), + VIRTIO_FEATURES_LOW(features128), + VIRTIO_FEATURES_HI(vdev->host_features_ex), + VIRTIO_FEATURES_LOW(vdev->host_features_ex)); + return -1; + } + } else +#endif if (virtio_64bit_features_needed(vdev)) { /* * Subsection load filled vdev->guest_features. Run them -- 2.49.0