Revision c81131db
b/hw/virtio-pci.c | ||
---|---|---|
79 | 79 |
* 12 is historical, and due to x86 page size. */ |
80 | 80 |
#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12 |
81 | 81 |
|
82 |
/* We can catch some guest bugs inside here so we continue supporting older |
|
83 |
guests. */ |
|
84 |
#define VIRTIO_PCI_BUG_BUS_MASTER (1 << 0) |
|
85 |
|
|
82 | 86 |
/* QEMU doesn't strictly need write barriers since everything runs in |
83 | 87 |
* lock-step. We'll leave the calls to wmb() in though to make it obvious for |
84 | 88 |
* KVM or if kqemu gets SMP support. |
... | ... | |
90 | 94 |
typedef struct { |
91 | 95 |
PCIDevice pci_dev; |
92 | 96 |
VirtIODevice *vdev; |
97 |
uint32_t bugs; |
|
93 | 98 |
uint32_t addr; |
94 | 99 |
uint32_t class_code; |
95 | 100 |
uint32_t nvectors; |
... | ... | |
144 | 149 |
if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) { |
145 | 150 |
return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector); |
146 | 151 |
} |
152 |
|
|
153 |
/* Try to find out if the guest has bus master disabled, but is |
|
154 |
in ready state. Then we have a buggy guest OS. */ |
|
155 |
if (!(proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && |
|
156 |
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { |
|
157 |
proxy->bugs |= VIRTIO_PCI_BUG_BUS_MASTER; |
|
158 |
} |
|
147 | 159 |
return 0; |
148 | 160 |
} |
149 | 161 |
|
... | ... | |
168 | 180 |
VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev); |
169 | 181 |
virtio_reset(proxy->vdev); |
170 | 182 |
msix_reset(&proxy->pci_dev); |
183 |
proxy->bugs = 0; |
|
171 | 184 |
} |
172 | 185 |
|
173 | 186 |
static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
... | ... | |
211 | 224 |
virtio_reset(proxy->vdev); |
212 | 225 |
msix_unuse_all_vectors(&proxy->pci_dev); |
213 | 226 |
} |
227 |
|
|
228 |
/* Linux before 2.6.34 sets the device as OK without enabling |
|
229 |
the PCI device bus master bit. In this case we need to disable |
|
230 |
some safety checks. */ |
|
231 |
if ((val & VIRTIO_CONFIG_S_DRIVER_OK) && |
|
232 |
!(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { |
|
233 |
proxy->bugs |= VIRTIO_PCI_BUG_BUS_MASTER; |
|
234 |
} |
|
214 | 235 |
break; |
215 | 236 |
case VIRTIO_MSI_CONFIG_VECTOR: |
216 | 237 |
msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); |
... | ... | |
377 | 398 |
|
378 | 399 |
if (PCI_COMMAND == address) { |
379 | 400 |
if (!(val & PCI_COMMAND_MASTER)) { |
380 |
proxy->vdev->status &= ~VIRTIO_CONFIG_S_DRIVER_OK; |
|
401 |
if (!(proxy->bugs & VIRTIO_PCI_BUG_BUS_MASTER)) { |
|
402 |
proxy->vdev->status &= ~VIRTIO_CONFIG_S_DRIVER_OK; |
|
403 |
} |
|
381 | 404 |
} |
382 | 405 |
} |
383 | 406 |
|
Also available in: Unified diff