aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/s390-virtio-bus.c5
-rw-r--r--hw/syborg_virtio.c4
-rw-r--r--hw/virtio-pci.c9
-rw-r--r--hw/virtio.c24
-rw-r--r--hw/virtio.h1
5 files changed, 23 insertions, 20 deletions
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 0ce6406b6d..c4b9a99e6e 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -254,10 +254,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
/* Update guest supported feature bitmap */
features = bswap32(ldl_be_phys(dev->feat_offs));
- if (vdev->set_features) {
- vdev->set_features(vdev, features);
- }
- vdev->guest_features = features;
+ virtio_set_features(vdev, features);
}
VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus)
diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c
index 00c7be8c8f..6de952c938 100644
--- a/hw/syborg_virtio.c
+++ b/hw/syborg_virtio.c
@@ -131,9 +131,7 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
}
switch (offset >> 2) {
case SYBORG_VIRTIO_GUEST_FEATURES:
- if (vdev->set_features)
- vdev->set_features(vdev, value);
- vdev->guest_features = value;
+ virtio_set_features(vdev, value);
break;
case SYBORG_VIRTIO_QUEUE_BASE:
if (value == 0)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index ca5923c495..64c6a9414f 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -285,14 +285,9 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case VIRTIO_PCI_GUEST_FEATURES:
/* Guest does not negotiate properly? We have to assume nothing. */
if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
- if (vdev->bad_features)
- val = proxy->host_features & vdev->bad_features(vdev);
- else
- val = 0;
+ val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
}
- if (vdev->set_features)
- vdev->set_features(vdev, val);
- vdev->guest_features = val;
+ virtio_set_features(vdev, val);
break;
case VIRTIO_PCI_QUEUE_PFN:
pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
diff --git a/hw/virtio.c b/hw/virtio.c
index 7011b5b398..81ecc40b31 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -763,12 +763,25 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
}
}
+int virtio_set_features(VirtIODevice *vdev, uint32_t val)
+{
+ uint32_t supported_features =
+ vdev->binding->get_features(vdev->binding_opaque);
+ bool bad = (val & ~supported_features) != 0;
+
+ val &= supported_features;
+ if (vdev->set_features) {
+ vdev->set_features(vdev, val);
+ }
+ vdev->guest_features = val;
+ return bad ? -1 : 0;
+}
+
int virtio_load(VirtIODevice *vdev, QEMUFile *f)
{
int num, i, ret;
uint32_t features;
- uint32_t supported_features =
- vdev->binding->get_features(vdev->binding_opaque);
+ uint32_t supported_features;
if (vdev->binding->load_config) {
ret = vdev->binding->load_config(vdev->binding_opaque, f);
@@ -780,14 +793,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
qemu_get_8s(f, &vdev->isr);
qemu_get_be16s(f, &vdev->queue_sel);
qemu_get_be32s(f, &features);
- if (features & ~supported_features) {
+
+ if (virtio_set_features(vdev, features) < 0) {
+ supported_features = vdev->binding->get_features(vdev->binding_opaque);
error_report("Features 0x%x unsupported. Allowed features: 0x%x",
features, supported_features);
return -1;
}
- if (vdev->set_features)
- vdev->set_features(vdev, features);
- vdev->guest_features = features;
vdev->config_len = qemu_get_be32(f);
qemu_get_buffer(f, vdev->config, vdev->config_len);
diff --git a/hw/virtio.h b/hw/virtio.h
index 2d18209fb2..25f55647b4 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -185,6 +185,7 @@ void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector);
void virtio_set_status(VirtIODevice *vdev, uint8_t val);
void virtio_reset(void *opaque);
void virtio_update_irq(VirtIODevice *vdev);
+int virtio_set_features(VirtIODevice *vdev, uint32_t val);
void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
void *opaque);