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 v3 13/13] x86: extend the map and unmap iommu_ops to support grant references
Date: Tue, 17 Jul 2018 14:38:16 +0100 [thread overview]
Message-ID: <20180717133816.37958-14-paul.durrant@citrix.com> (raw)
In-Reply-To: <20180717133816.37958-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>
v2:
- New in v2.
---
xen/arch/x86/iommu_op.c | 76 +++++++++++++++-------
xen/common/grant_table.c | 143 ++++++++++++++++++++++++++++++++++++++++++
xen/include/public/iommu_op.h | 31 +++++++--
xen/include/xen/grant_table.h | 7 +++
4 files changed, 228 insertions(+), 29 deletions(-)
diff --git a/xen/arch/x86/iommu_op.c b/xen/arch/x86/iommu_op.c
index 02bf9c679e..b3de7bce25 100644
--- a/xen/arch/x86/iommu_op.c
+++ b/xen/arch/x86/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;
@@ -121,10 +122,12 @@ 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_readonly) )
+ if ( op->pad || (op->flags & ~(XEN_IOMMUOP_map_readonly |
+ XEN_IOMMUOP_map_gref)) )
return -EINVAL;
if ( !iommu->iommu_op_ranges )
@@ -138,15 +141,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 ( !get_page_type(page, readonly ? PGT_none : 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 ( !get_page_type(page, readonly ? PGT_none : PGT_writable_page) )
+ {
+ put_page(page);
+ goto unlock;
+ }
+
+ mfn = page_to_mfn(page);
}
prot = IOMMUF_readable;
@@ -154,7 +170,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));
@@ -168,7 +184,10 @@ static int iommuop_map(struct xen_iommu_op_map *op)
ignore = iommu_unmap_page(currd, bfn);
release:
- put_page_and_type(page);
+ if ( op->flags & XEN_IOMMUOP_map_gref )
+ release_gref_for_iommu(d, op->u.gref, readonly, mfn);
+ else
+ put_page_and_type(page);
unlock:
rcu_unlock_domain(d);
@@ -182,11 +201,10 @@ static int iommuop_unmap(struct xen_iommu_op_unmap *op)
bfn_t bfn = _bfn(op->bfn);
mfn_t mfn;
unsigned int prot;
- struct page_info *page;
+ bool readonly;
int rc;
- if ( op->pad0 || op->pad1 )
- return -EINVAL;
+ if ( op->pad || (op->flags & ~XEN_IOMMUOP_unmap_gref) )
if ( !iommu->iommu_op_ranges )
return -EOPNOTSUPP;
@@ -196,28 +214,40 @@ static int iommuop_unmap(struct xen_iommu_op_unmap *op)
!mfn_valid(mfn) )
return -ENOENT;
+ readonly = !(prot & IOMMUF_writable);
+
d = rcu_lock_domain_by_any_id(op->domid);
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;
+
+ rc = get_paged_gfn(d, _gfn(op->u.gfn), readonly, NULL, &page);
+ if ( rc )
+ goto unlock;
- put_page(page); /* release extra reference just taken */
+ put_page(page); /* release extra reference just taken */
- rc = -EINVAL;
- if ( !mfn_eq(page_to_mfn(page), mfn) )
- goto unlock;
+ rc = -EINVAL;
+ if ( !mfn_eq(page_to_mfn(page), mfn) )
+ goto unlock;
- put_page_and_type(page); /* release references taken in map */
+ put_page_and_type(page); /* release references taken in map */
+ }
rc = rangeset_remove_singleton(iommu->iommu_op_ranges, bfn_x(bfn));
if ( rc )
goto unlock;
- if ( !iommu_unmap_page(currd, bfn) )
+ if ( iommu_unmap_page(currd, bfn) )
rc = -EIO;
unlock:
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index a492df2362..6d5bcca6df 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -3909,6 +3909,149 @@ int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
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/include/public/iommu_op.h b/xen/include/public/iommu_op.h
index 737e2c8cfe..485782a522 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 unsigned long xen_bfn_t;
@@ -79,12 +80,20 @@ struct xen_iommu_op_map {
#define _XEN_IOMMUOP_map_readonly 0
#define XEN_IOMMUOP_map_readonly (1 << (_XEN_IOMMUOP_map_readonly))
+#define _XEN_IOMMUOP_map_gref 1
+#define XEN_IOMMUOP_map_gref (1 << (_XEN_IOMMUOP_map_gref))
uint32_t pad;
/* 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;
};
/*
@@ -95,12 +104,22 @@ struct xen_iommu_op_map {
struct xen_iommu_op_unmap {
/* IN - The domid of the guest */
domid_t domid;
- uint16_t pad0;
- uint32_t pad1;
+ uint16_t flags;
+
+#define _XEN_IOMMUOP_unmap_gref 0
+#define XEN_IOMMUOP_unmap_gref (1 << (_XEN_IOMMUOP_unmap_gref))
+
+ uint32_t pad;
/* 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 b3a95fda58..22c80c2238 100644
--- a/xen/include/xen/grant_table.h
+++ b/xen/include/xen/grant_table.h
@@ -56,6 +56,13 @@ int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref,
int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
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
prev parent reply other threads:[~2018-07-17 13:58 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-17 13:38 [PATCH v3 00/13] paravirtual IOMMU interface Paul Durrant
2018-07-17 13:38 ` [PATCH v3 01/13] grant_table: use term 'mfn' for machine frame numbers Paul Durrant
2018-07-17 13:38 ` [PATCH v3 02/13] iommu: introduce the concept of BFN Paul Durrant
2018-07-19 8:08 ` Wei Liu
2018-07-17 13:38 ` [PATCH v3 03/13] iommu: make use of type-safe BFN and MFN in exported functions Paul Durrant
2018-07-19 8:08 ` Wei Liu
2018-07-17 13:38 ` [PATCH v3 04/13] iommu: push use of type-safe BFN and MFN into iommu_ops Paul Durrant
2018-07-19 8:10 ` Wei Liu
2018-07-17 13:38 ` [PATCH v3 05/13] iommu: don't domain_crash() inside iommu_map/unmap_page() Paul Durrant
2018-07-17 13:38 ` [PATCH v3 06/13] public / x86: introduce __HYPERCALL_iommu_op Paul Durrant
2018-07-17 13:38 ` [PATCH v3 07/13] iommu: track reserved ranges using a rangeset Paul Durrant
2018-07-19 9:01 ` Wei Liu
2018-07-17 13:38 ` [PATCH v3 08/13] x86: add iommu_op to query reserved ranges Paul Durrant
2018-07-19 9:37 ` Wei Liu
2018-07-19 10:03 ` Paul Durrant
2018-07-17 13:38 ` [PATCH v3 09/13] vtd: add lookup_page method to iommu_ops Paul Durrant
2018-07-19 9:55 ` Wei Liu
2018-07-17 13:38 ` [PATCH v3 10/13] x86: add iommu_op to enable modification of IOMMU mappings Paul Durrant
2018-07-20 8:59 ` Wei Liu
2018-07-20 9:05 ` Paul Durrant
2018-07-20 9:19 ` Paul Durrant
2018-07-20 9:30 ` Wei Liu
2018-07-17 13:38 ` [PATCH v3 11/13] memory: add get_paged_gfn() as a wrapper Paul Durrant
2018-07-17 13:38 ` [PATCH v3 12/13] x86: add iommu_ops to modify and flush IOMMU mappings Paul Durrant
2018-07-23 13:35 ` Wei Liu
2018-07-23 13:40 ` Paul Durrant
2018-07-23 13:49 ` Wei Liu
2018-07-23 14:26 ` Wei Liu
2018-07-23 14:27 ` Paul Durrant
2018-07-17 13:38 ` Paul Durrant [this message]
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=20180717133816.37958-14-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.