virtio: add and use virtio_set_features
vdev->guest_features is not masking features that are not supported by the guest. Fix this by introducing a common wrapper to be used by all virtio bus implementations. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
		
							parent
							
								
									ae0f940e6b
								
							
						
					
					
						commit
						ad0c93328d
					
				@ -254,10 +254,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
 | 
				
			|||||||
    /* Update guest supported feature bitmap */
 | 
					    /* Update guest supported feature bitmap */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    features = bswap32(ldl_be_phys(dev->feat_offs));
 | 
					    features = bswap32(ldl_be_phys(dev->feat_offs));
 | 
				
			||||||
    if (vdev->set_features) {
 | 
					    virtio_set_features(vdev, features);
 | 
				
			||||||
        vdev->set_features(vdev, features);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    vdev->guest_features = features;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus)
 | 
					VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus)
 | 
				
			||||||
 | 
				
			|||||||
@ -131,9 +131,7 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    switch (offset >> 2) {
 | 
					    switch (offset >> 2) {
 | 
				
			||||||
    case SYBORG_VIRTIO_GUEST_FEATURES:
 | 
					    case SYBORG_VIRTIO_GUEST_FEATURES:
 | 
				
			||||||
        if (vdev->set_features)
 | 
					        virtio_set_features(vdev, value);
 | 
				
			||||||
            vdev->set_features(vdev, value);
 | 
					 | 
				
			||||||
        vdev->guest_features = value;
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case SYBORG_VIRTIO_QUEUE_BASE:
 | 
					    case SYBORG_VIRTIO_QUEUE_BASE:
 | 
				
			||||||
        if (value == 0)
 | 
					        if (value == 0)
 | 
				
			||||||
 | 
				
			|||||||
@ -285,14 +285,9 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 | 
				
			|||||||
    case VIRTIO_PCI_GUEST_FEATURES:
 | 
					    case VIRTIO_PCI_GUEST_FEATURES:
 | 
				
			||||||
	/* Guest does not negotiate properly?  We have to assume nothing. */
 | 
						/* Guest does not negotiate properly?  We have to assume nothing. */
 | 
				
			||||||
	if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
 | 
						if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
 | 
				
			||||||
	    if (vdev->bad_features)
 | 
					            val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
 | 
				
			||||||
		val = proxy->host_features & vdev->bad_features(vdev);
 | 
					 | 
				
			||||||
	    else
 | 
					 | 
				
			||||||
		val = 0;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
        if (vdev->set_features)
 | 
					        virtio_set_features(vdev, val);
 | 
				
			||||||
            vdev->set_features(vdev, val);
 | 
					 | 
				
			||||||
        vdev->guest_features = val;
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case VIRTIO_PCI_QUEUE_PFN:
 | 
					    case VIRTIO_PCI_QUEUE_PFN:
 | 
				
			||||||
        pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
 | 
					        pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										24
									
								
								hw/virtio.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								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 virtio_load(VirtIODevice *vdev, QEMUFile *f)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int num, i, ret;
 | 
					    int num, i, ret;
 | 
				
			||||||
    uint32_t features;
 | 
					    uint32_t features;
 | 
				
			||||||
    uint32_t supported_features =
 | 
					    uint32_t supported_features;
 | 
				
			||||||
        vdev->binding->get_features(vdev->binding_opaque);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (vdev->binding->load_config) {
 | 
					    if (vdev->binding->load_config) {
 | 
				
			||||||
        ret = vdev->binding->load_config(vdev->binding_opaque, f);
 | 
					        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_8s(f, &vdev->isr);
 | 
				
			||||||
    qemu_get_be16s(f, &vdev->queue_sel);
 | 
					    qemu_get_be16s(f, &vdev->queue_sel);
 | 
				
			||||||
    qemu_get_be32s(f, &features);
 | 
					    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",
 | 
					        error_report("Features 0x%x unsupported. Allowed features: 0x%x",
 | 
				
			||||||
                     features, supported_features);
 | 
					                     features, supported_features);
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (vdev->set_features)
 | 
					 | 
				
			||||||
        vdev->set_features(vdev, features);
 | 
					 | 
				
			||||||
    vdev->guest_features = features;
 | 
					 | 
				
			||||||
    vdev->config_len = qemu_get_be32(f);
 | 
					    vdev->config_len = qemu_get_be32(f);
 | 
				
			||||||
    qemu_get_buffer(f, vdev->config, vdev->config_len);
 | 
					    qemu_get_buffer(f, vdev->config, vdev->config_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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_set_status(VirtIODevice *vdev, uint8_t val);
 | 
				
			||||||
void virtio_reset(void *opaque);
 | 
					void virtio_reset(void *opaque);
 | 
				
			||||||
void virtio_update_irq(VirtIODevice *vdev);
 | 
					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 virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
 | 
				
			||||||
                        void *opaque);
 | 
					                        void *opaque);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user