virtio: make features 64bit wide
authorGerd Hoffmann <kraxel@redhat.com>
Mon, 1 Jun 2015 08:45:40 +0000 (10:45 +0200)
committerMichael S. Tsirkin <mst@redhat.com>
Mon, 1 Jun 2015 12:18:55 +0000 (14:18 +0200)
Make features 64bit wide everywhere.

On migration a full 64bit guest_features field is sent if one of the
high bits is set, in addition to the lower 32bit guest_features field
which must stay for compatibility reasons.  That way we send the lower
32 feature bits twice, but the code is simpler because we don't have
to split and compose the 64bit features into two 32bit fields.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
hw/9pfs/virtio-9p-device.c
hw/block/virtio-blk.c
hw/char/virtio-serial-bus.c
hw/input/virtio-input.c
hw/net/virtio-net.c
hw/scsi/vhost-scsi.c
hw/scsi/virtio-scsi.c
hw/virtio/virtio-balloon.c
hw/virtio/virtio-rng.c
hw/virtio/virtio.c
include/hw/virtio/virtio.h

index 30492ecb0202c25f37753ce47462ef015d218306..60f9ff9a31f774f282577fef25c7fe48a742fa50 100644 (file)
@@ -21,7 +21,7 @@
 #include "virtio-9p-coth.h"
 #include "hw/virtio/virtio-access.h"
 
-static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
+static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features)
 {
     virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
     return features;
index e6afe9763d88e40de7a987eb95d73fe9e130546d..cd539aa11c666f663bdc5e86025cf9d616dc11fd 100644 (file)
@@ -718,7 +718,7 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
     aio_context_release(blk_get_aio_context(s->blk));
 }
 
-static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
+static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features)
 {
     VirtIOBlock *s = VIRTIO_BLK(vdev);
 
index 333339ebb7c4836af46c69d51671b2144dfe4d62..f893523ef1d1dd95fb28d73cfed05b638dd2df5e 100644 (file)
@@ -498,7 +498,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
     }
 }
 
-static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
+static uint64_t get_features(VirtIODevice *vdev, uint64_t features)
 {
     VirtIOSerial *vser;
 
index e615c5cc7cb8d1672800df911d293043eb9cfb3f..c4f4b3c150e02ecd4dc577d3cc23f75a3fa8a0ac 100644 (file)
@@ -166,7 +166,7 @@ static void virtio_input_set_config(VirtIODevice *vdev,
     virtio_notify_config(vdev);
 }
 
-static uint32_t virtio_input_get_features(VirtIODevice *vdev, uint32_t f)
+static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f)
 {
     return f;
 }
index 6dca7260219163d9c76ce5bf5b7ebf0cac06deed..012ab7fae8e9a385fa46cd69e55d2af799e6c983 100644 (file)
@@ -435,7 +435,7 @@ static void virtio_net_set_queues(VirtIONet *n)
 
 static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue);
 
-static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
+static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features)
 {
     VirtIONet *n = VIRTIO_NET(vdev);
     NetClientState *nc = qemu_get_queue(n->nic);
@@ -468,9 +468,9 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
     return vhost_net_get_features(get_vhost_net(nc->peer), features);
 }
 
-static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
+static uint64_t virtio_net_bad_features(VirtIODevice *vdev)
 {
-    uint32_t features = 0;
+    uint64_t features = 0;
 
     /* Linux kernel 2.6.25.  It understood MAC (as everyone must),
      * but also these: */
@@ -1032,10 +1032,12 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
             if (i == 0)
                 return -1;
             error_report("virtio-net unexpected empty queue: "
-                    "i %zd mergeable %d offset %zd, size %zd, "
-                    "guest hdr len %zd, host hdr len %zd guest features 0x%x",
-                    i, n->mergeable_rx_bufs, offset, size,
-                    n->guest_hdr_len, n->host_hdr_len, vdev->guest_features);
+                         "i %zd mergeable %d offset %zd, size %zd, "
+                         "guest hdr len %zd, host hdr len %zd "
+                         "guest features 0x%" PRIx64,
+                         i, n->mergeable_rx_bufs, offset, size,
+                         n->guest_hdr_len, n->host_hdr_len,
+                         vdev->guest_features);
             exit(1);
         }
 
@@ -1518,7 +1520,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
                              vdev, idx, mask);
 }
 
-static void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features)
+static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features)
 {
     int i, config_size = 0;
     virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
index 335f4429a969c4f84621ca1fece5b5d66a1c4e24..9c76486fa97c923716a15ff525555a6a81c23e3b 100644 (file)
@@ -151,8 +151,8 @@ static void vhost_scsi_stop(VHostSCSI *s)
     vhost_dev_disable_notifiers(&s->dev, vdev);
 }
 
-static uint32_t vhost_scsi_get_features(VirtIODevice *vdev,
-                                        uint32_t features)
+static uint64_t vhost_scsi_get_features(VirtIODevice *vdev,
+                                        uint64_t features)
 {
     VHostSCSI *s = VHOST_SCSI(vdev);
 
index 5818159e6467ae3ae4cbf9295b4b3d366960e1bb..b0dee295d8cbbc820f272ea60b33f5c911d5bd53 100644 (file)
@@ -628,8 +628,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
     vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
 }
 
-static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
-                                         uint32_t requested_features)
+static uint64_t virtio_scsi_get_features(VirtIODevice *vdev,
+                                         uint64_t requested_features)
 {
     VirtIOSCSI *s = VIRTIO_SCSI(vdev);
 
index cfff542f38e4d7538761b1e7e3a163b68f1c415f..f915c7bd736b2bfa6e6ca48908cf7e7af025b458 100644 (file)
@@ -310,7 +310,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
     trace_virtio_balloon_set_config(dev->actual, oldactual);
 }
 
-static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
+static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f)
 {
     f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
     return f;
index 06e71782b2d1813468a643dab87562eecb20cf5f..420c39fb509517ea9c40082a03ca2d60bdad4303 100644 (file)
@@ -99,7 +99,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
     virtio_rng_process(vrng);
 }
 
-static uint32_t get_features(VirtIODevice *vdev, uint32_t f)
+static uint64_t get_features(VirtIODevice *vdev, uint64_t f)
 {
     return f;
 }
index a0637d976350bac3ce315c0b9c2450017ede8b80..596e3d8aaf5082f6470a0861e6b367f1f86460e9 100644 (file)
@@ -906,6 +906,13 @@ static bool virtio_device_endian_needed(void *opaque)
     return vdev->device_endian != virtio_default_endian();
 }
 
+static bool virtio_64bit_features_needed(void *opaque)
+{
+    VirtIODevice *vdev = opaque;
+
+    return (vdev->host_features >> 32) != 0;
+}
+
 static const VMStateDescription vmstate_virtio_device_endian = {
     .name = "virtio/device_endian",
     .version_id = 1,
@@ -916,6 +923,16 @@ static const VMStateDescription vmstate_virtio_device_endian = {
     }
 };
 
+static const VMStateDescription vmstate_virtio_64bit_features = {
+    .name = "virtio/64bit_features",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(guest_features, VirtIODevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_virtio = {
     .name = "virtio",
     .version_id = 1,
@@ -929,6 +946,10 @@ static const VMStateDescription vmstate_virtio = {
             .vmsd = &vmstate_virtio_device_endian,
             .needed = &virtio_device_endian_needed
         },
+        {
+            .vmsd = &vmstate_virtio_64bit_features,
+            .needed = &virtio_64bit_features_needed
+        },
         { 0 }
     }
 };
@@ -938,6 +959,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
+    uint32_t guest_features_lo = (vdev->guest_features & 0xffffffff);
     int i;
 
     if (k->save_config) {
@@ -947,7 +969,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
     qemu_put_8s(f, &vdev->status);
     qemu_put_8s(f, &vdev->isr);
     qemu_put_be16s(f, &vdev->queue_sel);
-    qemu_put_be32s(f, &vdev->guest_features);
+    qemu_put_be32s(f, &guest_features_lo);
     qemu_put_be32(f, vdev->config_len);
     qemu_put_buffer(f, vdev->config, vdev->config_len);
 
@@ -1024,11 +1046,6 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
     }
     qemu_get_be32s(f, &features);
 
-    if (virtio_set_features(vdev, features) < 0) {
-        error_report("Features 0x%x unsupported. Allowed features: 0x%x",
-                     features, vdev->host_features);
-        return -1;
-    }
     config_len = qemu_get_be32(f);
 
     /*
@@ -1094,6 +1111,28 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
         vdev->device_endian = virtio_default_endian();
     }
 
+    if (virtio_64bit_features_needed(vdev)) {
+        /*
+         * Subsection load filled vdev->guest_features.  Run them
+         * through virtio_set_features to sanity-check them against
+         * host_features.
+         */
+        uint64_t features64 = vdev->guest_features;
+        if (virtio_set_features(vdev, features64) < 0) {
+            error_report("Features 0x%" PRIx64 " unsupported. "
+                         "Allowed features: 0x%" PRIx64,
+                         features64, vdev->host_features);
+            return -1;
+        }
+    } else {
+        if (virtio_set_features(vdev, features) < 0) {
+            error_report("Features 0x%x unsupported. "
+                         "Allowed features: 0x%" PRIx64,
+                         features, vdev->host_features);
+            return -1;
+        }
+    }
+
     for (i = 0; i < num; i++) {
         if (vdev->vq[i].pa) {
             uint16_t nheads;
index 45d6e5b01e6931e156917f639c64eaf7018ca79b..7222a904dc27acd6ee0b1c1ba015681f4c67abe7 100644 (file)
@@ -73,8 +73,8 @@ struct VirtIODevice
     uint8_t status;
     uint8_t isr;
     uint16_t queue_sel;
-    uint32_t guest_features;
-    uint32_t host_features;
+    uint64_t guest_features;
+    uint64_t host_features;
     size_t config_len;
     void *config;
     uint16_t config_vector;
@@ -96,8 +96,8 @@ typedef struct VirtioDeviceClass {
     /* This is what a VirtioDevice must implement */
     DeviceRealize realize;
     DeviceUnrealize unrealize;
-    uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
-    uint32_t (*bad_features)(VirtIODevice *vdev);
+    uint64_t (*get_features)(VirtIODevice *vdev, uint64_t requested_features);
+    uint64_t (*bad_features)(VirtIODevice *vdev);
     void (*set_features)(VirtIODevice *vdev, uint32_t val);
     void (*get_config)(VirtIODevice *vdev, uint8_t *config);
     void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
@@ -195,12 +195,12 @@ typedef struct VirtIOSCSIConf VirtIOSCSIConf;
 typedef struct VirtIORNGConf VirtIORNGConf;
 
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
-    DEFINE_PROP_BIT("indirect_desc", _state, _field,    \
-                    VIRTIO_RING_F_INDIRECT_DESC, true), \
-    DEFINE_PROP_BIT("event_idx", _state, _field,        \
-                    VIRTIO_RING_F_EVENT_IDX, true),     \
-    DEFINE_PROP_BIT("notify_on_empty", _state, _field,  \
-                    VIRTIO_F_NOTIFY_ON_EMPTY, true)
+    DEFINE_PROP_BIT64("indirect_desc", _state, _field,    \
+                      VIRTIO_RING_F_INDIRECT_DESC, true), \
+    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)
 
 hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
 hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
@@ -227,21 +227,21 @@ void virtio_irq(VirtQueue *vq);
 VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector);
 VirtQueue *virtio_vector_next_queue(VirtQueue *vq);
 
-static inline void virtio_add_feature(uint32_t *features, unsigned int fbit)
+static inline void virtio_add_feature(uint64_t *features, unsigned int fbit)
 {
-    assert(fbit < 32);
+    assert(fbit < 64);
     *features |= (1 << fbit);
 }
 
-static inline void virtio_clear_feature(uint32_t *features, unsigned int fbit)
+static inline void virtio_clear_feature(uint64_t *features, unsigned int fbit)
 {
-    assert(fbit < 32);
+    assert(fbit < 64);
     *features &= ~(1 << fbit);
 }
 
-static inline bool __virtio_has_feature(uint32_t features, unsigned int fbit)
+static inline bool __virtio_has_feature(uint64_t features, unsigned int fbit)
 {
-    assert(fbit < 32);
+    assert(fbit < 64);
     return !!(features & (1 << fbit));
 }