Commit 8eca6b1bc770982595db2f7207c65051572436cb
1 parent
1da92db2
Fix oops on 2.6.25 guest (Rusty Russell)
I believe this is behind the following: https://bugs.edge.launchpad.net/ubuntu/jaunty/+source/linux/+bug/331128 virtio_pci in 2.6.25 didn't do feature negotiation correctly: it acked every bit. Fortunately, we can detect this. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6975 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
27 additions
and
1 deletions
hw/virtio-net.c
... | ... | @@ -113,6 +113,21 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev) |
113 | 113 | return features; |
114 | 114 | } |
115 | 115 | |
116 | +static uint32_t virtio_net_bad_features(VirtIODevice *vdev) | |
117 | +{ | |
118 | + uint32_t features = 0; | |
119 | + | |
120 | + /* Linux kernel 2.6.25. It understood MAC (as everyone must), | |
121 | + * but also these: */ | |
122 | + features |= (1 << VIRTIO_NET_F_MAC); | |
123 | + features |= (1 << VIRTIO_NET_F_GUEST_CSUM); | |
124 | + features |= (1 << VIRTIO_NET_F_GUEST_TSO4); | |
125 | + features |= (1 << VIRTIO_NET_F_GUEST_TSO6); | |
126 | + features |= (1 << VIRTIO_NET_F_GUEST_ECN); | |
127 | + | |
128 | + return features & virtio_net_get_features(vdev); | |
129 | +} | |
130 | + | |
116 | 131 | static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) |
117 | 132 | { |
118 | 133 | VirtIONet *n = to_virtio_net(vdev); |
... | ... | @@ -580,6 +595,7 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) |
580 | 595 | n->vdev.set_config = virtio_net_set_config; |
581 | 596 | n->vdev.get_features = virtio_net_get_features; |
582 | 597 | n->vdev.set_features = virtio_net_set_features; |
598 | + n->vdev.bad_features = virtio_net_bad_features; | |
583 | 599 | n->vdev.reset = virtio_net_reset; |
584 | 600 | n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); |
585 | 601 | n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx); | ... | ... |
hw/virtio.c
... | ... | @@ -451,6 +451,13 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
451 | 451 | |
452 | 452 | switch (addr) { |
453 | 453 | case VIRTIO_PCI_GUEST_FEATURES: |
454 | + /* Guest does not negotiate properly? We have to assume nothing. */ | |
455 | + if (val & (1 << VIRTIO_F_BAD_FEATURE)) { | |
456 | + if (vdev->bad_features) | |
457 | + val = vdev->bad_features(vdev); | |
458 | + else | |
459 | + val = 0; | |
460 | + } | |
454 | 461 | if (vdev->set_features) |
455 | 462 | vdev->set_features(vdev, val); |
456 | 463 | vdev->features = val; |
... | ... | @@ -490,7 +497,7 @@ static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) |
490 | 497 | switch (addr) { |
491 | 498 | case VIRTIO_PCI_HOST_FEATURES: |
492 | 499 | ret = vdev->get_features(vdev); |
493 | - ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); | |
500 | + ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE); | |
494 | 501 | break; |
495 | 502 | case VIRTIO_PCI_GUEST_FEATURES: |
496 | 503 | ret = vdev->features; | ... | ... |
hw/virtio.h
... | ... | @@ -32,6 +32,8 @@ |
32 | 32 | /* We notify when the ring is completely used, even if the guest is supressing |
33 | 33 | * callbacks */ |
34 | 34 | #define VIRTIO_F_NOTIFY_ON_EMPTY 24 |
35 | +/* A guest should never accept this. It implies negotiation is broken. */ | |
36 | +#define VIRTIO_F_BAD_FEATURE 30 | |
35 | 37 | |
36 | 38 | /* from Linux's linux/virtio_ring.h */ |
37 | 39 | |
... | ... | @@ -82,6 +84,7 @@ struct VirtIODevice |
82 | 84 | size_t config_len; |
83 | 85 | void *config; |
84 | 86 | uint32_t (*get_features)(VirtIODevice *vdev); |
87 | + uint32_t (*bad_features)(VirtIODevice *vdev); | |
85 | 88 | void (*set_features)(VirtIODevice *vdev, uint32_t val); |
86 | 89 | void (*get_config)(VirtIODevice *vdev, uint8_t *config); |
87 | 90 | void (*set_config)(VirtIODevice *vdev, const uint8_t *config); | ... | ... |