diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 3f4c9e7a02..93a407c459 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -21,7 +21,8 @@ #include "virtio-9p-coth.h" #include "hw/virtio/virtio-access.h" -static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features) +static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) { virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG); return features; diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 6ef8af3f64..f972731f5a 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -14,6 +14,7 @@ #include "hw/virtio/virtio.h" #include "hw/i386/pc.h" #include "qemu/error-report.h" +#include "qemu/iov.h" #include "qemu/sockets.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" @@ -3261,16 +3262,26 @@ void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) while ((pdu = alloc_pdu(s)) && (len = virtqueue_pop(vq, &pdu->elem)) != 0) { - uint8_t *ptr; + struct { + uint32_t size_le; + uint8_t id; + uint16_t tag_le; + } QEMU_PACKED out; + int len; + pdu->s = s; BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0); - BUG_ON(pdu->elem.out_sg[0].iov_len < 7); + QEMU_BUILD_BUG_ON(sizeof out != 7); - ptr = pdu->elem.out_sg[0].iov_base; + len = iov_to_buf(pdu->elem.out_sg, pdu->elem.out_num, 0, + &out, sizeof out); + BUG_ON(len != sizeof out); + + pdu->size = le32_to_cpu(out.size_le); + + pdu->id = out.id; + pdu->tag = le16_to_cpu(out.tag_le); - pdu->size = le32_to_cpu(*(uint32_t *)ptr); - pdu->id = ptr[4]; - pdu->tag = le16_to_cpu(*(uint16_t *)(ptr + 5)); qemu_co_queue_init(&pdu->complete); submit_pdu(s, pdu); } diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 6aefda4bf2..1556c9cf5a 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -722,7 +722,8 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) aio_context_release(blk_get_aio_context(s->blk)); } -static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features) +static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) { VirtIOBlock *s = VIRTIO_BLK(vdev); @@ -730,7 +731,15 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features) virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); - virtio_add_feature(&features, VIRTIO_BLK_F_SCSI); + if (__virtio_has_feature(features, VIRTIO_F_VERSION_1)) { + if (s->conf.scsi) { + error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0"); + return 0; + } + } else { + virtio_clear_feature(&features, VIRTIO_F_ANY_LAYOUT); + virtio_add_feature(&features, VIRTIO_BLK_F_SCSI); + } if (s->conf.config_wce) { virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE); diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 78c73e5abe..bc56f5d520 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -195,7 +195,8 @@ static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len) return 0; } - memcpy(elem.in_sg[0].iov_base, buf, len); + /* TODO: detect a buffer that's too short, set NEEDS_RESET */ + iov_from_buf(elem.in_sg, elem.in_num, 0, buf, len); virtqueue_push(vq, &elem, len); virtio_notify(VIRTIO_DEVICE(vser), vq); @@ -499,7 +500,8 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq) } } -static uint64_t get_features(VirtIODevice *vdev, uint64_t features) +static uint64_t get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) { VirtIOSerial *vser; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 990a26b850..a67d927f56 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -89,7 +89,8 @@ static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config) } } -static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features) +static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) { return features; } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index aed811a166..46eddb8e48 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1108,8 +1108,8 @@ build_ssdt(GArray *table_data, GArray *linker, aml_append(field, aml_named_field("PEPT", 8)); aml_append(dev, field); - /* device present, functioning, decoding, not shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); + /* device present, functioning, decoding, shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); method = aml_method("RDPT", 0); aml_append(method, aml_store(aml_name("PEPT"), aml_local(0))); diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 7f5b8d6000..7b25d27693 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -166,7 +166,8 @@ static void virtio_input_set_config(VirtIODevice *vdev, virtio_notify_config(vdev); } -static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f) +static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f, + Error **errp) { return f; } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 304d3ddde1..1510839547 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -446,7 +446,8 @@ static void virtio_net_set_queues(VirtIONet *n) static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue); -static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features) +static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) { VirtIONet *n = VIRTIO_NET(vdev); NetClientState *nc = qemu_get_queue(n->nic); @@ -1777,8 +1778,6 @@ static void virtio_net_instance_init(Object *obj) } static Property virtio_net_properties[] = { - DEFINE_PROP_BIT("any_layout", VirtIONet, host_features, - VIRTIO_F_ANY_LAYOUT, true), DEFINE_PROP_BIT("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true), DEFINE_PROP_BIT("guest_csum", VirtIONet, host_features, VIRTIO_NET_F_GUEST_CSUM, true), diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 52549f8beb..a69918bef8 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -153,7 +153,8 @@ static void vhost_scsi_stop(VHostSCSI *s) } static uint64_t vhost_scsi_get_features(VirtIODevice *vdev, - uint64_t features) + uint64_t features, + Error **errp) { VHostSCSI *s = VHOST_SCSI(vdev); diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index f7d3c7c48a..811c3da8bd 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -629,7 +629,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev, } static uint64_t virtio_scsi_get_features(VirtIODevice *vdev, - uint64_t requested_features) + uint64_t requested_features, + Error **errp) { VirtIOSCSI *s = VIRTIO_SCSI(vdev); @@ -953,8 +954,6 @@ static Property virtio_scsi_properties[] = { 0xFFFF), DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun, 128), - DEFINE_PROP_BIT("any_layout", VirtIOSCSI, host_features, - VIRTIO_F_ANY_LAYOUT, true), DEFINE_PROP_BIT("hotplug", VirtIOSCSI, host_features, VIRTIO_SCSI_F_HOTPLUG, true), DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features, diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 2990f8de5d..3577b7af91 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -310,7 +310,8 @@ static void virtio_balloon_set_config(VirtIODevice *vdev, trace_virtio_balloon_set_config(dev->actual, oldactual); } -static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f) +static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f, + Error **errp) { VirtIOBalloon *dev = VIRTIO_BALLOON(vdev); f |= dev->host_features; diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 3926f7ee1e..febda76b94 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -54,7 +54,8 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) /* Get the features of the plugged device. */ assert(vdc->get_features != NULL); - vdev->host_features = vdc->get_features(vdev, vdev->host_features); + vdev->host_features = vdc->get_features(vdev, vdev->host_features, + errp); } /* Reset the virtio_bus */ diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 283401aa0d..c024161f59 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1095,7 +1095,8 @@ static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr, break; case VIRTIO_PCI_COMMON_DF: if (proxy->dfselect <= 1) { - val = vdev->host_features >> (32 * proxy->dfselect); + val = (vdev->host_features & ~VIRTIO_LEGACY_FEATURES) >> + (32 * proxy->dfselect); } break; case VIRTIO_PCI_COMMON_GFSELECT: @@ -1413,6 +1414,13 @@ static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, virtio_pci_add_mem_cap(proxy, cap); } +static void virtio_pci_modern_region_unmap(VirtIOPCIProxy *proxy, + VirtIOPCIRegion *region) +{ + memory_region_del_subregion(&proxy->modern_bar, + ®ion->mr); +} + /* This is called by virtio-bus just after the device is plugged. */ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) { @@ -1519,8 +1527,16 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) static void virtio_pci_device_unplugged(DeviceState *d) { VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN); virtio_pci_stop_ioeventfd(proxy); + + if (modern) { + virtio_pci_modern_region_unmap(proxy, &proxy->common); + virtio_pci_modern_region_unmap(proxy, &proxy->isr); + virtio_pci_modern_region_unmap(proxy, &proxy->device); + virtio_pci_modern_region_unmap(proxy, &proxy->notify); + } } static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 6e5f022301..97d1541918 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -104,7 +104,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq) virtio_rng_process(vrng); } -static uint64_t get_features(VirtIODevice *vdev, uint64_t f) +static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp) { return f; } diff --git a/include/hw/compat.h b/include/hw/compat.h index 4a43466f03..94c8097d0c 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -2,7 +2,27 @@ #define HW_COMPAT_H #define HW_COMPAT_2_3 \ - /* empty */ + {\ + .driver = "virtio-blk-pci",\ + .property = "any_layout",\ + .value = "off",\ + },{\ + .driver = "virtio-balloon-pci",\ + .property = "any_layout",\ + .value = "off",\ + },{\ + .driver = "virtio-serial-pci",\ + .property = "any_layout",\ + .value = "off",\ + },{\ + .driver = "virtio-9p-pci",\ + .property = "any_layout",\ + .value = "off",\ + },{\ + .driver = "virtio-rng-pci",\ + .property = "any_layout",\ + .value = "off",\ + }, #define HW_COMPAT_2_2 \ /* empty */ diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 473fb75e28..59f0763ed8 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -25,6 +25,10 @@ /* A guest should never accept this. It implies negotiation is broken. */ #define VIRTIO_F_BAD_FEATURE 30 +#define VIRTIO_LEGACY_FEATURES ((0x1ULL << VIRTIO_F_BAD_FEATURE) | \ + (0x1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) | \ + (0x1ULL << VIRTIO_F_ANY_LAYOUT)) + struct VirtQueue; static inline hwaddr vring_align(hwaddr addr, @@ -97,7 +101,9 @@ typedef struct VirtioDeviceClass { /* This is what a VirtioDevice must implement */ DeviceRealize realize; DeviceUnrealize unrealize; - uint64_t (*get_features)(VirtIODevice *vdev, uint64_t requested_features); + uint64_t (*get_features)(VirtIODevice *vdev, + uint64_t requested_features, + Error **errp); uint64_t (*bad_features)(VirtIODevice *vdev); void (*set_features)(VirtIODevice *vdev, uint64_t val); int (*validate_features)(VirtIODevice *vdev); @@ -214,7 +220,9 @@ typedef struct VirtIORNGConf VirtIORNGConf; DEFINE_PROP_BIT64("event_idx", _state, _field, \ VIRTIO_RING_F_EVENT_IDX, true), \ DEFINE_PROP_BIT64("notify_on_empty", _state, _field, \ - VIRTIO_F_NOTIFY_ON_EMPTY, true) + VIRTIO_F_NOTIFY_ON_EMPTY, true), \ + DEFINE_PROP_BIT64("any_layout", _state, _field, \ + VIRTIO_F_ANY_LAYOUT, true) hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);