From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9FEA0C433F5 for ; Mon, 16 May 2022 10:43:18 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 3397884272; Mon, 16 May 2022 12:42:39 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="sqR1TCu0"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 1D13F84203; Mon, 16 May 2022 12:42:10 +0200 (CEST) Received: from mail-wm1-x34a.google.com (mail-wm1-x34a.google.com [IPv6:2a00:1450:4864:20::34a]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 537CA840DA for ; Mon, 16 May 2022 12:41:58 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=3dSqCYgYKBuwOgQiZZUccUZS.Qcai-PcchZWghg.RSbl.RS@flex--ascull.bounces.google.com Received: by mail-wm1-x34a.google.com with SMTP id h6-20020a7bc926000000b0039470bcb9easo5457335wml.1 for ; Mon, 16 May 2022 03:41:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=PMhrYNlwcbh5vTdQ3isJoA1u5jksZndnXk2DZ48bkyo=; b=sqR1TCu0ChXtf7leKkYFnYHoVQbYMQJU2Q5yyjWRgpsTgu+4CKquzVK/zT7ANZvmD3 7XY2G3R7Yd9FQGkuS0f9bP3cdIql13Zgp8na5UuQBmvipGpEg+cX5IJw0nlgr3QAbco5 tLLbxX0Y+YoX50Wml3IZudNkYQqLxrTc3YHlBv5ldogsJ4XdpltpyF4GprPm/1vxkrj+ O7xdalT+gFDhNWlPs/ERsKCkYtoNzYa3Hq956ZNiwWrXNUf9gP80ZKdHuLTVj44Tnj8/ NZJSxl9s/e3unigzeWAzHs7Ug6tUq+7F8XdxjYU14KTbQ+QR+QwvNHUNCVFF3FHyOtYq /c+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=PMhrYNlwcbh5vTdQ3isJoA1u5jksZndnXk2DZ48bkyo=; b=ZTj0O7zDrnaak9wr26fGOyNBAfp7BJXQcOWCIWcolF1Z69DIA3VO/ZFvuMsHP5sR6N 1sRD2vO61Z5ym+l5xNA6+DdmEoaXY6kaQRk/o8Parp1wj9fr8c8T1kw5k75MSPXir7gE yBIQOYyTka0VqsDh5kuqFK44FOdDwMMP/KzBrY2ixeXJH/+hbpOTRduHIF9v0Vhkt9mr UTOKI0ehanFgy6Z0BYYNXsTUi1l4xSegLsXS1XwA0liwiB+scjIRJkJo5IraR7y+QbO0 qkq/YC4RLN9QqjQH2ipKn4re8d9qR6IL3ANTrkrJknC+DkC/3FfOhn9XyyAVuo/Mmv6S Xq6Q== X-Gm-Message-State: AOAM533ImX9x/rfLciZIjAjYvfSLWGmRQTTEfCL1tFxWpWLF3yOv+Fc/ yMbIczMg7ZMUuErI9QLJYEx65NhLUoL7wTy9dKtXpWDE7xbBjLMgX7IjUcUs9KAvWdlsq4OSs0h AHV+vVmURVh+tymLQiz8o+Q4sJ+8s5dW/P+gFwmhk0MnrbbMrvkBOwfZEOec= X-Google-Smtp-Source: ABdhPJwJvHQkawwh/5XsgsgGXyzgV4Afbbt9O3/pHQhX5we33keb4KD8yFZuvy4i+/d8k7ROu3trsD+Ox7A= X-Received: from ascull.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:1510]) (user=ascull job=sendgmr) by 2002:a05:600c:1e1a:b0:395:baf7:ca45 with SMTP id ay26-20020a05600c1e1a00b00395baf7ca45mr23511737wmb.85.1652697717866; Mon, 16 May 2022 03:41:57 -0700 (PDT) Date: Mon, 16 May 2022 10:41:31 +0000 In-Reply-To: <20220516104140.1047229-1-ascull@google.com> Message-Id: <20220516104140.1047229-4-ascull@google.com> Mime-Version: 1.0 References: <20220516104140.1047229-1-ascull@google.com> X-Mailer: git-send-email 2.36.0.550.gb090851708-goog Subject: [PATCH v3 03/12] virtio_ring: Maintain a shadow copy of descriptors From: Andrew Scull To: u-boot@lists.denx.de Cc: sjg@chromium.org, trini@konsulko.com, bmeng.cn@gmail.com, Andrew Scull Content-Type: text/plain; charset="UTF-8" X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean The shared descriptors should only be written by the guest driver, however, the device is still able to overwrite and corrupt them. Maintain a private shadow copy of the descriptors for the driver to use for state tracking, removing the need to read from the shared descriptors. Signed-off-by: Andrew Scull Reviewed-by: Simon Glass --- drivers/virtio/virtio_ring.c | 49 ++++++++++++++++++++++++------------ include/virtio_ring.h | 10 ++++++++ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index d3fc842f30..73671d79da 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -19,13 +19,21 @@ static unsigned int virtqueue_attach_desc(struct virtqueue *vq, unsigned int i, struct virtio_sg *sg, u16 flags) { + struct vring_desc_shadow *desc_shadow = &vq->vring_desc_shadow[i]; struct vring_desc *desc = &vq->vring.desc[i]; - desc->addr = cpu_to_virtio64(vq->vdev, (u64)(uintptr_t)sg->addr); - desc->len = cpu_to_virtio32(vq->vdev, sg->length); - desc->flags = cpu_to_virtio16(vq->vdev, flags); + /* Update the shadow descriptor. */ + desc_shadow->addr = (u64)(uintptr_t)sg->addr; + desc_shadow->len = sg->length; + desc_shadow->flags = flags; - return virtio16_to_cpu(vq->vdev, desc->next); + /* Update the shared descriptor to match the shadow. */ + desc->addr = cpu_to_virtio64(vq->vdev, desc_shadow->addr); + desc->len = cpu_to_virtio32(vq->vdev, desc_shadow->len); + desc->flags = cpu_to_virtio16(vq->vdev, desc_shadow->flags); + desc->next = cpu_to_virtio16(vq->vdev, desc_shadow->next); + + return desc_shadow->next; } int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[], @@ -65,7 +73,8 @@ int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[], i = virtqueue_attach_desc(vq, i, sgs[n], flags); } /* Last one doesn't continue */ - desc[prev].flags &= cpu_to_virtio16(vq->vdev, ~VRING_DESC_F_NEXT); + vq->vring_desc_shadow[prev].flags &= ~VRING_DESC_F_NEXT; + desc[prev].flags = cpu_to_virtio16(vq->vdev, vq->vring_desc_shadow[prev].flags); /* We're using some buffers from the free list. */ vq->num_free -= descs_used; @@ -134,17 +143,16 @@ void virtqueue_kick(struct virtqueue *vq) static void detach_buf(struct virtqueue *vq, unsigned int head) { unsigned int i; - __virtio16 nextflag = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT); /* Put back on free list: unmap first-level descriptors and find end */ i = head; - while (vq->vring.desc[i].flags & nextflag) { - i = virtio16_to_cpu(vq->vdev, vq->vring.desc[i].next); + while (vq->vring_desc_shadow[i].flags & VRING_DESC_F_NEXT) { + i = vq->vring_desc_shadow[i].next; vq->num_free++; } - vq->vring.desc[i].next = cpu_to_virtio16(vq->vdev, vq->free_head); + vq->vring_desc_shadow[i].next = vq->free_head; vq->free_head = head; /* Plus final descriptor */ @@ -197,8 +205,7 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len) virtio_store_mb(&vring_used_event(&vq->vring), cpu_to_virtio16(vq->vdev, vq->last_used_idx)); - return (void *)(uintptr_t)virtio64_to_cpu(vq->vdev, - vq->vring.desc[i].addr); + return (void *)(uintptr_t)vq->vring_desc_shadow[i].addr; } static struct virtqueue *__vring_new_virtqueue(unsigned int index, @@ -207,6 +214,7 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index, { unsigned int i; struct virtqueue *vq; + struct vring_desc_shadow *vring_desc_shadow; struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev); struct udevice *vdev = uc_priv->vdev; @@ -214,10 +222,17 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index, if (!vq) return NULL; + vring_desc_shadow = calloc(vring.num, sizeof(struct vring_desc_shadow)); + if (!vring_desc_shadow) { + free(vq); + return NULL; + } + vq->vdev = vdev; vq->index = index; vq->num_free = vring.num; vq->vring = vring; + vq->vring_desc_shadow = vring_desc_shadow; vq->last_used_idx = 0; vq->avail_flags_shadow = 0; vq->avail_idx_shadow = 0; @@ -235,7 +250,7 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index, /* Put everything in free lists */ vq->free_head = 0; for (i = 0; i < vring.num - 1; i++) - vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1); + vq->vring_desc_shadow[i].next = i + 1; return vq; } @@ -288,6 +303,7 @@ struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, void vring_del_virtqueue(struct virtqueue *vq) { free(vq->vring.desc); + free(vq->vring_desc_shadow); list_del(&vq->list); free(vq); } @@ -333,11 +349,12 @@ void virtqueue_dump(struct virtqueue *vq) printf("\tlast_used_idx %u, avail_flags_shadow %u, avail_idx_shadow %u\n", vq->last_used_idx, vq->avail_flags_shadow, vq->avail_idx_shadow); - printf("Descriptor dump:\n"); + printf("Shadow descriptor dump:\n"); for (i = 0; i < vq->vring.num; i++) { - printf("\tdesc[%u] = { 0x%llx, len %u, flags %u, next %u }\n", - i, vq->vring.desc[i].addr, vq->vring.desc[i].len, - vq->vring.desc[i].flags, vq->vring.desc[i].next); + struct vring_desc_shadow *desc = &vq->vring_desc_shadow[i]; + + printf("\tdesc_shadow[%u] = { 0x%llx, len %u, flags %u, next %u }\n", + i, desc->addr, desc->len, desc->flags, desc->next); } printf("Avail ring dump:\n"); diff --git a/include/virtio_ring.h b/include/virtio_ring.h index 6fc0593b14..52cbe77c0a 100644 --- a/include/virtio_ring.h +++ b/include/virtio_ring.h @@ -55,6 +55,14 @@ struct vring_desc { __virtio16 next; }; +/* Shadow of struct vring_desc in guest byte order. */ +struct vring_desc_shadow { + u64 addr; + u32 len; + u16 flags; + u16 next; +}; + struct vring_avail { __virtio16 flags; __virtio16 idx; @@ -89,6 +97,7 @@ struct vring { * @index: the zero-based ordinal number for this queue * @num_free: number of elements we expect to be able to fit * @vring: actual memory layout for this queue + * @vring_desc_shadow: guest-only copy of descriptors * @event: host publishes avail event idx * @free_head: head of free buffer list * @num_added: number we've added since last sync @@ -102,6 +111,7 @@ struct virtqueue { unsigned int index; unsigned int num_free; struct vring vring; + struct vring_desc_shadow *vring_desc_shadow; bool event; unsigned int free_head; unsigned int num_added; -- 2.36.0.550.gb090851708-goog