summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2015-02-13 17:13:42 +1030
committerRusty Russell <rusty@rustcorp.com.au>2015-02-13 17:15:51 +1030
commitd761b0329108c73020a7c95b6fa0d7e82e35fe8b (patch)
tree2abab56c0ee04256082f4c171f8d01b1f2393604
parent3afe3e0f8db10a41a5923e1d7498318877473f33 (diff)
downloadlinux-d761b0329108c73020a7c95b6fa0d7e82e35fe8b.tar.gz
linux-d761b0329108c73020a7c95b6fa0d7e82e35fe8b.tar.bz2
linux-d761b0329108c73020a7c95b6fa0d7e82e35fe8b.zip
tools/lguest: don't start devices until DRIVER_OK status set.
We were activating them with the virtqueues, and that's not allowed. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--tools/lguest/lguest.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c
index 990671e61f87..4c7c2aa66c89 100644
--- a/tools/lguest/lguest.c
+++ b/tools/lguest/lguest.c
@@ -1688,16 +1688,15 @@ static void restore_vq_config(struct virtio_pci_common_cfg *cfg,
}
/*
+ * 4.1.4.3.2:
+ *
+ * The driver MUST configure the other virtqueue fields before
+ * enabling the virtqueue with queue_enable.
+ *
* When they enable the virtqueue, we check that their setup is valid.
*/
-static void enable_virtqueue(struct device *d, struct virtqueue *vq)
+static void check_virtqueue(struct device *d, struct virtqueue *vq)
{
- /*
- * Create stack for thread. Since the stack grows upwards, we point
- * the stack pointer to the end of this region.
- */
- char *stack = malloc(32768);
-
/* Because lguest is 32 bit, all the descriptor high bits must be 0 */
if (vq->pci_config.queue_desc_hi
|| vq->pci_config.queue_avail_hi
@@ -1716,7 +1715,15 @@ static void enable_virtqueue(struct device *d, struct virtqueue *vq)
sizeof(*vq->vring.used)
+ (sizeof(vq->vring.used->ring[0])
* vq->vring.num));
+}
+static void start_virtqueue(struct virtqueue *vq)
+{
+ /*
+ * Create stack for thread. Since the stack grows upwards, we point
+ * the stack pointer to the end of this region.
+ */
+ char *stack = malloc(32768);
/* Create a zero-initialized eventfd. */
vq->eventfd = eventfd(0, 0);
@@ -1732,6 +1739,16 @@ static void enable_virtqueue(struct device *d, struct virtqueue *vq)
err(1, "Creating clone");
}
+static void start_virtqueues(struct device *d)
+{
+ struct virtqueue *vq;
+
+ for (vq = d->vq; vq; vq = vq->next) {
+ if (vq->pci_config.queue_enable)
+ start_virtqueue(vq);
+ }
+}
+
static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask)
{
struct virtqueue *vq;
@@ -1780,6 +1797,17 @@ static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask)
*/
if (val == 0)
reset_device(d);
+
+ /*
+ * 2.1.2:
+ *
+ * The device MUST NOT consume buffers or notify the driver
+ * before DRIVER_OK.
+ */
+ if (val & VIRTIO_CONFIG_S_DRIVER_OK
+ && !(d->mmio->cfg.device_status & VIRTIO_CONFIG_S_DRIVER_OK))
+ start_virtqueues(d);
+
goto write_through8;
case offsetof(struct virtio_pci_mmio, cfg.queue_select):
vq = vq_by_num(d, val);
@@ -1833,7 +1861,7 @@ static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask)
* The driver MUST configure the other virtqueue fields before
* enabling the virtqueue with queue_enable.
*/
- enable_virtqueue(d, vq_by_num(d, d->mmio->cfg.queue_select));
+ check_virtqueue(d, vq_by_num(d, d->mmio->cfg.queue_select));
goto write_through16;
case offsetof(struct virtio_pci_mmio, cfg.queue_notify_off):
errx(1, "%s: attempt to write to queue_notify_off", d->name);