linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] vfio/iommu_type1: support for platform bus devices on ARM
       [not found] <1413205748-6300-1-git-send-email-a.motakis@virtualopensystems.com>
@ 2014-10-13 13:09 ` Antonios Motakis
  2014-10-13 13:09 ` [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 14+ messages in thread
From: Antonios Motakis @ 2014-10-13 13:09 UTC (permalink / raw)
  To: kvmarm, iommu, alex.williamson
  Cc: will.deacon, tech, christoffer.dall, eric.auger, kim.phillips,
	marc.zyngier, Antonios Motakis, open list:VFIO DRIVER, open list

This allows to make use of the VFIO_IOMMU_TYPE1 driver with platform
devices on ARM. The driver can then be used with an Exynos SMMU, or
ARM SMMU driver.

Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
---
 drivers/vfio/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index d8c5763..a0abe04 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -16,7 +16,7 @@ config VFIO_SPAPR_EEH
 menuconfig VFIO
 	tristate "VFIO Non-Privileged userspace driver framework"
 	depends on IOMMU_API
-	select VFIO_IOMMU_TYPE1 if X86
+	select VFIO_IOMMU_TYPE1 if X86 || ARM
 	select VFIO_IOMMU_SPAPR_TCE if (PPC_POWERNV || PPC_PSERIES)
 	select VFIO_SPAPR_EEH if (PPC_POWERNV || PPC_PSERIES)
 	select ANON_INODES
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag
       [not found] <1413205748-6300-1-git-send-email-a.motakis@virtualopensystems.com>
  2014-10-13 13:09 ` [PATCH 1/5] vfio/iommu_type1: support for platform bus devices on ARM Antonios Motakis
@ 2014-10-13 13:09 ` Antonios Motakis
  2014-10-20 21:29   ` Alex Williamson
  2014-10-20 21:37   ` Andy Lutomirski
  2014-10-13 13:09 ` [PATCH 3/5] vfio: type1: replace domain wide protection flags with supported capabilities Antonios Motakis
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 14+ messages in thread
From: Antonios Motakis @ 2014-10-13 13:09 UTC (permalink / raw)
  To: kvmarm, iommu, alex.williamson
  Cc: will.deacon, tech, christoffer.dall, eric.auger, kim.phillips,
	marc.zyngier, Antonios Motakis, open list:VFIO DRIVER,
	open list:ABI/API, open list

We introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag to the VFIO dma map call,
and expose its availability via the capability VFIO_DMA_NOEXEC_IOMMU.
This way the user can control whether the XN flag will be set on the
requested mappings. The IOMMU_NOEXEC flag needs to be available for all
the IOMMUs of the container used.

Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
---
 include/uapi/linux/vfio.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 6612974..111b5e8 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -29,6 +29,7 @@
  * capability is subject to change as groups are added or removed.
  */
 #define VFIO_DMA_CC_IOMMU		4
+#define VFIO_DMA_NOEXEC_IOMMU		5
 
 /* Check if EEH is supported */
 #define VFIO_EEH			5
@@ -401,6 +402,7 @@ struct vfio_iommu_type1_dma_map {
 	__u32	flags;
 #define VFIO_DMA_MAP_FLAG_READ (1 << 0)		/* readable from device */
 #define VFIO_DMA_MAP_FLAG_WRITE (1 << 1)	/* writable from device */
+#define VFIO_DMA_MAP_FLAG_NOEXEC (1 << 2)	/* not executable from device */
 	__u64	vaddr;				/* Process virtual address */
 	__u64	iova;				/* IO virtual address */
 	__u64	size;				/* Size of mapping (bytes) */
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/5] vfio: type1: replace domain wide protection flags with supported capabilities
       [not found] <1413205748-6300-1-git-send-email-a.motakis@virtualopensystems.com>
  2014-10-13 13:09 ` [PATCH 1/5] vfio/iommu_type1: support for platform bus devices on ARM Antonios Motakis
  2014-10-13 13:09 ` [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
@ 2014-10-13 13:09 ` Antonios Motakis
       [not found]   ` <5447742A.8070705@linaro.org>
  2014-10-13 13:09 ` [PATCH 4/5] vfio: type1: replace vfio_domains_have_iommu_cache with generic function Antonios Motakis
  2014-10-13 13:09 ` [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
  4 siblings, 1 reply; 14+ messages in thread
From: Antonios Motakis @ 2014-10-13 13:09 UTC (permalink / raw)
  To: kvmarm, iommu, alex.williamson
  Cc: will.deacon, tech, christoffer.dall, eric.auger, kim.phillips,
	marc.zyngier, Antonios Motakis, open list:VFIO DRIVER, open list

VFIO_IOMMU_TYPE1 keeps track for each domain it knows a list of protection
flags it always applies to all mappings in the domain. This is used for
domains that support IOMMU_CAP_CACHE_COHERENCY.

Refactor this slightly, by keeping track instead that a given domain
supports the capability, and applying the IOMMU_CACHE protection flag when
doing the actual DMA mappings.

This will allow us to reuse the behavior for IOMMU_CAP_NOEXEC, which we
also want to keep track of, but without applying it to all domains that
support it unless the user explicitly requests it.

Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
---
 drivers/vfio/vfio_iommu_type1.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 562f686..62a8b4d 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -64,7 +64,7 @@ struct vfio_domain {
 	struct iommu_domain	*domain;
 	struct list_head	next;
 	struct list_head	group_list;
-	int			prot;		/* IOMMU_CACHE */
+	int			caps;
 };
 
 struct vfio_dma {
@@ -485,7 +485,7 @@ static int map_try_harder(struct vfio_domain *domain, dma_addr_t iova,
 	for (i = 0; i < npage; i++, pfn++, iova += PAGE_SIZE) {
 		ret = iommu_map(domain->domain, iova,
 				(phys_addr_t)pfn << PAGE_SHIFT,
-				PAGE_SIZE, prot | domain->prot);
+				PAGE_SIZE, prot);
 		if (ret)
 			break;
 	}
@@ -503,11 +503,16 @@ static int vfio_iommu_map(struct vfio_iommu *iommu, dma_addr_t iova,
 	int ret;
 
 	list_for_each_entry(d, &iommu->domain_list, next) {
+		int dprot = prot;
+
+		if (d->caps | IOMMU_CAP_CACHE_COHERENCY)
+			dprot |= IOMMU_CACHE;
+
 		ret = iommu_map(d->domain, iova, (phys_addr_t)pfn << PAGE_SHIFT,
-				npage << PAGE_SHIFT, prot | d->prot);
+				npage << PAGE_SHIFT, dprot);
 		if (ret) {
 			if (ret != -EBUSY ||
-			    map_try_harder(d, iova, pfn, npage, prot))
+			    map_try_harder(d, iova, pfn, npage, dprot))
 				goto unwind;
 		}
 	}
@@ -620,6 +625,10 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
 	struct vfio_domain *d;
 	struct rb_node *n;
 	int ret;
+	int dprot = 0;
+
+	if (domain->caps | IOMMU_CAP_CACHE_COHERENCY)
+		dprot |= IOMMU_CACHE;
 
 	/* Arbitrarily pick the first domain in the list for lookups */
 	d = list_first_entry(&iommu->domain_list, struct vfio_domain, next);
@@ -653,7 +662,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
 				size += PAGE_SIZE;
 
 			ret = iommu_map(domain->domain, iova, phys,
-					size, dma->prot | domain->prot);
+					size, dma->prot | dprot);
 			if (ret)
 				return ret;
 
@@ -721,7 +730,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
 	}
 
 	if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
-		domain->prot |= IOMMU_CACHE;
+		domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
 
 	/*
 	 * Try to match an existing compatible domain.  We don't want to
@@ -732,7 +741,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
 	 */
 	list_for_each_entry(d, &iommu->domain_list, next) {
 		if (d->domain->ops == domain->domain->ops &&
-		    d->prot == domain->prot) {
+		    d->caps == domain->caps) {
 			iommu_detach_group(domain->domain, iommu_group);
 			if (!iommu_attach_group(d->domain, iommu_group)) {
 				list_add(&group->next, &d->group_list);
@@ -865,7 +874,7 @@ static int vfio_domains_have_iommu_cache(struct vfio_iommu *iommu)
 
 	mutex_lock(&iommu->lock);
 	list_for_each_entry(domain, &iommu->domain_list, next) {
-		if (!(domain->prot & IOMMU_CACHE)) {
+		if (!(domain->caps & IOMMU_CAP_CACHE_COHERENCY)) {
 			ret = 0;
 			break;
 		}
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/5] vfio: type1: replace vfio_domains_have_iommu_cache with generic function
       [not found] <1413205748-6300-1-git-send-email-a.motakis@virtualopensystems.com>
                   ` (2 preceding siblings ...)
  2014-10-13 13:09 ` [PATCH 3/5] vfio: type1: replace domain wide protection flags with supported capabilities Antonios Motakis
@ 2014-10-13 13:09 ` Antonios Motakis
  2014-10-13 13:09 ` [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
  4 siblings, 0 replies; 14+ messages in thread
From: Antonios Motakis @ 2014-10-13 13:09 UTC (permalink / raw)
  To: kvmarm, iommu, alex.williamson
  Cc: will.deacon, tech, christoffer.dall, eric.auger, kim.phillips,
	marc.zyngier, Antonios Motakis, open list:VFIO DRIVER, open list

Replace the function vfio_domains_have_iommu_cache() with a more generic
function vfio_domains_have_iommu_cap() which allows to check all domains
of an vfio_iommu structure for a given cached capability.

Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
---
 drivers/vfio/vfio_iommu_type1.c | 37 +++++++++++++++++++------------------
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 62a8b4d..8b4202a 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -80,6 +80,23 @@ struct vfio_group {
 	struct list_head	next;
 };
 
+static int vfio_domains_have_iommu_cap(struct vfio_iommu *iommu, int cap)
+{
+	struct vfio_domain *domain;
+	int ret = 1;
+
+	mutex_lock(&iommu->lock);
+	list_for_each_entry(domain, &iommu->domain_list, next) {
+		if (!(domain->caps & cap)) {
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&iommu->lock);
+
+	return ret;
+}
+
 /*
  * This code handles mapping and unmapping of user data buffers
  * into DMA'ble space using the IOMMU
@@ -867,23 +884,6 @@ static void vfio_iommu_type1_release(void *iommu_data)
 	kfree(iommu);
 }
 
-static int vfio_domains_have_iommu_cache(struct vfio_iommu *iommu)
-{
-	struct vfio_domain *domain;
-	int ret = 1;
-
-	mutex_lock(&iommu->lock);
-	list_for_each_entry(domain, &iommu->domain_list, next) {
-		if (!(domain->caps & IOMMU_CAP_CACHE_COHERENCY)) {
-			ret = 0;
-			break;
-		}
-	}
-	mutex_unlock(&iommu->lock);
-
-	return ret;
-}
-
 static long vfio_iommu_type1_ioctl(void *iommu_data,
 				   unsigned int cmd, unsigned long arg)
 {
@@ -898,7 +898,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
 		case VFIO_DMA_CC_IOMMU:
 			if (!iommu)
 				return 0;
-			return vfio_domains_have_iommu_cache(iommu);
+			return vfio_domains_have_iommu_cap(iommu,
+						  IOMMU_CAP_CACHE_COHERENCY);
 		default:
 			return 0;
 		}
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag
       [not found] <1413205748-6300-1-git-send-email-a.motakis@virtualopensystems.com>
                   ` (3 preceding siblings ...)
  2014-10-13 13:09 ` [PATCH 4/5] vfio: type1: replace vfio_domains_have_iommu_cache with generic function Antonios Motakis
@ 2014-10-13 13:09 ` Antonios Motakis
  2014-10-20 21:13   ` Alex Williamson
  4 siblings, 1 reply; 14+ messages in thread
From: Antonios Motakis @ 2014-10-13 13:09 UTC (permalink / raw)
  To: kvmarm, iommu, alex.williamson
  Cc: will.deacon, tech, christoffer.dall, eric.auger, kim.phillips,
	marc.zyngier, Antonios Motakis, open list:VFIO DRIVER, open list

Some IOMMU drivers, such as the ARM SMMU driver, make available the
IOMMU_NOEXEC flag, to set the page tables for a device as XN (execute never).
This affects devices such as the ARM PL330 DMA Controller, which respects
this flag and will refuse to fetch DMA instructions from memory where the
XN flag has been set.

The flag can be used only if all IOMMU domains behind the container support
the IOMMU_NOEXEC flag. Also, if any mappings are created with the flag, any
new domains with devices will have to support it as well.

Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
---
 drivers/vfio/vfio_iommu_type1.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 8b4202a..e225e8f 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -569,6 +569,12 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
 	if (map->flags & VFIO_DMA_MAP_FLAG_READ)
 		prot |= IOMMU_READ;
 
+	if (map->flags & VFIO_DMA_MAP_FLAG_NOEXEC) {
+		if (!vfio_domains_have_iommu_cap(iommu, IOMMU_CAP_NOEXEC))
+			return -EINVAL;
+		prot |= IOMMU_NOEXEC;
+	}
+
 	if (!prot || !size || (size | iova | vaddr) & mask)
 		return -EINVAL;
 
@@ -662,6 +668,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
 		dma = rb_entry(n, struct vfio_dma, node);
 		iova = dma->iova;
 
+		/*
+		 * if any of the mappings to be replayed has the NOEXEC flag
+		 * set, then the new iommu domain must support it
+		 */
+		if ((dma->prot | IOMMU_NOEXEC) &&
+				!(domain->caps & IOMMU_CAP_NOEXEC))
+			return -EINVAL;
+
 		while (iova < dma->iova + dma->size) {
 			phys_addr_t phys = iommu_iova_to_phys(d->domain, iova);
 			size_t size;
@@ -749,6 +763,9 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
 	if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
 		domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
 
+	if (iommu_capable(bus, IOMMU_CAP_NOEXEC))
+		domain->caps |= IOMMU_CAP_NOEXEC;
+
 	/*
 	 * Try to match an existing compatible domain.  We don't want to
 	 * preclude an IOMMU driver supporting multiple bus_types and being
@@ -900,6 +917,11 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
 				return 0;
 			return vfio_domains_have_iommu_cap(iommu,
 						  IOMMU_CAP_CACHE_COHERENCY);
+		case VFIO_DMA_NOEXEC_IOMMU:
+			if (!iommu)
+				return 0;
+			return vfio_domains_have_iommu_cap(iommu,
+							   IOMMU_CAP_NOEXEC);
 		default:
 			return 0;
 		}
@@ -923,7 +945,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
 	} else if (cmd == VFIO_IOMMU_MAP_DMA) {
 		struct vfio_iommu_type1_dma_map map;
 		uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
-				VFIO_DMA_MAP_FLAG_WRITE;
+				VFIO_DMA_MAP_FLAG_WRITE |
+				VFIO_DMA_MAP_FLAG_NOEXEC;
 
 		minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
 
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag
  2014-10-13 13:09 ` [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
@ 2014-10-20 21:13   ` Alex Williamson
  2014-10-21 12:40     ` Antonios Motakis
  0 siblings, 1 reply; 14+ messages in thread
From: Alex Williamson @ 2014-10-20 21:13 UTC (permalink / raw)
  To: Antonios Motakis
  Cc: kvmarm, iommu, will.deacon, tech, christoffer.dall, eric.auger,
	kim.phillips, marc.zyngier, open list:VFIO DRIVER, open list

On Mon, 2014-10-13 at 15:09 +0200, Antonios Motakis wrote:
> Some IOMMU drivers, such as the ARM SMMU driver, make available the
> IOMMU_NOEXEC flag, to set the page tables for a device as XN (execute never).
> This affects devices such as the ARM PL330 DMA Controller, which respects
> this flag and will refuse to fetch DMA instructions from memory where the
> XN flag has been set.
> 
> The flag can be used only if all IOMMU domains behind the container support
> the IOMMU_NOEXEC flag. Also, if any mappings are created with the flag, any
> new domains with devices will have to support it as well.
> 
> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
> ---
>  drivers/vfio/vfio_iommu_type1.c | 25 ++++++++++++++++++++++++-
>  1 file changed, 24 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
> index 8b4202a..e225e8f 100644
> --- a/drivers/vfio/vfio_iommu_type1.c
> +++ b/drivers/vfio/vfio_iommu_type1.c
> @@ -569,6 +569,12 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>  	if (map->flags & VFIO_DMA_MAP_FLAG_READ)
>  		prot |= IOMMU_READ;
>  
> +	if (map->flags & VFIO_DMA_MAP_FLAG_NOEXEC) {
> +		if (!vfio_domains_have_iommu_cap(iommu, IOMMU_CAP_NOEXEC))
> +			return -EINVAL;
> +		prot |= IOMMU_NOEXEC;
> +	}
> +
>  	if (!prot || !size || (size | iova | vaddr) & mask)
>  		return -EINVAL;

I think this test needs to move above adding the NOEXEC flag, otherwise
we now allow mappings without read or write, which is an ABI change.

>  
> @@ -662,6 +668,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
>  		dma = rb_entry(n, struct vfio_dma, node);
>  		iova = dma->iova;
>  
> +		/*
> +		 * if any of the mappings to be replayed has the NOEXEC flag
> +		 * set, then the new iommu domain must support it
> +		 */
> +		if ((dma->prot | IOMMU_NOEXEC) &&

I think you mean

& IOMMU_NOEXEC

> +				!(domain->caps & IOMMU_CAP_NOEXEC))
> +			return -EINVAL;
> +

In patch 2/5 you stated:

        The IOMMU_NOEXEC flag needs to be available for all the IOMMUs
        of the container used.

But here you'll create heterogeneous containers so long as there are no
NOEXEC mappings.  Is that intentional or a side effect of the above
masking bug?

>  		while (iova < dma->iova + dma->size) {
>  			phys_addr_t phys = iommu_iova_to_phys(d->domain, iova);
>  			size_t size;
> @@ -749,6 +763,9 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
>  	if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
>  		domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
>  
> +	if (iommu_capable(bus, IOMMU_CAP_NOEXEC))
> +		domain->caps |= IOMMU_CAP_NOEXEC;
> +
>  	/*
>  	 * Try to match an existing compatible domain.  We don't want to
>  	 * preclude an IOMMU driver supporting multiple bus_types and being
> @@ -900,6 +917,11 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>  				return 0;
>  			return vfio_domains_have_iommu_cap(iommu,
>  						  IOMMU_CAP_CACHE_COHERENCY);
> +		case VFIO_DMA_NOEXEC_IOMMU:
> +			if (!iommu)
> +				return 0;
> +			return vfio_domains_have_iommu_cap(iommu,
> +							   IOMMU_CAP_NOEXEC);
>  		default:
>  			return 0;
>  		}
> @@ -923,7 +945,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>  	} else if (cmd == VFIO_IOMMU_MAP_DMA) {
>  		struct vfio_iommu_type1_dma_map map;
>  		uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
> -				VFIO_DMA_MAP_FLAG_WRITE;
> +				VFIO_DMA_MAP_FLAG_WRITE |
> +				VFIO_DMA_MAP_FLAG_NOEXEC;
>  
>  		minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
>  




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag
  2014-10-13 13:09 ` [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
@ 2014-10-20 21:29   ` Alex Williamson
  2014-10-21 12:17     ` Antonios Motakis
  2014-10-20 21:37   ` Andy Lutomirski
  1 sibling, 1 reply; 14+ messages in thread
From: Alex Williamson @ 2014-10-20 21:29 UTC (permalink / raw)
  To: Antonios Motakis
  Cc: kvmarm, iommu, will.deacon, tech, christoffer.dall, eric.auger,
	kim.phillips, marc.zyngier, open list:VFIO DRIVER,
	open list:ABI/API, open list

On Mon, 2014-10-13 at 15:09 +0200, Antonios Motakis wrote:
> We introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag to the VFIO dma map call,
> and expose its availability via the capability VFIO_DMA_NOEXEC_IOMMU.
> This way the user can control whether the XN flag will be set on the
> requested mappings. The IOMMU_NOEXEC flag needs to be available for all
> the IOMMUs of the container used.
> 
> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
> ---
>  include/uapi/linux/vfio.h | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
> index 6612974..111b5e8 100644
> --- a/include/uapi/linux/vfio.h
> +++ b/include/uapi/linux/vfio.h
> @@ -29,6 +29,7 @@
>   * capability is subject to change as groups are added or removed.
>   */
>  #define VFIO_DMA_CC_IOMMU		4
> +#define VFIO_DMA_NOEXEC_IOMMU		5
>  
>  /* Check if EEH is supported */
>  #define VFIO_EEH			5
                                    ^^
5 is still already used.  Feel free to convert to enum so we stop making
this mistake.

> @@ -401,6 +402,7 @@ struct vfio_iommu_type1_dma_map {
>  	__u32	flags;
>  #define VFIO_DMA_MAP_FLAG_READ (1 << 0)		/* readable from device */
>  #define VFIO_DMA_MAP_FLAG_WRITE (1 << 1)	/* writable from device */
> +#define VFIO_DMA_MAP_FLAG_NOEXEC (1 << 2)	/* not executable from device */
>  	__u64	vaddr;				/* Process virtual address */
>  	__u64	iova;				/* IO virtual address */
>  	__u64	size;				/* Size of mapping (bytes) */




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag
  2014-10-13 13:09 ` [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
  2014-10-20 21:29   ` Alex Williamson
@ 2014-10-20 21:37   ` Andy Lutomirski
  2014-10-21 12:23     ` Antonios Motakis
  1 sibling, 1 reply; 14+ messages in thread
From: Andy Lutomirski @ 2014-10-20 21:37 UTC (permalink / raw)
  To: Antonios Motakis
  Cc: kvmarm, iommu, Alex Williamson, Will Deacon, tech,
	christoffer.dall, eric.auger, kim.phillips, marc.zyngier,
	open list:VFIO DRIVER, open list:ABI/API, open list

On Mon, Oct 13, 2014 at 6:09 AM, Antonios Motakis
<a.motakis@virtualopensystems.com> wrote:
> We introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag to the VFIO dma map call,
> and expose its availability via the capability VFIO_DMA_NOEXEC_IOMMU.
> This way the user can control whether the XN flag will be set on the
> requested mappings. The IOMMU_NOEXEC flag needs to be available for all
> the IOMMUs of the container used.

Since you sent this to the linux-api list, I'll bite: what's the XN
flag?  I know what PROT_EXEC does when you mmap something, and I
presume that vfio is mmappable, but I don't actually have any clue
what this patch does.

I assume that this does not have anything to do with a non-CPU DMA
master executing code in main memory, because that makes rather little
sense.  (Or maybe it really does, in which case: weird.)

--Andy

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag
  2014-10-20 21:29   ` Alex Williamson
@ 2014-10-21 12:17     ` Antonios Motakis
  0 siblings, 0 replies; 14+ messages in thread
From: Antonios Motakis @ 2014-10-21 12:17 UTC (permalink / raw)
  To: Alex Williamson
  Cc: kvm-arm, Linux IOMMU, Will Deacon,
	VirtualOpenSystems Technical Team, Christoffer Dall, Eric Auger,
	Kim Phillips, Marc Zyngier, open list:VFIO DRIVER,
	open list:ABI/API, open list

On Mon, Oct 20, 2014 at 11:29 PM, Alex Williamson
<alex.williamson@redhat.com> wrote:
> On Mon, 2014-10-13 at 15:09 +0200, Antonios Motakis wrote:
>> We introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag to the VFIO dma map call,
>> and expose its availability via the capability VFIO_DMA_NOEXEC_IOMMU.
>> This way the user can control whether the XN flag will be set on the
>> requested mappings. The IOMMU_NOEXEC flag needs to be available for all
>> the IOMMUs of the container used.
>>
>> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
>> ---
>>  include/uapi/linux/vfio.h | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
>> index 6612974..111b5e8 100644
>> --- a/include/uapi/linux/vfio.h
>> +++ b/include/uapi/linux/vfio.h
>> @@ -29,6 +29,7 @@
>>   * capability is subject to change as groups are added or removed.
>>   */
>>  #define VFIO_DMA_CC_IOMMU            4
>> +#define VFIO_DMA_NOEXEC_IOMMU                5
>>
>>  /* Check if EEH is supported */
>>  #define VFIO_EEH                     5
>                                     ^^
> 5 is still already used.  Feel free to convert to enum so we stop making
> this mistake.

Oops :) will do.

>
>> @@ -401,6 +402,7 @@ struct vfio_iommu_type1_dma_map {
>>       __u32   flags;
>>  #define VFIO_DMA_MAP_FLAG_READ (1 << 0)              /* readable from device */
>>  #define VFIO_DMA_MAP_FLAG_WRITE (1 << 1)     /* writable from device */
>> +#define VFIO_DMA_MAP_FLAG_NOEXEC (1 << 2)    /* not executable from device */
>>       __u64   vaddr;                          /* Process virtual address */
>>       __u64   iova;                           /* IO virtual address */
>>       __u64   size;                           /* Size of mapping (bytes) */
>
>
>



-- 
Antonios Motakis
Virtual Open Systems

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag
  2014-10-20 21:37   ` Andy Lutomirski
@ 2014-10-21 12:23     ` Antonios Motakis
  0 siblings, 0 replies; 14+ messages in thread
From: Antonios Motakis @ 2014-10-21 12:23 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: kvm-arm, Linux IOMMU, Alex Williamson, Will Deacon,
	VirtualOpenSystems Technical Team, Christoffer Dall, Eric Auger,
	Kim Phillips, Marc Zyngier, open list:VFIO DRIVER,
	open list:ABI/API, open list

On Mon, Oct 20, 2014 at 11:37 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Mon, Oct 13, 2014 at 6:09 AM, Antonios Motakis
> <a.motakis@virtualopensystems.com> wrote:
>> We introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag to the VFIO dma map call,
>> and expose its availability via the capability VFIO_DMA_NOEXEC_IOMMU.
>> This way the user can control whether the XN flag will be set on the
>> requested mappings. The IOMMU_NOEXEC flag needs to be available for all
>> the IOMMUs of the container used.
>
> Since you sent this to the linux-api list, I'll bite: what's the XN
> flag?  I know what PROT_EXEC does when you mmap something, and I
> presume that vfio is mmappable, but I don't actually have any clue
> what this patch does.
>
> I assume that this does not have anything to do with a non-CPU DMA
> master executing code in main memory, because that makes rather little
> sense.  (Or maybe it really does, in which case: weird.)

It does actually. For example, the ARM PL330 DMA controller will fetch
from memory code with DMA instructions, and it will respect this flag.
It is not code that can be executed on the CPU of course, but it is
executable on the DMAC.


>
> --Andy



-- 
Antonios Motakis
Virtual Open Systems

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag
  2014-10-20 21:13   ` Alex Williamson
@ 2014-10-21 12:40     ` Antonios Motakis
  2014-10-21 14:37       ` Alex Williamson
  0 siblings, 1 reply; 14+ messages in thread
From: Antonios Motakis @ 2014-10-21 12:40 UTC (permalink / raw)
  To: Alex Williamson
  Cc: kvm-arm, Linux IOMMU, Will Deacon,
	VirtualOpenSystems Technical Team, Christoffer Dall, Eric Auger,
	Kim Phillips, Marc Zyngier, open list:VFIO DRIVER, open list

On Mon, Oct 20, 2014 at 11:13 PM, Alex Williamson
<alex.williamson@redhat.com> wrote:
> On Mon, 2014-10-13 at 15:09 +0200, Antonios Motakis wrote:
>> Some IOMMU drivers, such as the ARM SMMU driver, make available the
>> IOMMU_NOEXEC flag, to set the page tables for a device as XN (execute never).
>> This affects devices such as the ARM PL330 DMA Controller, which respects
>> this flag and will refuse to fetch DMA instructions from memory where the
>> XN flag has been set.
>>
>> The flag can be used only if all IOMMU domains behind the container support
>> the IOMMU_NOEXEC flag. Also, if any mappings are created with the flag, any
>> new domains with devices will have to support it as well.
>>
>> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
>> ---
>>  drivers/vfio/vfio_iommu_type1.c | 25 ++++++++++++++++++++++++-
>>  1 file changed, 24 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
>> index 8b4202a..e225e8f 100644
>> --- a/drivers/vfio/vfio_iommu_type1.c
>> +++ b/drivers/vfio/vfio_iommu_type1.c
>> @@ -569,6 +569,12 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>>       if (map->flags & VFIO_DMA_MAP_FLAG_READ)
>>               prot |= IOMMU_READ;
>>
>> +     if (map->flags & VFIO_DMA_MAP_FLAG_NOEXEC) {
>> +             if (!vfio_domains_have_iommu_cap(iommu, IOMMU_CAP_NOEXEC))
>> +                     return -EINVAL;
>> +             prot |= IOMMU_NOEXEC;
>> +     }
>> +
>>       if (!prot || !size || (size | iova | vaddr) & mask)
>>               return -EINVAL;
>
> I think this test needs to move above adding the NOEXEC flag, otherwise
> we now allow mappings without read or write, which is an ABI change.
>

Ack.

>>
>> @@ -662,6 +668,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
>>               dma = rb_entry(n, struct vfio_dma, node);
>>               iova = dma->iova;
>>
>> +             /*
>> +              * if any of the mappings to be replayed has the NOEXEC flag
>> +              * set, then the new iommu domain must support it
>> +              */
>> +             if ((dma->prot | IOMMU_NOEXEC) &&
>
> I think you mean
>
> & IOMMU_NOEXEC

Ack.

>
>> +                             !(domain->caps & IOMMU_CAP_NOEXEC))
>> +                     return -EINVAL;
>> +
>
> In patch 2/5 you stated:
>
>         The IOMMU_NOEXEC flag needs to be available for all the IOMMUs
>         of the container used.
>
> But here you'll create heterogeneous containers so long as there are no
> NOEXEC mappings.  Is that intentional or a side effect of the above
> masking bug?
>

Yeah, my intention was to not stop the user of having heterogeneous
containers, as long as he doesn't care about using the NOEXEC flag. As
soon as the user tries to apply this flag however, then it should be
supported by all the IOMMUs behind the container - otherwise it is not
enforceable.

Do you think we should change this behavior? I think most users will
not care about using this flag, and we should not stop them from
mixing containers.

>>               while (iova < dma->iova + dma->size) {
>>                       phys_addr_t phys = iommu_iova_to_phys(d->domain, iova);
>>                       size_t size;
>> @@ -749,6 +763,9 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
>>       if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
>>               domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
>>
>> +     if (iommu_capable(bus, IOMMU_CAP_NOEXEC))
>> +             domain->caps |= IOMMU_CAP_NOEXEC;
>> +
>>       /*
>>        * Try to match an existing compatible domain.  We don't want to
>>        * preclude an IOMMU driver supporting multiple bus_types and being
>> @@ -900,6 +917,11 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>>                               return 0;
>>                       return vfio_domains_have_iommu_cap(iommu,
>>                                                 IOMMU_CAP_CACHE_COHERENCY);
>> +             case VFIO_DMA_NOEXEC_IOMMU:
>> +                     if (!iommu)
>> +                             return 0;
>> +                     return vfio_domains_have_iommu_cap(iommu,
>> +                                                        IOMMU_CAP_NOEXEC);
>>               default:
>>                       return 0;
>>               }
>> @@ -923,7 +945,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>>       } else if (cmd == VFIO_IOMMU_MAP_DMA) {
>>               struct vfio_iommu_type1_dma_map map;
>>               uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
>> -                             VFIO_DMA_MAP_FLAG_WRITE;
>> +                             VFIO_DMA_MAP_FLAG_WRITE |
>> +                             VFIO_DMA_MAP_FLAG_NOEXEC;
>>
>>               minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
>>
>
>
>



-- 
Antonios Motakis
Virtual Open Systems

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag
  2014-10-21 12:40     ` Antonios Motakis
@ 2014-10-21 14:37       ` Alex Williamson
  2014-10-21 14:41         ` Antonios Motakis
  0 siblings, 1 reply; 14+ messages in thread
From: Alex Williamson @ 2014-10-21 14:37 UTC (permalink / raw)
  To: Antonios Motakis
  Cc: kvm-arm, Linux IOMMU, Will Deacon,
	VirtualOpenSystems Technical Team, Christoffer Dall, Eric Auger,
	Kim Phillips, Marc Zyngier, open list:VFIO DRIVER, open list

On Tue, 2014-10-21 at 14:40 +0200, Antonios Motakis wrote:
> On Mon, Oct 20, 2014 at 11:13 PM, Alex Williamson
> <alex.williamson@redhat.com> wrote:
> > On Mon, 2014-10-13 at 15:09 +0200, Antonios Motakis wrote:
> >> Some IOMMU drivers, such as the ARM SMMU driver, make available the
> >> IOMMU_NOEXEC flag, to set the page tables for a device as XN (execute never).
> >> This affects devices such as the ARM PL330 DMA Controller, which respects
> >> this flag and will refuse to fetch DMA instructions from memory where the
> >> XN flag has been set.
> >>
> >> The flag can be used only if all IOMMU domains behind the container support
> >> the IOMMU_NOEXEC flag. Also, if any mappings are created with the flag, any
> >> new domains with devices will have to support it as well.
> >>
> >> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
> >> ---
> >>  drivers/vfio/vfio_iommu_type1.c | 25 ++++++++++++++++++++++++-
> >>  1 file changed, 24 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
> >> index 8b4202a..e225e8f 100644
> >> --- a/drivers/vfio/vfio_iommu_type1.c
> >> +++ b/drivers/vfio/vfio_iommu_type1.c
> >> @@ -569,6 +569,12 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
> >>       if (map->flags & VFIO_DMA_MAP_FLAG_READ)
> >>               prot |= IOMMU_READ;
> >>
> >> +     if (map->flags & VFIO_DMA_MAP_FLAG_NOEXEC) {
> >> +             if (!vfio_domains_have_iommu_cap(iommu, IOMMU_CAP_NOEXEC))
> >> +                     return -EINVAL;
> >> +             prot |= IOMMU_NOEXEC;
> >> +     }
> >> +
> >>       if (!prot || !size || (size | iova | vaddr) & mask)
> >>               return -EINVAL;
> >
> > I think this test needs to move above adding the NOEXEC flag, otherwise
> > we now allow mappings without read or write, which is an ABI change.
> >
> 
> Ack.
> 
> >>
> >> @@ -662,6 +668,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
> >>               dma = rb_entry(n, struct vfio_dma, node);
> >>               iova = dma->iova;
> >>
> >> +             /*
> >> +              * if any of the mappings to be replayed has the NOEXEC flag
> >> +              * set, then the new iommu domain must support it
> >> +              */
> >> +             if ((dma->prot | IOMMU_NOEXEC) &&
> >
> > I think you mean
> >
> > & IOMMU_NOEXEC
> 
> Ack.
> 
> >
> >> +                             !(domain->caps & IOMMU_CAP_NOEXEC))
> >> +                     return -EINVAL;
> >> +
> >
> > In patch 2/5 you stated:
> >
> >         The IOMMU_NOEXEC flag needs to be available for all the IOMMUs
> >         of the container used.
> >
> > But here you'll create heterogeneous containers so long as there are no
> > NOEXEC mappings.  Is that intentional or a side effect of the above
> > masking bug?
> >
> 
> Yeah, my intention was to not stop the user of having heterogeneous
> containers, as long as he doesn't care about using the NOEXEC flag. As
> soon as the user tries to apply this flag however, then it should be
> supported by all the IOMMUs behind the container - otherwise it is not
> enforceable.
> 
> Do you think we should change this behavior? I think most users will
> not care about using this flag, and we should not stop them from
> mixing containers.

I think that's a reasonable way to go, but let's add a comment in uapi
vfio.h describing that expectation.  Thanks,

Alex

> >>               while (iova < dma->iova + dma->size) {
> >>                       phys_addr_t phys = iommu_iova_to_phys(d->domain, iova);
> >>                       size_t size;
> >> @@ -749,6 +763,9 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
> >>       if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
> >>               domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
> >>
> >> +     if (iommu_capable(bus, IOMMU_CAP_NOEXEC))
> >> +             domain->caps |= IOMMU_CAP_NOEXEC;
> >> +
> >>       /*
> >>        * Try to match an existing compatible domain.  We don't want to
> >>        * preclude an IOMMU driver supporting multiple bus_types and being
> >> @@ -900,6 +917,11 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
> >>                               return 0;
> >>                       return vfio_domains_have_iommu_cap(iommu,
> >>                                                 IOMMU_CAP_CACHE_COHERENCY);
> >> +             case VFIO_DMA_NOEXEC_IOMMU:
> >> +                     if (!iommu)
> >> +                             return 0;
> >> +                     return vfio_domains_have_iommu_cap(iommu,
> >> +                                                        IOMMU_CAP_NOEXEC);
> >>               default:
> >>                       return 0;
> >>               }
> >> @@ -923,7 +945,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
> >>       } else if (cmd == VFIO_IOMMU_MAP_DMA) {
> >>               struct vfio_iommu_type1_dma_map map;
> >>               uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
> >> -                             VFIO_DMA_MAP_FLAG_WRITE;
> >> +                             VFIO_DMA_MAP_FLAG_WRITE |
> >> +                             VFIO_DMA_MAP_FLAG_NOEXEC;
> >>
> >>               minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
> >>
> >
> >
> >
> 
> 
> 




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag
  2014-10-21 14:37       ` Alex Williamson
@ 2014-10-21 14:41         ` Antonios Motakis
  0 siblings, 0 replies; 14+ messages in thread
From: Antonios Motakis @ 2014-10-21 14:41 UTC (permalink / raw)
  To: Alex Williamson
  Cc: kvm-arm, Linux IOMMU, Will Deacon,
	VirtualOpenSystems Technical Team, Christoffer Dall, Eric Auger,
	Kim Phillips, Marc Zyngier, open list:VFIO DRIVER, open list

On Tue, Oct 21, 2014 at 4:37 PM, Alex Williamson
<alex.williamson@redhat.com> wrote:
> On Tue, 2014-10-21 at 14:40 +0200, Antonios Motakis wrote:
>> On Mon, Oct 20, 2014 at 11:13 PM, Alex Williamson
>> <alex.williamson@redhat.com> wrote:
>> > On Mon, 2014-10-13 at 15:09 +0200, Antonios Motakis wrote:
>> >> Some IOMMU drivers, such as the ARM SMMU driver, make available the
>> >> IOMMU_NOEXEC flag, to set the page tables for a device as XN (execute never).
>> >> This affects devices such as the ARM PL330 DMA Controller, which respects
>> >> this flag and will refuse to fetch DMA instructions from memory where the
>> >> XN flag has been set.
>> >>
>> >> The flag can be used only if all IOMMU domains behind the container support
>> >> the IOMMU_NOEXEC flag. Also, if any mappings are created with the flag, any
>> >> new domains with devices will have to support it as well.
>> >>
>> >> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
>> >> ---
>> >>  drivers/vfio/vfio_iommu_type1.c | 25 ++++++++++++++++++++++++-
>> >>  1 file changed, 24 insertions(+), 1 deletion(-)
>> >>
>> >> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
>> >> index 8b4202a..e225e8f 100644
>> >> --- a/drivers/vfio/vfio_iommu_type1.c
>> >> +++ b/drivers/vfio/vfio_iommu_type1.c
>> >> @@ -569,6 +569,12 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
>> >>       if (map->flags & VFIO_DMA_MAP_FLAG_READ)
>> >>               prot |= IOMMU_READ;
>> >>
>> >> +     if (map->flags & VFIO_DMA_MAP_FLAG_NOEXEC) {
>> >> +             if (!vfio_domains_have_iommu_cap(iommu, IOMMU_CAP_NOEXEC))
>> >> +                     return -EINVAL;
>> >> +             prot |= IOMMU_NOEXEC;
>> >> +     }
>> >> +
>> >>       if (!prot || !size || (size | iova | vaddr) & mask)
>> >>               return -EINVAL;
>> >
>> > I think this test needs to move above adding the NOEXEC flag, otherwise
>> > we now allow mappings without read or write, which is an ABI change.
>> >
>>
>> Ack.
>>
>> >>
>> >> @@ -662,6 +668,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
>> >>               dma = rb_entry(n, struct vfio_dma, node);
>> >>               iova = dma->iova;
>> >>
>> >> +             /*
>> >> +              * if any of the mappings to be replayed has the NOEXEC flag
>> >> +              * set, then the new iommu domain must support it
>> >> +              */
>> >> +             if ((dma->prot | IOMMU_NOEXEC) &&
>> >
>> > I think you mean
>> >
>> > & IOMMU_NOEXEC
>>
>> Ack.
>>
>> >
>> >> +                             !(domain->caps & IOMMU_CAP_NOEXEC))
>> >> +                     return -EINVAL;
>> >> +
>> >
>> > In patch 2/5 you stated:
>> >
>> >         The IOMMU_NOEXEC flag needs to be available for all the IOMMUs
>> >         of the container used.
>> >
>> > But here you'll create heterogeneous containers so long as there are no
>> > NOEXEC mappings.  Is that intentional or a side effect of the above
>> > masking bug?
>> >
>>
>> Yeah, my intention was to not stop the user of having heterogeneous
>> containers, as long as he doesn't care about using the NOEXEC flag. As
>> soon as the user tries to apply this flag however, then it should be
>> supported by all the IOMMUs behind the container - otherwise it is not
>> enforceable.
>>
>> Do you think we should change this behavior? I think most users will
>> not care about using this flag, and we should not stop them from
>> mixing containers.
>
> I think that's a reasonable way to go, but let's add a comment in uapi
> vfio.h describing that expectation.  Thanks,

Ok, will do.

>
> Alex
>
>> >>               while (iova < dma->iova + dma->size) {
>> >>                       phys_addr_t phys = iommu_iova_to_phys(d->domain, iova);
>> >>                       size_t size;
>> >> @@ -749,6 +763,9 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
>> >>       if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
>> >>               domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
>> >>
>> >> +     if (iommu_capable(bus, IOMMU_CAP_NOEXEC))
>> >> +             domain->caps |= IOMMU_CAP_NOEXEC;
>> >> +
>> >>       /*
>> >>        * Try to match an existing compatible domain.  We don't want to
>> >>        * preclude an IOMMU driver supporting multiple bus_types and being
>> >> @@ -900,6 +917,11 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>> >>                               return 0;
>> >>                       return vfio_domains_have_iommu_cap(iommu,
>> >>                                                 IOMMU_CAP_CACHE_COHERENCY);
>> >> +             case VFIO_DMA_NOEXEC_IOMMU:
>> >> +                     if (!iommu)
>> >> +                             return 0;
>> >> +                     return vfio_domains_have_iommu_cap(iommu,
>> >> +                                                        IOMMU_CAP_NOEXEC);
>> >>               default:
>> >>                       return 0;
>> >>               }
>> >> @@ -923,7 +945,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
>> >>       } else if (cmd == VFIO_IOMMU_MAP_DMA) {
>> >>               struct vfio_iommu_type1_dma_map map;
>> >>               uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
>> >> -                             VFIO_DMA_MAP_FLAG_WRITE;
>> >> +                             VFIO_DMA_MAP_FLAG_WRITE |
>> >> +                             VFIO_DMA_MAP_FLAG_NOEXEC;
>> >>
>> >>               minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
>> >>
>> >
>> >
>> >
>>
>>
>>
>
>
>



-- 
Antonios Motakis
Virtual Open Systems

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/5] vfio: type1: replace domain wide protection flags with supported capabilities
       [not found]   ` <5447742A.8070705@linaro.org>
@ 2014-10-22 13:57     ` Antonios Motakis
  0 siblings, 0 replies; 14+ messages in thread
From: Antonios Motakis @ 2014-10-22 13:57 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm-arm, Linux IOMMU, Alex Williamson, Will Deacon,
	VirtualOpenSystems Technical Team, Christoffer Dall,
	Kim Phillips, Marc Zyngier,
	open list:VFIO DRIVER <kvm@vger.kernel.org>,
	open list

On Wed, Oct 22, 2014 at 11:08 AM, Eric Auger <eric.auger@linaro.org> wrote:
> On 10/13/2014 03:09 PM, Antonios Motakis wrote:
>> VFIO_IOMMU_TYPE1 keeps track for each domain it knows a list of protection
>> flags it always applies to all mappings in the domain. This is used for
>> domains that support IOMMU_CAP_CACHE_COHERENCY.
>>
>> Refactor this slightly, by keeping track instead that a given domain
>> supports the capability, and applying the IOMMU_CACHE protection flag when
>> doing the actual DMA mappings.
>>
>> This will allow us to reuse the behavior for IOMMU_CAP_NOEXEC, which we
>> also want to keep track of, but without applying it to all domains that
>> support it unless the user explicitly requests it.
>>
>> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
>> ---
>>  drivers/vfio/vfio_iommu_type1.c | 25 +++++++++++++++++--------
>>  1 file changed, 17 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
>> index 562f686..62a8b4d 100644
>> --- a/drivers/vfio/vfio_iommu_type1.c
>> +++ b/drivers/vfio/vfio_iommu_type1.c
>> @@ -64,7 +64,7 @@ struct vfio_domain {
>>       struct iommu_domain     *domain;
>>       struct list_head        next;
>>       struct list_head        group_list;
>> -     int                     prot;           /* IOMMU_CACHE */
>> +     int                     caps;
>>  };
>>
>>  struct vfio_dma {
>> @@ -485,7 +485,7 @@ static int map_try_harder(struct vfio_domain *domain, dma_addr_t iova,
>>       for (i = 0; i < npage; i++, pfn++, iova += PAGE_SIZE) {
>>               ret = iommu_map(domain->domain, iova,
>>                               (phys_addr_t)pfn << PAGE_SHIFT,
>> -                             PAGE_SIZE, prot | domain->prot);
>> +                             PAGE_SIZE, prot);
>>               if (ret)
>>                       break;
>>       }
>> @@ -503,11 +503,16 @@ static int vfio_iommu_map(struct vfio_iommu *iommu, dma_addr_t iova,
>>       int ret;
>>
>>       list_for_each_entry(d, &iommu->domain_list, next) {
>> +             int dprot = prot;
>> +
>> +             if (d->caps | IOMMU_CAP_CACHE_COHERENCY)
> should be &
>> +                     dprot |= IOMMU_CACHE;
>> +
>>               ret = iommu_map(d->domain, iova, (phys_addr_t)pfn << PAGE_SHIFT,
>> -                             npage << PAGE_SHIFT, prot | d->prot);
>> +                             npage << PAGE_SHIFT, dprot);
>>               if (ret) {
>>                       if (ret != -EBUSY ||
>> -                         map_try_harder(d, iova, pfn, npage, prot))
>> +                         map_try_harder(d, iova, pfn, npage, dprot))
>>                               goto unwind;
>>               }
>>       }
>> @@ -620,6 +625,10 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
>>       struct vfio_domain *d;
>>       struct rb_node *n;
>>       int ret;
>> +     int dprot = 0;
>> +
>> +     if (domain->caps | IOMMU_CAP_CACHE_COHERENCY)
> same to be fixed here.
>
> With the 3 "|" corrections and "num--" fix in get_platform_resource, v8
> is functional with Calxeda xgmac QEMU VFIO device.
>

Ack.

> Best Regards
>
> Eric
>> +             dprot |= IOMMU_CACHE;
>>
>>       /* Arbitrarily pick the first domain in the list for lookups */
>>       d = list_first_entry(&iommu->domain_list, struct vfio_domain, next);
>> @@ -653,7 +662,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
>>                               size += PAGE_SIZE;
>>
>>                       ret = iommu_map(domain->domain, iova, phys,
>> -                                     size, dma->prot | domain->prot);
>> +                                     size, dma->prot | dprot);
>>                       if (ret)
>>                               return ret;
>>
>> @@ -721,7 +730,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
>>       }
>>
>>       if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
>> -             domain->prot |= IOMMU_CACHE;
>> +             domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
>>
>>       /*
>>        * Try to match an existing compatible domain.  We don't want to
>> @@ -732,7 +741,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
>>        */
>>       list_for_each_entry(d, &iommu->domain_list, next) {
>>               if (d->domain->ops == domain->domain->ops &&
>> -                 d->prot == domain->prot) {
>> +                 d->caps == domain->caps) {
>>                       iommu_detach_group(domain->domain, iommu_group);
>>                       if (!iommu_attach_group(d->domain, iommu_group)) {
>>                               list_add(&group->next, &d->group_list);
>> @@ -865,7 +874,7 @@ static int vfio_domains_have_iommu_cache(struct vfio_iommu *iommu)
>>
>>       mutex_lock(&iommu->lock);
>>       list_for_each_entry(domain, &iommu->domain_list, next) {
>> -             if (!(domain->prot & IOMMU_CACHE)) {
>> +             if (!(domain->caps & IOMMU_CAP_CACHE_COHERENCY)) {
>>                       ret = 0;
>>                       break;
>>               }
>>
>



-- 
Antonios Motakis
Virtual Open Systems

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2014-10-22 14:00 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1413205748-6300-1-git-send-email-a.motakis@virtualopensystems.com>
2014-10-13 13:09 ` [PATCH 1/5] vfio/iommu_type1: support for platform bus devices on ARM Antonios Motakis
2014-10-13 13:09 ` [PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
2014-10-20 21:29   ` Alex Williamson
2014-10-21 12:17     ` Antonios Motakis
2014-10-20 21:37   ` Andy Lutomirski
2014-10-21 12:23     ` Antonios Motakis
2014-10-13 13:09 ` [PATCH 3/5] vfio: type1: replace domain wide protection flags with supported capabilities Antonios Motakis
     [not found]   ` <5447742A.8070705@linaro.org>
2014-10-22 13:57     ` Antonios Motakis
2014-10-13 13:09 ` [PATCH 4/5] vfio: type1: replace vfio_domains_have_iommu_cache with generic function Antonios Motakis
2014-10-13 13:09 ` [PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag Antonios Motakis
2014-10-20 21:13   ` Alex Williamson
2014-10-21 12:40     ` Antonios Motakis
2014-10-21 14:37       ` Alex Williamson
2014-10-21 14:41         ` Antonios Motakis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).