summaryrefslogtreecommitdiff
path: root/hw/virtio/virtio.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2018-08-23 14:21:23 +0200
committerMichael S. Tsirkin <mst@redhat.com>2018-09-07 17:05:18 -0400
commitdb812c4073c77c8a64db8d6663b3416a587c7b4a (patch)
tree8ca2687455cbbeea15a2352a617d11fad18607ea /hw/virtio/virtio.c
parentdbb6da8ba7e02105bdbb33b527e088249c9843c8 (diff)
downloadqemu-db812c4073c77c8a64db8d6663b3416a587c7b4a.zip
virtio: update MemoryRegionCaches when guest negotiates features
Because the cache is sized to include the rings and the event indices, negotiating the VIRTIO_RING_F_EVENT_IDX feature will result in the size of the cache changing. And because MemoryRegionCache accesses are range-checked, if we skip this we end up with an assertion failure. This happens with OpenBSD 6.3. Reported-by: Fam Zheng <famz@redhat.com> Fixes: 97cd965c070152bc626c7507df9fb356bbe1cd81 Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Tested-by: Fam Zheng <famz@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/virtio/virtio.c')
-rw-r--r--hw/virtio/virtio.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index d4e4d98b59..f6a588ab57 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2006,14 +2006,25 @@ static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val)
int virtio_set_features(VirtIODevice *vdev, uint64_t val)
{
- /*
+ int ret;
+ /*
* The driver must not attempt to set features after feature negotiation
* has finished.
*/
if (vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) {
return -EINVAL;
}
- return virtio_set_features_nocheck(vdev, val);
+ ret = virtio_set_features_nocheck(vdev, val);
+ if (!ret && virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ /* VIRTIO_RING_F_EVENT_IDX changes the size of the caches. */
+ int i;
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ if (vdev->vq[i].vring.num != 0) {
+ virtio_init_region_cache(vdev, i);
+ }
+ }
+ }
+ return ret;
}
int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)