All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paul Durrant <paul.durrant@citrix.com>
To: xen-devel@lists.xenproject.org
Cc: Stefano Stabellini <sstabellini@kernel.org>,
	Wei Liu <wei.liu2@citrix.com>,
	George Dunlap <George.Dunlap@eu.citrix.com>,
	Andrew Cooper <andrew.cooper3@citrix.com>,
	Ian Jackson <ian.jackson@eu.citrix.com>, Tim Deegan <tim@xen.org>,
	Julien Grall <julien.grall@arm.com>,
	Paul Durrant <paul.durrant@citrix.com>,
	Jan Beulich <jbeulich@suse.com>
Subject: [PATCH v6 14/14] x86: extend the map and unmap iommu_ops to support grant references
Date: Thu, 23 Aug 2018 10:47:11 +0100	[thread overview]
Message-ID: <20180823094711.21376-15-paul.durrant@citrix.com> (raw)
In-Reply-To: <20180823094711.21376-1-paul.durrant@citrix.com>

This patch allows a domain to add or remove foreign frames from its
IOMMU mappings by grant reference as well as GFN. This is necessary,
for example, to support a PV network backend that needs to construct a
packet buffer that can be directly accessed by a NIC.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
---
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: George Dunlap <George.Dunlap@eu.citrix.com>
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Julien Grall <julien.grall@arm.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Tim Deegan <tim@xen.org>
Cc: Wei Liu <wei.liu2@citrix.com>

v6:
 - Re-base.

v2:
 - New in v2.
---
 xen/common/grant_table.c      | 143 ++++++++++++++++++++++++++++++++++++++++++
 xen/common/iommu_op.c         |  83 ++++++++++++++++--------
 xen/include/public/iommu_op.h |  29 +++++++--
 xen/include/xen/grant_table.h |   7 +++
 4 files changed, 232 insertions(+), 30 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index f3b2fad7a8..01a95c05ed 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -3961,6 +3961,149 @@ int gnttab_get_status_frame(struct domain *d, unsigned long idx,
     return rc;
 }
 
+int
+acquire_gref_for_iommu(struct domain *d, grant_ref_t gref,
+                       bool readonly, mfn_t *mfn)
+{
+    struct domain *currd = current->domain;
+    struct grant_table *gt = d->grant_table;
+    grant_entry_header_t *shah;
+    struct active_grant_entry *act;
+    uint16_t *status;
+    int rc;
+
+    grant_read_lock(gt);
+
+    rc = -ENOENT;
+    if ( gref > nr_grant_entries(gt) )
+        goto unlock;
+
+    act = active_entry_acquire(gt, gref);
+    shah = shared_entry_header(gt, gref);
+    status = ( gt->gt_version == 2 ) ?
+        &status_entry(gt, gref) :
+        &shah->flags;
+
+    rc = -EACCES;
+    if ( (shah->flags & GTF_type_mask) != GTF_permit_access ||
+         (shah->flags & GTF_sub_page) )
+        goto release;
+
+    rc = -ERANGE;
+    if ( act->pin && ((act->domid != currd->domain_id) ||
+                      (act->pin & 0x80808080U) != 0) )
+        goto release;
+
+    rc = -EINVAL;
+    if ( !act->pin ||
+         (!readonly && !(act->pin & GNTPIN_devw_mask)) ) {
+        if ( _set_status(gt->gt_version, currd->domain_id, readonly,
+                         0, shah, act, status) != GNTST_okay )
+            goto release;
+    }
+
+    if ( !act->pin )
+    {
+        gfn_t gfn = gt->gt_version == 1 ?
+            _gfn(shared_entry_v1(gt, gref).frame) :
+            _gfn(shared_entry_v2(gt, gref).full_page.frame);
+        struct page_info *page;
+
+        rc =  get_paged_gfn(d, gfn, readonly, NULL, &page);
+        if ( rc )
+            goto clear;
+
+        act_set_gfn(act, gfn);
+        act->mfn = page_to_mfn(page);
+        act->domid = currd->domain_id;
+        act->start = 0;
+        act->length = PAGE_SIZE;
+        act->is_sub_page = false;
+        act->trans_domain = d;
+        act->trans_gref = gref;
+    }
+    else
+    {
+        ASSERT(mfn_valid(act->mfn));
+        if ( !get_page(mfn_to_page(act->mfn), d) )
+            goto clear;
+    }
+
+    rc = 0;
+    act->pin += readonly ? GNTPIN_devr_inc : GNTPIN_devw_inc;
+    *mfn = act->mfn;
+    goto release;
+
+ clear:
+    if ( !readonly && !(act->pin & GNTPIN_devw_mask) )
+        gnttab_clear_flag(_GTF_writing, status);
+
+    if ( !act->pin )
+        gnttab_clear_flag(_GTF_reading, status);
+
+ release:
+    active_entry_release(act);
+
+ unlock:
+    grant_read_unlock(gt);
+
+    return rc;
+}
+
+int
+release_gref_for_iommu(struct domain *d, grant_ref_t gref,
+                       bool readonly, mfn_t mfn)
+{
+    struct domain *currd = current->domain;
+    struct grant_table *gt = d->grant_table;
+    grant_entry_header_t *shah;
+    struct active_grant_entry *act;
+    uint16_t *status;
+    int rc;
+
+    grant_read_lock(gt);
+
+    rc = -ENOENT;
+    if ( gref > nr_grant_entries(gt) )
+        goto unlock;
+
+    act = active_entry_acquire(gt, gref);
+    shah = shared_entry_header(gt, gref);
+    status = ( gt->gt_version == 2 ) ?
+        &status_entry(gt, gref) :
+        &shah->flags;
+
+    rc = -EINVAL;
+    if ( !act->pin || (act->domid != currd->domain_id) ||
+         !mfn_eq(act->mfn, mfn) )
+        goto release;
+
+    rc = 0;
+    if ( readonly )
+        act->pin -= GNTPIN_devr_inc;
+    else
+    {
+        gnttab_mark_dirty(d, mfn);
+
+        act->pin -= GNTPIN_devw_inc;
+        if ( !(act->pin & GNTPIN_devw_mask) )
+            gnttab_clear_flag(_GTF_writing, status);
+    }
+
+    if ( !act->pin )
+        gnttab_clear_flag(_GTF_reading, status);
+
+    put_page(mfn_to_page(mfn));
+
+ release:
+    active_entry_release(act);
+
+ unlock:
+    grant_read_unlock(gt);
+
+    return rc;
+}
+
 static void gnttab_usage_print(struct domain *rd)
 {
     int first = 1;
diff --git a/xen/common/iommu_op.c b/xen/common/iommu_op.c
index 328522f245..272f53298f 100644
--- a/xen/common/iommu_op.c
+++ b/xen/common/iommu_op.c
@@ -23,6 +23,7 @@
 #include <xen/guest_access.h>
 #include <xen/hypercall.h>
 #include <xen/nospec.h>
+#include <xen/grant_table.h>
 
 struct get_reserved_ctxt {
     unsigned int max_entries;
@@ -130,12 +131,14 @@ static int iommuop_map(struct xen_iommu_op_map *op)
     bool readonly = op->flags & XEN_IOMMUOP_map_readonly;
     bfn_t bfn = _bfn(op->bfn);
     struct page_info *page;
+    mfn_t mfn;
     unsigned int prot;
     int rc, ignore;
 
     if ( op->pad ||
          (op->flags & ~(XEN_IOMMUOP_map_all |
-                        XEN_IOMMUOP_map_readonly)) )
+                        XEN_IOMMUOP_map_readonly |
+                        XEN_IOMMUOP_map_gref)) )
         return -EINVAL;
 
     if ( !iommu->iommu_op_ranges )
@@ -153,15 +156,28 @@ static int iommuop_map(struct xen_iommu_op_map *op)
     if ( !d )
         return -ESRCH;
 
-    rc = get_paged_gfn(d, _gfn(op->gfn), readonly, NULL, &page);
-    if ( rc )
-        goto unlock;
+    if ( op->flags & XEN_IOMMUOP_map_gref )
+    {
+        rc = acquire_gref_for_iommu(d, op->u.gref, readonly, &mfn);
+        if ( rc )
+            goto unlock;
 
-    rc = -EINVAL;
-    if ( !readonly && !get_page_type(page, PGT_writable_page) )
+        page = mfn_to_page(mfn);
+    }
+    else
     {
-        put_page(page);
-        goto unlock;
+        rc = get_paged_gfn(d, _gfn(op->u.gfn), readonly, NULL, &page);
+        if ( rc )
+            goto unlock;
+
+        rc = -EINVAL;
+        if ( !readonly && !get_page_type(page, PGT_writable_page) )
+        {
+            put_page(page);
+            goto unlock;
+        }
+
+        mfn = page_to_mfn(page);
     }
 
     prot = IOMMUF_readable;
@@ -169,7 +185,7 @@ static int iommuop_map(struct xen_iommu_op_map *op)
         prot |= IOMMUF_writable;
 
     rc = -EIO;
-    if ( iommu_map_page(currd, bfn, page_to_mfn(page), prot) )
+    if ( iommu_map_page(currd, bfn, mfn, prot) )
         goto release;
 
     rc = rangeset_add_singleton(iommu->iommu_op_ranges, bfn_x(bfn));
@@ -183,9 +199,14 @@ static int iommuop_map(struct xen_iommu_op_map *op)
     ignore = iommu_unmap_page(currd, bfn);
 
  release:
-    if ( !readonly )
-        put_page_type(page);
-    put_page(page);
+    if ( op->flags & XEN_IOMMUOP_map_gref )
+        release_gref_for_iommu(d, op->u.gref, readonly, mfn);
+    else
+    {
+        if ( !readonly )
+            put_page_type(page);
+        put_page(page);
+    }
 
  unlock:
     rcu_unlock_domain(d);
@@ -200,11 +221,11 @@ static int iommuop_unmap(struct xen_iommu_op_unmap *op)
     mfn_t mfn;
     bool readonly;
     unsigned int prot;
-    struct page_info *page;
     int rc;
 
     if ( op->pad ||
-         (op->flags & ~XEN_IOMMUOP_unmap_all) )
+         (op->flags & ~(XEN_IOMMUOP_unmap_all |
+                        XEN_IOMMUOP_unmap_gref)) )
         return -EINVAL;
 
     if ( !iommu->iommu_op_ranges )
@@ -225,21 +246,31 @@ static int iommuop_unmap(struct xen_iommu_op_unmap *op)
     if ( !d )
         return -ESRCH;
 
-    rc = get_paged_gfn(d, _gfn(op->gfn), !(prot & IOMMUF_writable), NULL,
-                       &page);
-    if ( rc )
-        goto unlock;
+    if ( op->flags & XEN_IOMMUOP_unmap_gref )
+    {
+        rc = release_gref_for_iommu(d, op->u.gref, readonly, mfn);
+        if ( rc )
+            goto unlock;
+    }
+    else
+    {
+        struct page_info *page;
 
-    put_page(page); /* release extra reference just taken */
+        rc = get_paged_gfn(d, _gfn(op->u.gfn), readonly, NULL, &page);
+        if ( rc )
+            goto unlock;
 
-    rc = -EINVAL;
-    if ( !mfn_eq(page_to_mfn(page), mfn) )
-        goto unlock;
+        put_page(page); /* release extra reference just taken */
 
-    /* release reference taken in map */
-    if ( !readonly )
-        put_page_type(page);
-    put_page(page);
+        rc = -EINVAL;
+        if ( !mfn_eq(page_to_mfn(page), mfn) )
+            goto unlock;
+
+        /* release reference taken in map */
+        if ( !readonly )
+            put_page_type(page);
+        put_page(page);
+    }
 
     rc = rangeset_remove_singleton(iommu->iommu_op_ranges, bfn_x(bfn));
     if ( rc )
diff --git a/xen/include/public/iommu_op.h b/xen/include/public/iommu_op.h
index e6c08f4bdd..e3d702a8d0 100644
--- a/xen/include/public/iommu_op.h
+++ b/xen/include/public/iommu_op.h
@@ -24,6 +24,7 @@
 #define XEN_PUBLIC_IOMMU_OP_H
 
 #include "xen.h"
+#include "grant_table.h"
 
 typedef uint64_t xen_bfn_t;
 
@@ -107,6 +108,10 @@ struct xen_iommu_op_map {
 #define _XEN_IOMMUOP_map_readonly 1
 #define XEN_IOMMUOP_map_readonly (1 << (_XEN_IOMMUOP_map_readonly))
 
+    /* Is the memory specified by gfn or grant reference? */
+#define _XEN_IOMMUOP_map_gref 2
+#define XEN_IOMMUOP_map_gref (1 << (_XEN_IOMMUOP_map_gref))
+
     uint32_t pad;
     /*
      * IN - Segment/Bus/Device/Function of the initiator.
@@ -116,8 +121,14 @@ struct xen_iommu_op_map {
     uint64_t sbdf;
     /* IN - The IOMMU frame number which will hold the new mapping */
     xen_bfn_t bfn;
-    /* IN - The guest frame number of the page to be mapped */
-    xen_pfn_t gfn;
+    /*
+     * IN - The guest frame number or grant reference of the page to
+     * be mapped.
+     */
+    union {
+        xen_pfn_t gfn;
+        grant_ref_t gref;
+    } u;
 };
 
 /*
@@ -143,6 +154,10 @@ struct xen_iommu_op_unmap {
 #define _XEN_IOMMUOP_unmap_all 0
 #define XEN_IOMMUOP_unmap_all (1 << (_XEN_IOMMUOP_unmap_all))
 
+    /* Is the memory specified by gfn or grant reference? */
+#define _XEN_IOMMUOP_unmap_gref 1
+#define XEN_IOMMUOP_unmap_gref (1 << (_XEN_IOMMUOP_unmap_gref))
+
     uint32_t pad;
     /*
      * IN - Segment/Bus/Device/Function of the initiator.
@@ -152,8 +167,14 @@ struct xen_iommu_op_unmap {
     uint64_t sbdf;
     /* IN - The IOMMU frame number which holds the mapping to be removed */
     xen_bfn_t bfn;
-    /* IN - The guest frame number of the page that is mapped */
-    xen_pfn_t gfn;
+    /*
+     * IN - The guest frame number or grant reference of the page that
+     * is mapped.
+     */
+    union {
+        xen_pfn_t gfn;
+        grant_ref_t gref;
+    } u;
 };
 
 /*
diff --git a/xen/include/xen/grant_table.h b/xen/include/xen/grant_table.h
index c881414e5b..35afb27202 100644
--- a/xen/include/xen/grant_table.h
+++ b/xen/include/xen/grant_table.h
@@ -63,6 +63,13 @@ int gnttab_get_shared_frame(struct domain *d, unsigned long idx,
 int gnttab_get_status_frame(struct domain *d, unsigned long idx,
                             mfn_t *mfn);
 
+int
+acquire_gref_for_iommu(struct domain *d, grant_ref_t gref,
+                       bool readonly, mfn_t *mfn);
+int
+release_gref_for_iommu(struct domain *d, grant_ref_t gref,
+                       bool readonly, mfn_t mfn);
+
 unsigned int gnttab_dom0_frames(void);
 
 #endif /* __XEN_GRANT_TABLE_H__ */
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

  parent reply	other threads:[~2018-08-23  9:58 UTC|newest]

Thread overview: 111+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-23  9:46 [PATCH v6 00/14] paravirtual IOMMU interface Paul Durrant
2018-08-23  9:46 ` [PATCH v6 01/14] iommu: introduce the concept of BFN Paul Durrant
2018-08-30 15:59   ` Jan Beulich
2018-09-03  8:23     ` Paul Durrant
2018-09-03 11:46       ` Jan Beulich
2018-09-04  6:48         ` Tian, Kevin
2018-09-04  8:32           ` Jan Beulich
2018-09-04  8:37             ` Tian, Kevin
2018-09-04  8:47               ` Jan Beulich
2018-09-04  8:49                 ` Paul Durrant
2018-09-04  9:08                   ` Jan Beulich
2018-09-05  0:42                     ` Tian, Kevin
2018-09-05  6:48                       ` Jan Beulich
2018-09-05  6:56                         ` Tian, Kevin
2018-09-05  7:11                           ` Jan Beulich
2018-09-05  9:13                             ` Paul Durrant
2018-09-05  9:38                               ` Jan Beulich
2018-09-06 10:36                                 ` Paul Durrant
2018-09-06 13:13                                   ` Jan Beulich
2018-09-06 14:54                                     ` Paul Durrant
2018-09-07  1:47                                       ` Tian, Kevin
2018-09-07  6:24                                         ` Jan Beulich
2018-09-07  8:13                                           ` Paul Durrant
2018-09-07  8:16                                             ` Tian, Kevin
2018-09-07  8:25                                               ` Paul Durrant
2018-08-23  9:46 ` [PATCH v6 02/14] iommu: make use of type-safe BFN and MFN in exported functions Paul Durrant
2018-09-04 10:29   ` Jan Beulich
2018-08-23  9:47 ` [PATCH v6 03/14] iommu: push use of type-safe BFN and MFN into iommu_ops Paul Durrant
2018-09-04 10:32   ` Jan Beulich
2018-08-23  9:47 ` [PATCH v6 04/14] iommu: don't domain_crash() inside iommu_map/unmap_page() Paul Durrant
2018-09-04 10:38   ` Jan Beulich
2018-09-04 10:39     ` Paul Durrant
2018-08-23  9:47 ` [PATCH v6 05/14] public / x86: introduce __HYPERCALL_iommu_op Paul Durrant
2018-09-04 11:50   ` Jan Beulich
2018-09-04 12:23     ` Paul Durrant
2018-09-04 12:55       ` Jan Beulich
2018-09-04 13:17         ` Paul Durrant
2018-09-07 10:52   ` Jan Beulich
2018-08-23  9:47 ` [PATCH v6 06/14] iommu: track reserved ranges using a rangeset Paul Durrant
2018-09-07 10:40   ` Jan Beulich
2018-09-11  9:28     ` Paul Durrant
2018-08-23  9:47 ` [PATCH v6 07/14] x86: add iommu_op to query reserved ranges Paul Durrant
2018-09-07 11:01   ` Jan Beulich
2018-09-11  9:34     ` Paul Durrant
2018-09-11  9:43       ` Jan Beulich
2018-09-13  6:11     ` Tian, Kevin
2018-08-23  9:47 ` [PATCH v6 08/14] vtd: add lookup_page method to iommu_ops Paul Durrant
2018-09-07 11:11   ` Jan Beulich
2018-09-07 12:36     ` Paul Durrant
2018-09-07 14:56       ` Jan Beulich
2018-09-07 15:24         ` Paul Durrant
2018-09-07 15:52           ` Jan Beulich
2018-09-12  8:31     ` Paul Durrant
2018-09-12  8:43       ` Jan Beulich
2018-09-12  8:45         ` Paul Durrant
2018-09-12  8:51           ` Paul Durrant
2018-09-12  8:53             ` Paul Durrant
2018-09-12  9:03               ` Jan Beulich
2018-09-12  9:05                 ` Paul Durrant
2018-09-12  9:12                   ` Jan Beulich
2018-09-12  9:15                     ` Paul Durrant
2018-09-12  9:21                       ` Jan Beulich
2018-09-12  9:30                         ` Paul Durrant
2018-09-12 10:07                           ` Jan Beulich
2018-09-12 10:09                             ` Paul Durrant
2018-09-12 12:15                               ` Jan Beulich
2018-09-12 12:22                                 ` Paul Durrant
2018-09-12 12:39                                   ` Jan Beulich
2018-09-12 12:53                                     ` Paul Durrant
2018-09-12 13:19                                       ` Jan Beulich
2018-09-12 13:25                                         ` Paul Durrant
2018-09-12 13:39                                           ` Jan Beulich
2018-09-12 13:43                                             ` Paul Durrant
2018-09-12  8:59           ` Jan Beulich
2018-08-23  9:47 ` [PATCH v6 09/14] mm / iommu: include need_iommu() test in iommu_use_hap_pt() Paul Durrant
2018-09-07 11:20   ` Jan Beulich
2018-09-11  9:39     ` Paul Durrant
2018-09-11  9:47       ` Jan Beulich
2018-09-13  6:23         ` Tian, Kevin
2018-09-13  8:34           ` Paul Durrant
2018-08-23  9:47 ` [PATCH v6 10/14] mm / iommu: split need_iommu() into has_iommu_pt() and need_iommu_pt_sync() Paul Durrant
2018-08-23 11:10   ` Razvan Cojocaru
2018-09-11 14:31   ` Jan Beulich
2018-09-11 15:40     ` Paul Durrant
2018-09-12  6:45       ` Jan Beulich
2018-09-12  8:07         ` Paul Durrant
2018-08-23  9:47 ` [PATCH v6 11/14] x86: add iommu_op to enable modification of IOMMU mappings Paul Durrant
2018-09-11 14:48   ` Jan Beulich
2018-09-11 15:52     ` Paul Durrant
2018-09-12  6:53       ` Jan Beulich
2018-09-12  8:04         ` Paul Durrant
2018-08-23  9:47 ` [PATCH v6 12/14] memory: add get_paged_gfn() as a wrapper Paul Durrant
2018-08-23 10:24   ` Julien Grall
2018-08-23 10:30     ` Paul Durrant
2018-09-11 14:56   ` Jan Beulich
2018-09-12  9:10     ` Paul Durrant
2018-09-12  9:15       ` Jan Beulich
2018-09-12 10:01         ` George Dunlap
2018-09-12 10:08           ` Paul Durrant
2018-09-12 10:10           ` Jan Beulich
2018-08-23  9:47 ` [PATCH v6 13/14] x86: add iommu_ops to modify and flush IOMMU mappings Paul Durrant
2018-09-11 15:15   ` Jan Beulich
2018-09-12  7:03   ` Jan Beulich
2018-09-12  8:02     ` Paul Durrant
2018-09-12  8:27       ` Jan Beulich
2018-09-13  6:41       ` Tian, Kevin
2018-09-13  8:32         ` Paul Durrant
2018-09-13  8:49         ` Jan Beulich
2018-08-23  9:47 ` Paul Durrant [this message]
2018-09-12 14:12   ` [PATCH v6 14/14] x86: extend the map and unmap iommu_ops to support grant references Jan Beulich
2018-09-12 16:28     ` Paul Durrant

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180823094711.21376-15-paul.durrant@citrix.com \
    --to=paul.durrant@citrix.com \
    --cc=George.Dunlap@eu.citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=julien.grall@arm.com \
    --cc=sstabellini@kernel.org \
    --cc=tim@xen.org \
    --cc=wei.liu2@citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.