[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 01/21] xen: arm: implement XENMEM_add_to_physmap_range



This allows for foreign mappings as well as batching, fitting all that
into XENMEM_add_to_physmap wasn't possible.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
 xen/arch/arm/mm.c           |  120 ++++++++++++++++++++++++++++++++++++++-----
 xen/include/public/memory.h |   40 +++++++++++---
 xen/include/public/xen.h    |    1 +
 3 files changed, 139 insertions(+), 22 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 40ac176..dde304b 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -25,6 +25,8 @@
 #include <xen/mm.h>
 #include <xen/preempt.h>
 #include <xen/errno.h>
+#include <xen/softirq.h>
+#include <xen/event.h>
 #include <xen/guest_access.h>
 #include <xen/domain_page.h>
 #include <asm/page.h>
@@ -461,37 +463,96 @@ void share_xen_page_with_guest(struct page_info *page,
     spin_unlock(&d->page_alloc_lock);
 }
 
-static int xenmem_add_to_physmap_once(
+static int xenmem_add_to_physmap_one(
     struct domain *d,
-    const struct xen_add_to_physmap *xatp)
+    uint16_t space,
+    domid_t foreign_domid,
+    unsigned long idx,
+    xen_pfn_t gpfn)
 {
     unsigned long mfn = 0;
     int rc;
 
-    switch ( xatp->space )
+    switch ( space )
     {
-        case XENMAPSPACE_shared_info:
-            if ( xatp->idx == 0 )
-                mfn = virt_to_mfn(d->shared_info);
-            break;
-        default:
-            return -ENOSYS;
+    case XENMAPSPACE_shared_info:
+        if ( idx == 0 )
+            mfn = virt_to_mfn(d->shared_info);
+        break;
+    case XENMAPSPACE_gmfn_foreign:
+    {
+        paddr_t maddr;
+        struct domain *od;
+        rc = rcu_lock_target_domain_by_id(foreign_domid, &od);
+        if ( rc < 0 )
+            return rc;
+
+        maddr = p2m_lookup(od, idx << PAGE_SHIFT);
+        if ( maddr == INVALID_PADDR )
+        {
+            dump_p2m_lookup(od, idx << PAGE_SHIFT);
+            rcu_unlock_domain(od);
+            return -EINVAL;
+        }
+
+        mfn = maddr >> PAGE_SHIFT;
+
+        rcu_unlock_domain(od);
+        break;
+    }
+
+    default:
+        return -ENOSYS;
     }
 
     domain_lock(d);
 
     /* Map at new location. */
-    rc = guest_physmap_add_page(d, xatp->gpfn, mfn, 0);
+    rc = guest_physmap_add_page(d, gpfn, mfn, 0);
 
     domain_unlock(d);
 
     return rc;
 }
 
-static int xenmem_add_to_physmap(struct domain *d,
-                                 struct xen_add_to_physmap *xatp)
+static int xenmem_add_to_physmap_range(struct domain *d,
+                                       struct xen_add_to_physmap_range *xatpr)
 {
-    return xenmem_add_to_physmap_once(d, xatp);
+    int rc;
+
+    /* Process entries in reverse order to allow continuations */
+    while ( xatpr->size > 0 )
+    {
+        xen_ulong_t idx;
+        xen_pfn_t gpfn;
+
+        rc = copy_from_guest_offset(&idx, xatpr->idxs, xatpr->size-1, 1);
+        if ( rc < 0 )
+            goto out;
+
+        rc = copy_from_guest_offset(&gpfn, xatpr->gpfns, xatpr->size-1, 1);
+        if ( rc < 0 )
+            goto out;
+
+        rc = xenmem_add_to_physmap_one(d, xatpr->space,
+                                       xatpr->foreign_domid,
+                                       idx, gpfn);
+
+        xatpr->size--;
+
+        /* Check for continuation if it's not the last interation */
+        if ( xatpr->size > 0 && hypercall_preempt_check() )
+        {
+            rc = -EAGAIN;
+            goto out;
+        }
+    }
+
+    rc = 0;
+
+out:
+    return rc;
+
 }
 
 long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
@@ -508,14 +569,45 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
         if ( copy_from_guest(&xatp, arg, 1) )
             return -EFAULT;
 
+        /* This one is only supported by add_to_physmap_range */
+        if ( xatp.space == XENMAPSPACE_gmfn_foreign )
+            return -EINVAL;
+
         rc = rcu_lock_target_domain_by_id(xatp.domid, &d);
         if ( rc != 0 )
             return rc;
 
-        rc = xenmem_add_to_physmap(d, &xatp);
+        rc = xenmem_add_to_physmap_one(d, xatp.space, DOMID_INVALID,
+                                       xatp.idx, xatp.gpfn);
+
+        rcu_unlock_domain(d);
+
+        return rc;
+    }
+
+    case XENMEM_add_to_physmap_range:
+    {
+        struct xen_add_to_physmap_range xatpr;
+        struct domain *d;
+
+        if ( copy_from_guest(&xatpr, arg, 1) )
+            return -EFAULT;
+
+        rc = rcu_lock_target_domain_by_id(xatpr.domid, &d);
+        if ( rc != 0 )
+            return rc;
+
+        rc = xenmem_add_to_physmap_range(d, &xatpr);
 
         rcu_unlock_domain(d);
 
+        if ( rc && copy_to_guest(arg, &xatpr, 1) )
+            rc = -EFAULT;
+
+        if ( rc == -EAGAIN )
+            rc = hypercall_create_continuation(
+                __HYPERVISOR_memory_op, "ih", op, arg);
+
         return rc;
     }
 
diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h
index 86d02c8..f1ddbc0 100644
--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -198,6 +198,15 @@ struct xen_machphys_mapping {
 typedef struct xen_machphys_mapping xen_machphys_mapping_t;
 DEFINE_XEN_GUEST_HANDLE(xen_machphys_mapping_t);
 
+/* Source mapping space. */
+/* ` enum phys_map_space { */
+#define XENMAPSPACE_shared_info  0 /* shared info page */
+#define XENMAPSPACE_grant_table  1 /* grant table page */
+#define XENMAPSPACE_gmfn         2 /* GMFN */
+#define XENMAPSPACE_gmfn_range   3 /* GMFN range */
+#define XENMAPSPACE_gmfn_foreign 4 /* GMFN from another dom */
+/* ` } */
+
 /*
  * Sets the GPFN at which a particular page appears in the specified guest's
  * pseudophysical address space.
@@ -211,24 +220,39 @@ struct xen_add_to_physmap {
     /* Number of pages to go through for gmfn_range */
     uint16_t    size;
 
-    /* Source mapping space. */
-#define XENMAPSPACE_shared_info 0 /* shared info page */
-#define XENMAPSPACE_grant_table 1 /* grant table page */
-#define XENMAPSPACE_gmfn        2 /* GMFN */
-#define XENMAPSPACE_gmfn_range  3 /* GMFN range */
-    unsigned int space;
+    unsigned int space; /* => enum phys_map_space */
 
 #define XENMAPIDX_grant_table_status 0x80000000
 
-    /* Index into source mapping space. */
+    /* Index into space being mapped. */
     xen_ulong_t idx;
 
-    /* GPFN where the source mapping page should appear. */
+    /* GPFN in domid where the source mapping page should appear. */
     xen_pfn_t     gpfn;
 };
 typedef struct xen_add_to_physmap xen_add_to_physmap_t;
 DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t);
 
+/* A batched version of add_to_physmap. */
+#define XENMEM_add_to_physmap_range 23
+struct xen_add_to_physmap_range {
+    /* Which domain to change the mapping for. */
+    domid_t domid;
+    uint16_t space; /* => enum phys_map_space */
+
+    /* Number of pages to go through */
+    uint16_t size;
+    domid_t foreign_domid; /* IFF gmfn_foreign */
+
+    /* Indexes into space being mapped. */
+    XEN_GUEST_HANDLE(xen_ulong_t) idxs;
+
+    /* GPFN in domdwhere the source mapping page should appear. */
+    XEN_GUEST_HANDLE(xen_pfn_t) gpfns;
+};
+typedef struct xen_add_to_physmap_range xen_add_to_physmap_range_t;
+DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_range_t);
+
 /*
  * Unmaps the page appearing at a particular GPFN from the specified guest's
  * pseudophysical address space.
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 361398b..e42d01f 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -49,6 +49,7 @@ DEFINE_XEN_GUEST_HANDLE(void);
 
 DEFINE_XEN_GUEST_HANDLE(uint64_t);
 DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
+DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
 #endif
 
 /*
-- 
1.7.9.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.