diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-13 17:13:42 +1030 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-13 17:15:51 +1030 |
commit | d761b0329108c73020a7c95b6fa0d7e82e35fe8b (patch) | |
tree | 2abab56c0ee04256082f4c171f8d01b1f2393604 /tools/lguest/lguest.c | |
parent | 3afe3e0f8db10a41a5923e1d7498318877473f33 (diff) | |
download | linux-d761b0329108c73020a7c95b6fa0d7e82e35fe8b.tar.bz2 |
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>
Diffstat (limited to 'tools/lguest/lguest.c')
-rw-r--r-- | tools/lguest/lguest.c | 44 |
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); |