On Wed, May 29, 2013 at 02:01:18PM +0930, Rusty Russell wrote:
> Anthony Liguori <aligu...@us.ibm.com> writes:
> > "Michael S. Tsirkin" <m...@redhat.com> writes:
> >> +    case offsetof(struct virtio_pci_common_cfg, device_feature_select):
> >> +        return proxy->device_feature_select;
> >
> > Oh dear no...  Please use defines like the rest of QEMU.
> 
> It is pretty ugly.
> 
> Yet the structure definitions are descriptive, capturing layout, size
> and endianness in natural a format readable by any C programmer.
> 
> So AFAICT the question is, do we put the required
> 
> #define VIRTIO_PCI_CFG_FEATURE_SEL \
>          (offsetof(struct virtio_pci_common_cfg, device_feature_select))
> 
> etc. in the kernel headers or qemu?


I forgot that we need to validate size (different fields
have different sizes so memory core does not validate
for us).

And that is much cleaner if we use offsetof directly:
You can see that you are checking the correct
size matching the offset, at a glance.

--->

virtio: new layout: add offset validation

Signed-off-by: Michael S. Tsirkin <m...@redhat.com>

---

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index f4db224..fd09ea7 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -467,51 +467,70 @@ static uint64_t virtio_pci_config_common_read(void 
*opaque, hwaddr addr,
 {
     VirtIOPCIProxy *proxy = opaque;
     VirtIODevice *vdev = proxy->vdev;
+    struct virtio_pci_common_cfg cfg;
 
     uint64_t low = 0xffffffffull;
 
     switch (addr) {
     case offsetof(struct virtio_pci_common_cfg, device_feature_select):
+        assert(size == sizeof cfg.device_feature_select);
         return proxy->device_feature_select;
     case offsetof(struct virtio_pci_common_cfg, device_feature):
+        assert(size == sizeof cfg.device_feature);
         /* TODO: 64-bit features */
        return proxy->device_feature_select ? 0 : proxy->host_features;
     case offsetof(struct virtio_pci_common_cfg, guest_feature_select):
+        assert(size == sizeof cfg.guest_feature_select);
         return proxy->guest_feature_select;
     case offsetof(struct virtio_pci_common_cfg, guest_feature):
+        assert(size == sizeof cfg.guest_feature);
         /* TODO: 64-bit features */
        return proxy->guest_feature_select ? 0 : vdev->guest_features;
     case offsetof(struct virtio_pci_common_cfg, msix_config):
+        assert(size == sizeof cfg.msix_config);
        return vdev->config_vector;
     case offsetof(struct virtio_pci_common_cfg, num_queues):
+        assert(size == sizeof cfg.num_queues);
         /* TODO: more exact limit? */
        return VIRTIO_PCI_QUEUE_MAX;
     case offsetof(struct virtio_pci_common_cfg, device_status):
+        assert(size == sizeof cfg.device_status);
         return vdev->status;
 
        /* About a specific virtqueue. */
     case offsetof(struct virtio_pci_common_cfg, queue_select):
+        assert(size == sizeof cfg.queue_select);
         return  vdev->queue_sel;
     case offsetof(struct virtio_pci_common_cfg, queue_size):
+        assert(size == sizeof cfg.queue_size);
         return virtio_queue_get_num(vdev, vdev->queue_sel);
     case offsetof(struct virtio_pci_common_cfg, queue_msix_vector):
+        assert(size == sizeof cfg.queue_msix_vector);
        return virtio_queue_vector(vdev, vdev->queue_sel);
     case offsetof(struct virtio_pci_common_cfg, queue_enable):
+        assert(size == sizeof cfg.queue_enable);
         /* TODO */
        return 0;
     case offsetof(struct virtio_pci_common_cfg, queue_notify_off):
+        assert(size == sizeof cfg.queue_notify_off);
         return vdev->queue_sel;
     case offsetof(struct virtio_pci_common_cfg, queue_desc):
+        assert(size == 4);
         return virtio_queue_get_desc_addr(vdev, vdev->queue_sel) & low;
     case offsetof(struct virtio_pci_common_cfg, queue_desc) + 4:
+        assert(size == 4);
         return virtio_queue_get_desc_addr(vdev, vdev->queue_sel) >> 32;
     case offsetof(struct virtio_pci_common_cfg, queue_avail):
+        assert(size == 4);
         return virtio_queue_get_avail_addr(vdev, vdev->queue_sel) & low;
     case offsetof(struct virtio_pci_common_cfg, queue_avail) + 4:
+        assert(size == 4);
         return virtio_queue_get_avail_addr(vdev, vdev->queue_sel) >> 32;
     case offsetof(struct virtio_pci_common_cfg, queue_used):
+        assert(size == 4);
         return virtio_queue_get_used_addr(vdev, vdev->queue_sel) & low;
     case offsetof(struct virtio_pci_common_cfg, queue_used) + 4:
+        assert(size == 4);
         return virtio_queue_get_used_addr(vdev, vdev->queue_sel) >> 32;
     default:
         return 0;
@@ -523,76 +542,95 @@ static void virtio_pci_config_common_write(void *opaque, 
hwaddr addr,
 {
     VirtIOPCIProxy *proxy = opaque;
     VirtIODevice *vdev = proxy->vdev;
+    struct virtio_pci_common_cfg cfg;
 
     uint64_t low = 0xffffffffull;
     uint64_t high = ~low;
 
     switch (addr) {
     case offsetof(struct virtio_pci_common_cfg, device_feature_select):
+        assert(size == sizeof cfg.device_feature_select);
         proxy->device_feature_select = val;
         break;
     case offsetof(struct virtio_pci_common_cfg, device_feature):
+        assert(size == sizeof cfg.device_feature);
         break;
     case offsetof(struct virtio_pci_common_cfg, guest_feature_select):
+        assert(size == sizeof cfg.guest_feature_select);
         proxy->guest_feature_select = val;
         break;
     case offsetof(struct virtio_pci_common_cfg, guest_feature):
+        assert(size == sizeof cfg.guest_feature);
         /* TODO: 64-bit features */
        if (!proxy->guest_feature_select) {
             virtio_set_features(vdev, val);
         }
         break;
     case offsetof(struct virtio_pci_common_cfg, msix_config):
+        assert(size == sizeof cfg.msix_config);
        vdev->config_vector = val;
         break;
     case offsetof(struct virtio_pci_common_cfg, num_queues):
+        assert(size == sizeof cfg.num_queues);
         break;
     case offsetof(struct virtio_pci_common_cfg, device_status):
+        assert(size == sizeof cfg.device_status);
         virtio_pci_set_status(proxy, val);
         break;
        /* About a specific virtqueue. */
     case offsetof(struct virtio_pci_common_cfg, queue_select):
+        assert(size == sizeof cfg.queue_select);
         assert(val < VIRTIO_PCI_QUEUE_MAX);
         vdev->queue_sel = val;
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_size):
+        assert(size == sizeof cfg.queue_size);
         assert(val && val < 0x8ffff && !(val & (val - 1)));
         virtio_queue_set_num(vdev, vdev->queue_sel, val);
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_msix_vector):
+        assert(size == sizeof cfg.queue_msix_vector);
        virtio_queue_set_vector(vdev, vdev->queue_sel, val);
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_enable):
+        assert(size == sizeof cfg.queue_enable);
         /* TODO */
        break;
     case offsetof(struct virtio_pci_common_cfg, queue_notify_off):
+        assert(size == sizeof cfg.queue_notify_off);
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_desc):
+        assert(size == 4);
         val &= low;
         val |= virtio_queue_get_desc_addr(vdev, vdev->queue_sel) & high;
         virtio_queue_set_desc_addr(vdev, vdev->queue_sel, val);
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_desc) + 4:
+        assert(size == 4);
         val = val << 32;
         val |= virtio_queue_get_desc_addr(vdev, vdev->queue_sel) & low;
         virtio_queue_set_desc_addr(vdev, vdev->queue_sel, val);
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_avail):
+        assert(size == 4);
         val &= low;
         val |= virtio_queue_get_avail_addr(vdev, vdev->queue_sel) & high;
         virtio_queue_set_avail_addr(vdev, vdev->queue_sel, val);
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_avail) + 4:
+        assert(size == 4);
         val = val << 32;
         val |= virtio_queue_get_avail_addr(vdev, vdev->queue_sel) & low;
         virtio_queue_set_avail_addr(vdev, vdev->queue_sel, val);
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_used):
+        assert(size == 4);
         val &= low;
         val |= virtio_queue_get_used_addr(vdev, vdev->queue_sel) & high;
         virtio_queue_set_used_addr(vdev, vdev->queue_sel, val);
         break;
     case offsetof(struct virtio_pci_common_cfg, queue_used) + 4:
+        assert(size == 4);
         val = val << 32;
         val |= virtio_queue_get_used_addr(vdev, vdev->queue_sel) & low;
         virtio_queue_set_used_addr(vdev, vdev->queue_sel, val);
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to