From: Mukesh Rathor <mukesh.rathor@oracle.com>
To: xen-devel@lists.xenproject.org
Cc: JBeulich@suse.com, George.Dunlap@eu.citrix.com, tim@xen.org,
eddie.dong@intel.com, keir.xen@gmail.com, jun.nakajima@intel.com
Subject: [V9 PATCH 6/8] pvh dom0: Add and remove foreign pages
Date: Tue, 15 Apr 2014 17:12:50 -0700 [thread overview]
Message-ID: <1397607172-32065-7-git-send-email-mukesh.rathor@oracle.com> (raw)
In-Reply-To: <1397607172-32065-1-git-send-email-mukesh.rathor@oracle.com>
In this patch, a new function, p2m_add_foreign(), is added
to map pages from foreign guest into dom0 for domU creation.
Such pages are typed p2m_map_foreign. Note, it is the nature
of such pages that a refcnt is held during their stay in the p2m.
The refcnt is added and released in the low level ept function
atomic_write_ept_entry for convenience.
Also, p2m_teardown is changed to add a call to allow for the
cleanup of foreign pages during it's destruction.
Finally, get_pg_owner is changed to allow pvh to map foreign mappings,
and is made public to be used by p2m_add_foreign().
Signed-off-by: Mukesh Rathor <mukesh.rathor@oracle.com>
---
xen/arch/x86/mm.c | 11 +++--
xen/arch/x86/mm/p2m-ept.c | 37 +++++++++++++---
xen/arch/x86/mm/p2m-pt.c | 7 +++
xen/arch/x86/mm/p2m.c | 110 +++++++++++++++++++++++++++++++++++++++++++---
xen/include/asm-x86/mm.h | 2 +
xen/include/asm-x86/p2m.h | 7 +++
6 files changed, 158 insertions(+), 16 deletions(-)
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index fdc5ed3..e8ab68a 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -2794,7 +2794,7 @@ int new_guest_cr3(unsigned long mfn)
return rc;
}
-static struct domain *get_pg_owner(domid_t domid)
+struct domain *get_pg_owner(domid_t domid)
{
struct domain *pg_owner = NULL, *curr = current->domain;
@@ -2810,7 +2810,7 @@ static struct domain *get_pg_owner(domid_t domid)
goto out;
}
- if ( unlikely(paging_mode_translate(curr)) )
+ if ( !is_pvh_domain(curr) && unlikely(paging_mode_translate(curr)) )
{
MEM_LOG("Cannot mix foreign mappings with translated domains");
goto out;
@@ -2837,7 +2837,7 @@ static struct domain *get_pg_owner(domid_t domid)
return pg_owner;
}
-static void put_pg_owner(struct domain *pg_owner)
+void put_pg_owner(struct domain *pg_owner)
{
rcu_unlock_domain(pg_owner);
}
@@ -4583,6 +4583,11 @@ int xenmem_add_to_physmap_one(
page = mfn_to_page(mfn);
break;
}
+ case XENMAPSPACE_gmfn_foreign:
+ {
+ rc = p2m_add_foreign(d, idx, gpfn, foreign_domid);
+ return rc;
+ }
default:
break;
}
diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c
index e6a0ef4..7dcfcb6 100644
--- a/xen/arch/x86/mm/p2m-ept.c
+++ b/xen/arch/x86/mm/p2m-ept.c
@@ -36,8 +36,6 @@
#define atomic_read_ept_entry(__pepte) \
( (ept_entry_t) { .epte = read_atomic(&(__pepte)->epte) } )
-#define atomic_write_ept_entry(__pepte, __epte) \
- write_atomic(&(__pepte)->epte, (__epte).epte)
#define is_epte_present(ept_entry) ((ept_entry)->epte & 0x7)
#define is_epte_superpage(ept_entry) ((ept_entry)->sp)
@@ -46,6 +44,33 @@ static inline bool_t is_epte_valid(ept_entry_t *e)
return (e->epte != 0 && e->sa_p2mt != p2m_invalid);
}
+static inline void atomic_write_ept_entry(ept_entry_t *entryptr,
+ const ept_entry_t *new)
+{
+ unsigned long oldmfn = 0;
+
+ if ( p2m_is_foreign(new->sa_p2mt) )
+ {
+ int rc;
+ struct page_info *page;
+ struct domain *fdom;
+
+ ASSERT(mfn_valid(new->mfn));
+ page = mfn_to_page(new->mfn);
+ fdom = page_get_owner(page);
+ ASSERT(fdom);
+ rc = get_page(page, fdom);
+ ASSERT(rc);
+ }
+ if ( p2m_is_foreign(entryptr->sa_p2mt) )
+ oldmfn = entryptr->mfn;
+
+ write_atomic(&entryptr->epte, new->epte);
+
+ if ( oldmfn )
+ put_page(mfn_to_page(oldmfn));
+}
+
static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_access_t access)
{
/* First apply type permissions */
@@ -377,7 +402,7 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
ept_p2m_type_to_flags(&new_entry, p2mt, p2ma);
}
- atomic_write_ept_entry(ept_entry, new_entry);
+ atomic_write_ept_entry(ept_entry, &new_entry);
}
else
{
@@ -398,7 +423,7 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
/* now install the newly split ept sub-tree */
/* NB: please make sure domian is paused and no in-fly VT-d DMA. */
- atomic_write_ept_entry(ept_entry, split_ept_entry);
+ atomic_write_ept_entry(ept_entry, &split_ept_entry);
/* then move to the level we want to make real changes */
for ( ; i > target; i-- )
@@ -425,7 +450,7 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
ept_p2m_type_to_flags(&new_entry, p2mt, p2ma);
- atomic_write_ept_entry(ept_entry, new_entry);
+ atomic_write_ept_entry(ept_entry, &new_entry);
}
/* Track the highest gfn for which we have ever had a valid mapping */
@@ -641,7 +666,7 @@ static void ept_change_entry_type_page(mfn_t ept_page_mfn, int ept_page_level,
e.sa_p2mt = nt;
ept_p2m_type_to_flags(&e, nt, e.access);
- atomic_write_ept_entry(&epte[i], e);
+ atomic_write_ept_entry(&epte[i], &e);
}
}
diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c
index 3b449b8..915f60d 100644
--- a/xen/arch/x86/mm/p2m-pt.c
+++ b/xen/arch/x86/mm/p2m-pt.c
@@ -313,6 +313,13 @@ p2m_pt_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
__trace_var(TRC_MEM_SET_P2M_ENTRY, 0, sizeof(t), &t);
}
+ if ( p2m_is_foreign(p2mt) )
+ {
+ /* pvh fixme: foreign types are only supported on ept at present */
+ gdprintk(XENLOG_WARNING, "Unimplemented foreign p2m type.\n");
+ return -EINVAL;
+ }
+
rc = p2m_next_level(p2m, &table_mfn, &table, &gfn_remainder, gfn,
L4_PAGETABLE_SHIFT - PAGE_SHIFT,
L4_PAGETABLE_ENTRIES, PGT_l3_page_table);
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 996408a..67aa5f6 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -36,6 +36,7 @@
#include <xen/event.h>
#include <asm/hvm/nestedhvm.h>
#include <asm/hvm/svm/amd-iommu-proto.h>
+#include <xsm/xsm.h>
#include "mm-locks.h"
@@ -275,14 +276,18 @@ struct page_info *get_page_from_gfn_p2m(
/* Fast path: look up and get out */
p2m_read_lock(p2m);
mfn = __get_gfn_type_access(p2m, gfn, t, a, 0, NULL, 0);
- if ( (p2m_is_ram(*t) || p2m_is_grant(*t))
- && mfn_valid(mfn)
+ if ( p2m_is_any_ram(*t) && mfn_valid(mfn)
&& !((q & P2M_UNSHARE) && p2m_is_shared(*t)) )
{
page = mfn_to_page(mfn);
- if ( !get_page(page, d)
- /* Page could be shared */
- && !get_page(page, dom_cow) )
+ if ( p2m_is_foreign(*t) )
+ {
+ struct domain *fdom = page_get_owner_and_reference(page);
+ ASSERT(fdom && fdom != d);
+ }
+ else if ( !get_page(page, d)
+ /* Page could be shared */
+ && !get_page(page, dom_cow) )
page = NULL;
}
p2m_read_unlock(p2m);
@@ -451,6 +456,10 @@ void p2m_teardown(struct p2m_domain *p2m)
d = p2m->domain;
p2m_lock(p2m);
+ /* pvh: we must release refcnt on all foreign pages */
+ if ( is_pvh_domain(d) )
+ p2m_change_entry_type_global(d, p2m_map_foreign, p2m_invalid);
+
ASSERT(atomic_read(&d->shr_pages) == 0);
p2m->phys_table = pagetable_null();
@@ -789,8 +798,8 @@ static int set_typed_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
}
/* Set foreign mfn in the given guest's p2m table. */
-static int __attribute__((unused))
-set_foreign_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
+static int set_foreign_p2m_entry(struct domain *d, unsigned long gfn,
+ mfn_t mfn)
{
return set_typed_p2m_entry(d, gfn, mfn, p2m_map_foreign);
}
@@ -1748,6 +1757,93 @@ out_p2m_audit:
#endif /* P2M_AUDIT */
/*
+ * Add frame from foreign domain to target domain's physmap. Similar to
+ * XENMAPSPACE_gmfn but the frame is foreign being mapped into current,
+ * and is not removed from foreign domain.
+ *
+ * Usage: - libxl on pvh dom0 creating a guest and doing privcmd_ioctl_mmap.
+ * - xentrace running on dom0 mapping xenheap pages. fdid would be
+ * DOMID_XEN in such a case.
+ * etc..
+ *
+ * Side Effect: the mfn for fgfn will be refcounted in lower level routines
+ * so it is not lost while mapped here. The refcnt is released
+ * via the XENMEM_remove_from_physmap path.
+ *
+ * Returns: 0 ==> success
+ */
+int p2m_add_foreign(struct domain *tdom, unsigned long fgfn,
+ unsigned long gpfn, domid_t fdid)
+{
+ p2m_type_t p2mt, p2mt_prev;
+ unsigned long prev_mfn, mfn;
+ struct page_info *page;
+ int rc = -EINVAL;
+ struct domain *fdom = NULL;
+
+ if ( fdid == DOMID_SELF )
+ goto out;
+
+ rc = -ESRCH;
+ fdom = get_pg_owner(fdid);
+ if ( fdom == NULL )
+ goto out;
+
+ rc = -EINVAL;
+ if ( tdom == NULL || tdom == fdom || !is_pvh_domain(tdom) )
+ goto out;
+
+ rc = xsm_map_gmfn_foreign(XSM_TARGET, tdom, fdom);
+ if ( rc )
+ goto out;
+
+ /* following will take a refcnt on the mfn */
+ page = get_page_from_gfn(fdom, fgfn, &p2mt, P2M_ALLOC);
+ if ( !page || !p2m_is_valid(p2mt) )
+ {
+ if ( page )
+ put_page(page);
+ goto out;
+ }
+ mfn = mfn_x(page_to_mfn(page));
+
+ /* Remove previously mapped page if it is present. */
+ prev_mfn = mfn_x(get_gfn(tdom, gpfn, &p2mt_prev));
+ if ( mfn_valid(_mfn(prev_mfn)) )
+ {
+ if ( is_xen_heap_mfn(prev_mfn) )
+ /* Xen heap frames are simply unhooked from this phys slot */
+ guest_physmap_remove_page(tdom, gpfn, prev_mfn, 0);
+ else
+ /* Normal domain memory is freed, to avoid leaking memory. */
+ guest_remove_page(tdom, gpfn);
+ }
+ /*
+ * Create the new mapping. Can't use guest_physmap_add_page() because it
+ * will update the m2p table which will result in mfn -> gpfn of dom0
+ * and not fgfn of domU.
+ */
+ rc = set_foreign_p2m_entry(tdom, gpfn, _mfn(mfn));
+ if ( rc )
+ gdprintk(XENLOG_WARNING, "set_foreign_p2m_entry failed. "
+ "gpfn:%lx mfn:%lx fgfn:%lx td:%d fd:%d\n",
+ gpfn, mfn, fgfn, tdom->domain_id, fdom->domain_id);
+
+ put_page(page);
+
+ /*
+ * This put_gfn for the above get_gfn for prev_mfn. We must do this
+ * after set_foreign_p2m_entry so another cpu doesn't populate the gpfn
+ * before us.
+ */
+ put_gfn(tdom, gpfn);
+
+out:
+ if ( fdom )
+ put_pg_owner(fdom);
+ return rc;
+}
+/*
* Local variables:
* mode: C
* c-file-style: "BSD"
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index c835f76..afa6c48 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -358,6 +358,8 @@ int put_old_guest_table(struct vcpu *);
int get_page_from_l1e(
l1_pgentry_t l1e, struct domain *l1e_owner, struct domain *pg_owner);
void put_page_from_l1e(l1_pgentry_t l1e, struct domain *l1e_owner);
+struct domain *get_pg_owner(domid_t domid);
+void put_pg_owner(struct domain *pg_owner);
static inline void put_page_and_type(struct page_info *page)
{
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index 7aa71cc..47604da 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -184,6 +184,10 @@ typedef unsigned int p2m_query_t;
#define p2m_is_broken(_t) (p2m_to_mask(_t) & P2M_BROKEN_TYPES)
#define p2m_is_foreign(_t) (p2m_to_mask(_t) & p2m_to_mask(p2m_map_foreign))
+#define p2m_is_any_ram(_t) (p2m_to_mask(_t) & \
+ (P2M_RAM_TYPES | P2M_GRANT_TYPES | \
+ p2m_to_mask(p2m_map_foreign)))
+
/* Per-p2m-table state */
struct p2m_domain {
/* Lock that protects updates to the p2m */
@@ -513,6 +517,9 @@ p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn,
int set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn);
int clear_mmio_p2m_entry(struct domain *d, unsigned long gfn);
+/* Add foreign mapping to the guest's p2m table. */
+int p2m_add_foreign(struct domain *tdom, unsigned long fgfn,
+ unsigned long gpfn, domid_t foreign_domid);
/*
* Populate-on-demand
--
1.8.3.1
next prev parent reply other threads:[~2014-04-16 0:13 UTC|newest]
Thread overview: 58+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-16 0:12 [V9 PATCH 0/8] pvh dom0 patches Mukesh Rathor
2014-04-16 0:12 ` [V9 PATCH 1/8] pvh dom0: move some pv specific code to static functions Mukesh Rathor
2014-04-16 0:12 ` [V9 PATCH 2/8] pvh dom0: construct_dom0 changes Mukesh Rathor
2014-04-16 0:12 ` [V9 PATCH 3/8] pvh dom0: Introduce p2m_map_foreign Mukesh Rathor
2014-04-16 0:12 ` [V9 PATCH 4/8] pvh dom0: Add checks and restrictions for p2m_is_foreign Mukesh Rathor
2014-04-16 15:28 ` Jan Beulich
2014-04-16 0:12 ` [V9 PATCH 5/8] pvh dom0: make xsm_map_gmfn_foreign available for x86 Mukesh Rathor
2014-04-16 14:29 ` Daniel De Graaf
2014-04-16 0:12 ` Mukesh Rathor [this message]
2014-04-16 16:00 ` [V9 PATCH 6/8] pvh dom0: Add and remove foreign pages Jan Beulich
2014-04-17 1:37 ` Mukesh Rathor
2014-04-17 6:50 ` Jan Beulich
2014-04-17 12:36 ` Tim Deegan
2014-04-17 13:58 ` Jan Beulich
2014-04-19 0:59 ` Mukesh Rathor
2014-04-21 16:10 ` Jan Beulich
2014-04-24 2:21 ` Mukesh Rathor
2014-04-24 6:44 ` Jan Beulich
2014-04-24 9:46 ` Tim Deegan
2014-04-25 2:09 ` Mukesh Rathor
2014-04-25 6:49 ` Jan Beulich
2014-04-25 23:23 ` Mukesh Rathor
2014-04-26 0:06 ` Mukesh Rathor
2014-04-28 7:23 ` Jan Beulich
2014-04-25 8:55 ` Tim Deegan
2014-04-25 23:29 ` Mukesh Rathor
2014-04-26 1:34 ` Mukesh Rathor
2014-04-28 8:54 ` Jan Beulich
2014-04-28 9:09 ` Tim Deegan
2014-04-22 0:19 ` Mukesh Rathor
2014-04-22 7:28 ` Jan Beulich
2014-04-23 0:28 ` Mukesh Rathor
2014-04-23 9:03 ` Jan Beulich
2014-04-23 16:13 ` Andres Lagar-Cavilla
2014-04-24 16:37 ` Tim Deegan
2014-04-16 0:12 ` [V9 PATCH 7/8] pvh dom0: check for vioapic null ptr in vioapic_range Mukesh Rathor
2014-04-16 16:05 ` Jan Beulich
2014-04-17 1:44 ` Mukesh Rathor
2014-04-17 6:54 ` Jan Beulich
2014-04-22 0:59 ` Mukesh Rathor
2014-04-22 7:33 ` Jan Beulich
2014-04-23 0:11 ` Mukesh Rathor
2014-04-23 9:07 ` Jan Beulich
2014-04-23 21:18 ` Mukesh Rathor
2014-04-24 6:49 ` Jan Beulich
2014-04-24 23:28 ` Mukesh Rathor
2014-05-06 0:19 ` Mukesh Rathor
2014-05-06 7:44 ` Jan Beulich
2014-05-07 1:07 ` Mukesh Rathor
2014-05-07 6:47 ` Jan Beulich
2014-05-07 23:52 ` Mukesh Rathor
2014-05-08 6:33 ` Jan Beulich
2014-04-16 0:12 ` [V9 PATCH 8/8] pvh dom0: add opt_dom0pvh to setup.c Mukesh Rathor
2014-04-16 12:57 ` Konrad Rzeszutek Wilk
2014-04-16 13:01 ` Andrew Cooper
2014-04-16 16:09 ` Jan Beulich
2014-04-16 14:57 ` [V9 PATCH 0/8] pvh dom0 patches Roger Pau Monné
2014-04-16 21:15 ` Mukesh Rathor
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=1397607172-32065-7-git-send-email-mukesh.rathor@oracle.com \
--to=mukesh.rathor@oracle.com \
--cc=George.Dunlap@eu.citrix.com \
--cc=JBeulich@suse.com \
--cc=eddie.dong@intel.com \
--cc=jun.nakajima@intel.com \
--cc=keir.xen@gmail.com \
--cc=tim@xen.org \
--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 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).