summaryrefslogtreecommitdiff
path: root/drivers/virtio
diff options
context:
space:
mode:
authorAndrew Scull <ascull@google.com>2022-05-16 13:41:32 +0300
committerTom Rini <trini@konsulko.com>2022-06-08 16:24:03 +0300
commitfbef3f53d4a1ccdcbec46c923c9d208d6cbb50aa (patch)
treea1dc19e6ec49ade2bc1b5a8b592448d037e0b71a /drivers/virtio
parent10a14536366350fdd2d14af1981d9e3d8cb3c524 (diff)
downloadu-boot-fbef3f53d4a1ccdcbec46c923c9d208d6cbb50aa.tar.xz
virtio_ring: Check used descriptors are chain heads
When the device returns used buffers, it should refer to the descriptor that is the head of the descriptor chain for that buffer. Confirm this to be the case by tracking the head of descriptor chains that have been made available to the device. Signed-off-by: Andrew Scull <ascull@google.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/virtio')
-rw-r--r--drivers/virtio/virtio_ring.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 73671d79da..f71bab7847 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -82,6 +82,9 @@ int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
/* Update free pointer */
vq->free_head = i;
+ /* Mark the descriptor as the head of a chain. */
+ vq->vring_desc_shadow[head].chain_head = true;
+
/*
* Put entry in available array (but don't update avail->idx
* until they do sync).
@@ -144,6 +147,9 @@ static void detach_buf(struct virtqueue *vq, unsigned int head)
{
unsigned int i;
+ /* Unmark the descriptor as the head of a chain. */
+ vq->vring_desc_shadow[head].chain_head = false;
+
/* Put back on free list: unmap first-level descriptors and find end */
i = head;
@@ -194,6 +200,12 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
return NULL;
}
+ if (unlikely(!vq->vring_desc_shadow[i].chain_head)) {
+ printf("(%s.%d): id %u is not a head\n",
+ vq->vdev->name, vq->index, i);
+ return NULL;
+ }
+
detach_buf(vq, i);
vq->last_used_idx++;
/*