From nobody Mon Feb 9 13:38:22 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1649964015; cv=none; d=zohomail.com; s=zohoarc; b=HzwmidRv9lBLZOhJk06f/IzBxsbTwuOf7igjYKIpzK4B2cnvTYM0Qt1GZ0csJjzZZkh2t/ggWN972KNcDfd3xSGMpdm0Zy6KSA7rodkOvVBNs5fE2+m/xG/YSyGkQ87RPbbpCHHm4rZx0W3DTtKyJkbYyYM0OWi4WZfzar/i4LI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1649964015; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=HH0lNJhCKrn1KVzcgV/uI3rqOPkxUwMay92nkSrAjww=; b=fxZD/H8gbGmh6mCS5NhjWLxefUyANeKGJsITgFPkL1oPlpicO/1GgMdRf0JKtXKlQ/UBMWOp92dD7AVpfAwmEM2+4vK1YWkTyvVKwulenSNtofY/E33Rw1yAk6iPp7l1Jf516nhba9bCNCj2c5s5/QuRVOQKwO/qgriyg1e6p0M= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1649964015229673.5238670460665; Thu, 14 Apr 2022 12:20:15 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.305049.519891 (Exim 4.92) (envelope-from ) id 1nf50L-0005vc-Mf; Thu, 14 Apr 2022 19:19:45 +0000 Received: by outflank-mailman (output) from mailman id 305049.519891; Thu, 14 Apr 2022 19:19:45 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1nf50L-0005v5-G6; Thu, 14 Apr 2022 19:19:45 +0000 Received: by outflank-mailman (input) for mailman id 305049; Thu, 14 Apr 2022 19:19:44 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1nf50K-00054x-KR for xen-devel@lists.xenproject.org; Thu, 14 Apr 2022 19:19:44 +0000 Received: from mail-lj1-x230.google.com (mail-lj1-x230.google.com [2a00:1450:4864:20::230]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id d6d29c6f-bc27-11ec-8fbe-03012f2f19d4; Thu, 14 Apr 2022 21:19:43 +0200 (CEST) Received: by mail-lj1-x230.google.com with SMTP id o16so7264762ljp.3 for ; Thu, 14 Apr 2022 12:19:43 -0700 (PDT) Received: from otyshchenko.router ([212.22.223.21]) by smtp.gmail.com with ESMTPSA id l3-20020a194943000000b0046b928d2795sm85001lfj.67.2022.04.14.12.19.41 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 14 Apr 2022 12:19:42 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: d6d29c6f-bc27-11ec-8fbe-03012f2f19d4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HH0lNJhCKrn1KVzcgV/uI3rqOPkxUwMay92nkSrAjww=; b=CSmQsWmMPhKn65VWOLhlyWUk/5YwfpW6oHGmDgSr8oyIRtln1bgL/FxXCzwqOQ2scW Kul15jhG/xUMsrq9hwxgzV7VZ+jj3hupZRanvoSdnRr8nY+F8D9bVK1bhDZDRzNimT23 LAh7fUHs+YKWYCqE86acY6uO/YWr6KZAKVBtZxwCRFor0ambo4hAmrApMjmGMTo04/Vx omjZqW9FpYwni3wQwXilVmnhhBiTL44fcofN4KwMa0r/naLAzWmPO9D0cVR9OT/QkH7A h4d5ucGnzxq/vZwtYADqFA6IbCHPqfZ2O1SM0pyYOBrcVF6qgnYeOnQS+OhyTtG8dwru XDgw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HH0lNJhCKrn1KVzcgV/uI3rqOPkxUwMay92nkSrAjww=; b=C45vKP/KXwWMnkBsnGoT9PkvB8ww3PfQgr0HsOvcUR8+2LI2TRnE/I2ZZtmSw3uBs4 pzfpUGNjqW584lp93FohXlmcRBiIwSYZRXooztWmRGbNT6LEUT6r6lKJiaaxgHWbmOhX TZhxbf66R5j2i1Ok6L57UGLMjQi9xzX4cFdmVDBpP43fn9mi6UGj8hkOmjQNRX8aOuCP Hc1S7w6AYeQJ00YaGsfSjuWMXejW2nM0sKOvAHn1HO/FFWr4oIphFs7L5dEgBlTQf+2e pVt1V904IdslXAkRbKCrZBcBc8pqSIceJTWkqC7joxKN/ntrt/aY4ncjLdZuqHN2cTfm xaHw== X-Gm-Message-State: AOAM532kWm62D2QwoAqF8ETnuLrkLgLn4WPPibAL5uM+gRlrMTu9aKMm 5tEKWdcqQfY3o85r/APcaYMWeFWeHX0= X-Google-Smtp-Source: ABdhPJyqaIJqLPokLPf5w1P1n+RXHoKfPPFHkJ8cRMG0ZDENL1jq4zsAVzAnYaGGBHo3X65+xfsMjQ== X-Received: by 2002:a2e:9c2:0:b0:24a:c757:b9bb with SMTP id 185-20020a2e09c2000000b0024ac757b9bbmr2493120ljj.360.1649963982965; Thu, 14 Apr 2022 12:19:42 -0700 (PDT) From: Oleksandr Tyshchenko To: xen-devel@lists.xenproject.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: Oleksandr Tyshchenko , Stefano Stabellini , Russell King , Boris Ostrovsky , Juergen Gross , Julien Grall Subject: [RFC PATCH 4/6] virtio: Various updates to xen-virtio DMA ops layer Date: Thu, 14 Apr 2022 22:19:31 +0300 Message-Id: <1649963973-22879-5-git-send-email-olekstysh@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1649963973-22879-1-git-send-email-olekstysh@gmail.com> References: <1649963973-22879-1-git-send-email-olekstysh@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1649964015766100011 From: Oleksandr Tyshchenko In the context of current patch do the following: 1. Update code to support virtio-mmio devices 2. Introduce struct xen_virtio_data and account passed virtio devices (using list) as we need to store some per-device data 3. Add multi-page support for xen_virtio_dma_map(unmap)_page callbacks 4. Harden code against malicious backend 5. Change to use alloc_pages_exact() instead of __get_free_pages() 6. Introduce locking scheme to protect mappings (I am not 100% sure whether per-device lock is really needed) 7. Handle virtio device's DMA mask 8. Retrieve the ID of backend domain from DT for virtio-mmio device instead of hardcoding it. Signed-off-by: Oleksandr Tyshchenko --- arch/arm/xen/enlighten.c | 11 +++ drivers/xen/Kconfig | 2 +- drivers/xen/xen-virtio.c | 200 ++++++++++++++++++++++++++++++++++++++++++-= ---- include/xen/xen-ops.h | 5 ++ 4 files changed, 196 insertions(+), 22 deletions(-) diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index ec5b082..870d92f 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -409,6 +409,17 @@ int __init arch_xen_unpopulated_init(struct resource *= *res) } #endif =20 +#ifdef CONFIG_ARCH_HAS_RESTRICTED_VIRTIO_MEMORY_ACCESS +int arch_has_restricted_virtio_memory_access(void) +{ + if (IS_ENABLED(CONFIG_XEN_HVM_VIRTIO_GRANT) && xen_hvm_domain()) + return 1; + + return 0; +} +EXPORT_SYMBOL_GPL(arch_has_restricted_virtio_memory_access); +#endif + static void __init xen_dt_guest_init(void) { struct device_node *xen_node; diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index fc61f7a..56afe6a 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -347,7 +347,7 @@ config XEN_VIRTIO =20 config XEN_HVM_VIRTIO_GRANT bool "Require virtio for fully virtualized guests to use grant mappings" - depends on XEN_VIRTIO && X86_64 + depends on XEN_VIRTIO && (X86_64 || ARM || ARM64) default y help Require virtio for fully virtualized guests to use grant mappings. diff --git a/drivers/xen/xen-virtio.c b/drivers/xen/xen-virtio.c index cfd5eda..c5b2ec9 100644 --- a/drivers/xen/xen-virtio.c +++ b/drivers/xen/xen-virtio.c @@ -7,12 +7,26 @@ =20 #include #include +#include #include #include #include #include #include =20 +struct xen_virtio_data { + /* The ID of backend domain */ + domid_t dev_domid; + struct device *dev; + struct list_head list; + spinlock_t lock; + /* Is device behaving sane? */ + bool broken; +}; + +static LIST_HEAD(xen_virtio_devices); +static DEFINE_SPINLOCK(xen_virtio_lock); + #define XEN_GRANT_ADDR_OFF 0x8000000000000000ULL =20 static inline dma_addr_t grant_to_dma(grant_ref_t grant) @@ -25,6 +39,25 @@ static inline grant_ref_t dma_to_grant(dma_addr_t dma) return (grant_ref_t)((dma & ~XEN_GRANT_ADDR_OFF) >> PAGE_SHIFT); } =20 +static struct xen_virtio_data *find_xen_virtio_data(struct device *dev) +{ + struct xen_virtio_data *data =3D NULL; + bool found =3D false; + + spin_lock(&xen_virtio_lock); + + list_for_each_entry( data, &xen_virtio_devices, list) { + if (data->dev =3D=3D dev) { + found =3D true; + break; + } + } + + spin_unlock(&xen_virtio_lock); + + return found ? data : NULL; +} + /* * DMA ops for Xen virtio frontends. * @@ -43,48 +76,78 @@ static void *xen_virtio_dma_alloc(struct device *dev, s= ize_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { - unsigned int n_pages =3D PFN_UP(size); - unsigned int i; + struct xen_virtio_data *data; + unsigned int i, n_pages =3D PFN_UP(size); unsigned long pfn; grant_ref_t grant; - void *ret; + void *ret =3D NULL; =20 - ret =3D (void *)__get_free_pages(gfp, get_order(size)); - if (!ret) + data =3D find_xen_virtio_data(dev); + if (!data) return NULL; =20 + spin_lock(&data->lock); + + if (unlikely(data->broken)) + goto out; + + ret =3D alloc_pages_exact(n_pages * PAGE_SIZE, gfp); + if (!ret) + goto out; + pfn =3D virt_to_pfn(ret); =20 if (gnttab_alloc_grant_reference_seq(n_pages, &grant)) { - free_pages((unsigned long)ret, get_order(size)); - return NULL; + free_pages_exact(ret, n_pages * PAGE_SIZE); + ret =3D NULL; + goto out; } =20 for (i =3D 0; i < n_pages; i++) { - gnttab_grant_foreign_access_ref(grant + i, 0, + gnttab_grant_foreign_access_ref(grant + i, data->dev_domid, pfn_to_gfn(pfn + i), 0); } =20 *dma_handle =3D grant_to_dma(grant); =20 +out: + spin_unlock(&data->lock); + return ret; } =20 static void xen_virtio_dma_free(struct device *dev, size_t size, void *vad= dr, dma_addr_t dma_handle, unsigned long attrs) { - unsigned int n_pages =3D PFN_UP(size); - unsigned int i; + struct xen_virtio_data *data; + unsigned int i, n_pages =3D PFN_UP(size); grant_ref_t grant; =20 + data =3D find_xen_virtio_data(dev); + if (!data) + return; + + spin_lock(&data->lock); + + if (unlikely(data->broken)) + goto out; + grant =3D dma_to_grant(dma_handle); =20 - for (i =3D 0; i < n_pages; i++) - gnttab_end_foreign_access_ref(grant + i); + for (i =3D 0; i < n_pages; i++) { + if (unlikely(!gnttab_end_foreign_access_ref(grant + i))) { + dev_alert(dev, "Grant still in use by backend domain, disabled for furt= her use\n"); + data->broken =3D true; + goto out; + } + } =20 gnttab_free_grant_reference_seq(grant, n_pages); =20 - free_pages((unsigned long)vaddr, get_order(size)); + free_pages_exact(vaddr, n_pages * PAGE_SIZE); + +out: + spin_unlock(&data->lock); } =20 static struct page *xen_virtio_dma_alloc_pages(struct device *dev, size_t = size, @@ -108,28 +171,71 @@ static dma_addr_t xen_virtio_dma_map_page(struct devi= ce *dev, struct page *page, enum dma_data_direction dir, unsigned long attrs) { + struct xen_virtio_data *data; + unsigned int i, n_pages =3D PFN_UP(size); grant_ref_t grant; + dma_addr_t dma_handle =3D DMA_MAPPING_ERROR; + + BUG_ON(dir =3D=3D DMA_NONE); + + data =3D find_xen_virtio_data(dev); + if (!data) + return DMA_MAPPING_ERROR; + + spin_lock(&data->lock); =20 - if (gnttab_alloc_grant_references(1, &grant)) - return 0; + if (unlikely(data->broken)) + goto out; =20 - gnttab_grant_foreign_access_ref(grant, 0, xen_page_to_gfn(page), - dir =3D=3D DMA_TO_DEVICE); + if (gnttab_alloc_grant_reference_seq(n_pages, &grant)) + goto out; =20 - return grant_to_dma(grant) + offset; + for (i =3D 0; i < n_pages; i++) { + gnttab_grant_foreign_access_ref(grant + i, data->dev_domid, + xen_page_to_gfn(page) + i, dir =3D=3D DMA_TO_DEVICE); + } + + dma_handle =3D grant_to_dma(grant) + offset; + +out: + spin_unlock(&data->lock); + + return dma_handle; } =20 static void xen_virtio_dma_unmap_page(struct device *dev, dma_addr_t dma_h= andle, size_t size, enum dma_data_direction dir, unsigned long attrs) { + struct xen_virtio_data *data; + unsigned int i, n_pages =3D PFN_UP(size); grant_ref_t grant; =20 + BUG_ON(dir =3D=3D DMA_NONE); + + data =3D find_xen_virtio_data(dev); + if (!data) + return; + + spin_lock(&data->lock); + + if (unlikely(data->broken)) + goto out; + grant =3D dma_to_grant(dma_handle); =20 - gnttab_end_foreign_access_ref(grant); + for (i =3D 0; i < n_pages; i++) { + if (unlikely(!gnttab_end_foreign_access_ref(grant + i))) { + dev_alert(dev, "Grant still in use by backend domain, disabled for furt= her use\n"); + data->broken =3D true; + goto out; + } + } + + gnttab_free_grant_reference_seq(grant, n_pages); =20 - gnttab_free_grant_reference(grant); +out: + spin_unlock(&data->lock); } =20 static int xen_virtio_dma_map_sg(struct device *dev, struct scatterlist *s= g, @@ -149,7 +255,7 @@ static void xen_virtio_dma_unmap_sg(struct device *dev,= struct scatterlist *sg, =20 static int xen_virtio_dma_dma_supported(struct device *dev, u64 mask) { - return 1; + return mask =3D=3D DMA_BIT_MASK(64); } =20 static const struct dma_map_ops xen_virtio_dma_ops =3D { @@ -166,9 +272,61 @@ static const struct dma_map_ops xen_virtio_dma_ops =3D= { .dma_supported =3D xen_virtio_dma_dma_supported, }; =20 +bool xen_is_virtio_device(struct device *dev) +{ + /* XXX Handle only DT devices for now */ + if (!dev->of_node) + return false; + + if (!of_device_is_compatible(dev->of_node, "virtio,mmio")) + return false; + + return of_property_read_bool(dev->of_node, "xen,dev-domid"); +} +EXPORT_SYMBOL_GPL(xen_is_virtio_device); + void xen_virtio_setup_dma_ops(struct device *dev) { + struct xen_virtio_data *data; + uint32_t dev_domid; + + data =3D find_xen_virtio_data(dev); + if (data) { + dev_err(dev, "xen_virtio data is already created\n"); + return; + } + + if (dev_is_pci(dev)) { + /* XXX Leave it hard wired to dom0 for now */ + dev_domid =3D 0; + } else if (dev->of_node) { + if (of_property_read_u32(dev->of_node, "xen,dev-domid", &dev_domid)) { + dev_err(dev, "xen,dev-domid property is not present\n"); + goto err; + } + } else + /* The ACPI case is not supported */ + goto err; + + data =3D devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(dev, "=D0=A1annot allocate xen_virtio data\n"); + goto err; + } + data->dev_domid =3D dev_domid; + data->dev =3D dev; + spin_lock_init(&data->lock); + + spin_lock(&xen_virtio_lock); + list_add(&data->list, &xen_virtio_devices); + spin_unlock(&xen_virtio_lock); + dev->dma_ops =3D &xen_virtio_dma_ops; + + return; + +err: + dev_err(dev, "=D0=A1annot set up xen_virtio DMA ops, retain platform DMA = ops\n"); } EXPORT_SYMBOL_GPL(xen_virtio_setup_dma_ops); =20 diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index ae3c1bc..fdbcb99 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -223,10 +223,15 @@ static inline void xen_preemptible_hcall_end(void) { } =20 #ifdef CONFIG_XEN_VIRTIO void xen_virtio_setup_dma_ops(struct device *dev); +bool xen_is_virtio_device(struct device *dev); #else static inline void xen_virtio_setup_dma_ops(struct device *dev) { } +static inline bool xen_is_virtio_device(struct device *dev) +{ + return false; +} #endif /* CONFIG_XEN_VIRTIO */ =20 #endif /* INCLUDE_XEN_OPS_H */ --=20 2.7.4