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

Re: [Xen-devel] RT Xen on ARM - R-Car series



On Fri, Feb 01, 2019 at 05:40:14PM +0000, Julien Grall wrote:
> Hi,
> 
> On 01/02/2019 16:53, Roger Pau Monné wrote:
> > On Thu, Jan 31, 2019 at 11:14:37PM +0000, Julien Grall wrote:
> > > On 1/31/19 9:56 PM, Stefano Stabellini wrote:
> > > > On Thu, 31 Jan 2019, Julien Grall wrote:
> > > > > On 31/01/2019 12:00, Andrii Anisov wrote:
> > > > > > On 31.01.19 13:37, Julien Grall wrote:
> > So, I've got a hacky patch to 'fix' this on x86, by taking a reference
> > to the mfn behind the virtual address provided when setting up the
> > hypercall and mapping it in Xen.
> 
> That was the idea I had in mind :). Hopefully, no guest is modifying the
> mapping (i.e the virtual address point to a different physical address)
> afterwards.
> 
> > This however doesn't work on ARM due
> > to the lack of paging_gva_to_gfn. I guess there's something similar to
> > translate a guest virtual address into a gfn or a mfn?
> 
> get_page_from_gva should to the job for you.
> > +int map_runstate_area(struct vcpu *v,
> > +                      struct vcpu_register_runstate_memory_area *area)
> > +{
> > +    unsigned long offset;
> > +    unsigned int i;
> > +    struct domain *d = v->domain;
> > +    size_t size =
> > +#ifdef CONFIG_COMPAT
> > +        has_32bit_shinfo((v)->domain) ? sizeof(*v->compat_runstate_guest) :
> > +#endif
> > +                                        sizeof(*v->runstate_guest);
> > +
> > +    if ( v->runstate_guest )
> > +    {
> > +        ASSERT_UNREACHABLE();
> > +        return -EBUSY;
> > +    }
> > +
> > +    offset = area->addr.p & ~PAGE_MASK;
> > +
> > +    for ( i = 0; i < ARRAY_SIZE(v->runstate_mfn); i++ )
> > +    {
> > +        p2m_type_t t;
> > +        uint32_t pfec = PFEC_page_present;
> > +        gfn_t gfn = _gfn(paging_gva_to_gfn(v, area->addr.p, &pfec));
> > +        struct page_info *pg;
> > +
> > +        if ( gfn_eq(gfn, INVALID_GFN) )
> > +            return -EFAULT;
> > +
> > +        v->runstate_mfn[i] = get_gfn(d, gfn_x(gfn), &t);
> 
> get_gfn would need to be implemented on Arm.
> 
> > +        if ( t != p2m_ram_rw || mfn_eq(v->runstate_mfn[i], INVALID_MFN) )
> > +            return -EFAULT;
> > +
> > +        pg = mfn_to_page(v->runstate_mfn[i]);
> > +        if ( !pg || !get_page_type(pg, PGT_writable_page) )
> > +        {
> > +            put_gfn(d, gfn_x(gfn));
> > +            return -EFAULT;
> > +        }
> > +
> > +        put_gfn(d, gfn_x(gfn));
> > +
> > +        if ( PFN_DOWN(gfn_x(gfn) + size) == PFN_DOWN(gfn_x(gfn)) )
> 
> This looks wrong, you seem to mix address and frame. I think you might want:
> 
> if ( gfn_eq(gfn_add(gfn, PFN_DOWN(size)), gfn) )

Thanks!

Here is an updated version which seems to build on ARM. I don't have
an easy way to test this, could you give it a spin?

I don't like adding CONFIG_X86/ARM in common code, so it might be
worth to either try to factor this out into arch specific code, or
even better, provide common functions to translate a guest virtual
address into a gfn, mfn or page.

---8<---
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 6dc633ed50..6fb69a9e12 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -275,31 +275,25 @@ static void ctxt_switch_to(struct vcpu *n)
 }
 
 /* Update per-VCPU guest runstate shared memory area (if registered). */
-static void update_runstate_area(struct vcpu *v)
+void update_runstate_area(struct vcpu *v)
 {
-    void __user *guest_handle = NULL;
-
-    if ( guest_handle_is_null(runstate_guest(v)) )
+    if ( !v->runstate_guest )
         return;
 
     if ( VM_ASSIST(v->domain, runstate_update_flag) )
     {
-        guest_handle = &v->runstate_guest.p->state_entry_time + 1;
-        guest_handle--;
         v->runstate.state_entry_time |= XEN_RUNSTATE_UPDATE;
-        __raw_copy_to_guest(guest_handle,
-                            (void *)(&v->runstate.state_entry_time + 1) - 1, 
1);
+        v->runstate_guest->state_entry_time |= XEN_RUNSTATE_UPDATE;
         smp_wmb();
     }
 
-    __copy_to_guest(runstate_guest(v), &v->runstate, 1);
+    memcpy(v->runstate_guest, &v->runstate, sizeof(v->runstate));
 
-    if ( guest_handle )
+    if ( VM_ASSIST(v->domain, runstate_update_flag) )
     {
         v->runstate.state_entry_time &= ~XEN_RUNSTATE_UPDATE;
         smp_wmb();
-        __raw_copy_to_guest(guest_handle,
-                            (void *)(&v->runstate.state_entry_time + 1) - 1, 
1);
+        v->runstate_guest->state_entry_time &= ~XEN_RUNSTATE_UPDATE;
     }
 }
 
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 32dc4253ff..b86d8d94c7 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1604,26 +1604,22 @@ void paravirt_ctxt_switch_to(struct vcpu *v)
 }
 
 /* Update per-VCPU guest runstate shared memory area (if registered). */
-bool update_runstate_area(struct vcpu *v)
+void update_runstate_area(struct vcpu *v)
 {
-    bool rc;
     struct guest_memory_policy policy = { .nested_guest_mode = false };
-    void __user *guest_handle = NULL;
 
-    if ( guest_handle_is_null(runstate_guest(v)) )
-        return true;
+    if ( !v->runstate_guest )
+        return;
 
     update_guest_memory_policy(v, &policy);
 
     if ( VM_ASSIST(v->domain, runstate_update_flag) )
     {
-        guest_handle = has_32bit_shinfo(v->domain)
-            ? &v->runstate_guest.compat.p->state_entry_time + 1
-            : &v->runstate_guest.native.p->state_entry_time + 1;
-        guest_handle--;
         v->runstate.state_entry_time |= XEN_RUNSTATE_UPDATE;
-        __raw_copy_to_guest(guest_handle,
-                            (void *)(&v->runstate.state_entry_time + 1) - 1, 
1);
+        if ( has_32bit_shinfo((v)->domain) )
+            v->compat_runstate_guest->state_entry_time |= XEN_RUNSTATE_UPDATE;
+        else
+            v->runstate_guest->state_entry_time |= XEN_RUNSTATE_UPDATE;
         smp_wmb();
     }
 
@@ -1632,31 +1628,22 @@ bool update_runstate_area(struct vcpu *v)
         struct compat_vcpu_runstate_info info;
 
         XLAT_vcpu_runstate_info(&info, &v->runstate);
-        __copy_to_guest(v->runstate_guest.compat, &info, 1);
-        rc = true;
+        memcpy(v->compat_runstate_guest, &info, sizeof(info));
     }
     else
-        rc = __copy_to_guest(runstate_guest(v), &v->runstate, 1) !=
-             sizeof(v->runstate);
+        memcpy(v->runstate_guest, &v->runstate, sizeof(v->runstate));
 
-    if ( guest_handle )
+    if ( VM_ASSIST(v->domain, runstate_update_flag) )
     {
         v->runstate.state_entry_time &= ~XEN_RUNSTATE_UPDATE;
         smp_wmb();
-        __raw_copy_to_guest(guest_handle,
-                            (void *)(&v->runstate.state_entry_time + 1) - 1, 
1);
+        if ( has_32bit_shinfo((v)->domain) )
+            v->compat_runstate_guest->state_entry_time &= ~XEN_RUNSTATE_UPDATE;
+        else
+            v->runstate_guest->state_entry_time &= ~XEN_RUNSTATE_UPDATE;
     }
 
     update_guest_memory_policy(v, &policy);
-
-    return rc;
-}
-
-static void _update_runstate_area(struct vcpu *v)
-{
-    if ( !update_runstate_area(v) && is_pv_vcpu(v) &&
-         !(v->arch.flags & TF_kernel_mode) )
-        v->arch.pv.need_update_runstate_area = 1;
 }
 
 static inline bool need_full_gdt(const struct domain *d)
@@ -1779,7 +1766,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
 
     if ( prev != next )
     {
-        _update_runstate_area(prev);
+        update_runstate_area(prev);
         vpmu_switch_from(prev);
         np2m_schedule(NP2M_SCHEDLE_OUT);
     }
@@ -1841,7 +1828,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
 
     if ( prev != next )
     {
-        _update_runstate_area(next);
+        update_runstate_area(next);
 
         /* Must be done with interrupts enabled */
         vpmu_switch_to(next);
diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c
index a571d15c13..3046bd4bc9 100644
--- a/xen/arch/x86/hvm/dom0_build.c
+++ b/xen/arch/x86/hvm/dom0_build.c
@@ -421,7 +421,7 @@ static int __init pvh_setup_p2m(struct domain *d)
     pvh_setup_e820(d, nr_pages);
     do {
         preempted = false;
-        paging_set_allocation(d, dom0_paging_pages(d, nr_pages),
+        paging_set_allocation(d, dom0_paging_pages(d, nr_pages) * 10,
                               &preempted);
         process_pending_softirqs();
     } while ( preempted );
diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c
index 7e84b04082..027bcf4eb0 100644
--- a/xen/arch/x86/pv/domain.c
+++ b/xen/arch/x86/pv/domain.c
@@ -313,9 +313,6 @@ static void _toggle_guest_pt(struct vcpu *v)
     if ( !(v->arch.flags & TF_kernel_mode) )
         return;
 
-    if ( v->arch.pv.need_update_runstate_area && update_runstate_area(v) )
-        v->arch.pv.need_update_runstate_area = 0;
-
     if ( v->arch.pv.pending_system_time.version &&
          update_secondary_system_time(v, &v->arch.pv.pending_system_time) )
         v->arch.pv.pending_system_time.version = 0;
diff --git a/xen/arch/x86/x86_64/domain.c b/xen/arch/x86/x86_64/domain.c
index c46dccc25a..9734cd39ef 100644
--- a/xen/arch/x86/x86_64/domain.c
+++ b/xen/arch/x86/x86_64/domain.c
@@ -22,34 +22,21 @@ arch_compat_vcpu_op(
     {
     case VCPUOP_register_runstate_memory_area:
     {
-        struct compat_vcpu_register_runstate_memory_area area;
-        struct compat_vcpu_runstate_info info;
-
-        area.addr.p = 0;
+        union {
+            struct compat_vcpu_register_runstate_memory_area compat;
+            struct vcpu_register_runstate_memory_area native;
+        } area = { };
 
         rc = -EFAULT;
-        if ( copy_from_guest(&area.addr.h, arg, 1) )
+        if ( copy_from_guest(&area.compat.addr.v, arg, 1) )
             break;
 
-        if ( area.addr.h.c != area.addr.p ||
-             !compat_handle_okay(area.addr.h, 1) )
+        unmap_runstate_area(v);
+        rc = map_runstate_area(v, &area.native);
+        if ( rc )
             break;
 
-        rc = 0;
-        guest_from_compat_handle(v->runstate_guest.compat, area.addr.h);
-
-        if ( v == current )
-        {
-            XLAT_vcpu_runstate_info(&info, &v->runstate);
-        }
-        else
-        {
-            struct vcpu_runstate_info runstate;
-
-            vcpu_runstate_get(v, &runstate);
-            XLAT_vcpu_runstate_info(&info, &runstate);
-        }
-        __copy_to_guest(v->runstate_guest.compat, &info, 1);
+        update_runstate_area(v);
 
         break;
     }
diff --git a/xen/common/domain.c b/xen/common/domain.c
index c623daec56..3b362a38c8 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -15,6 +15,7 @@
 #include <xen/mm.h>
 #include <xen/event.h>
 #include <xen/vm_event.h>
+#include <xen/vmap.h>
 #include <xen/time.h>
 #include <xen/console.h>
 #include <xen/softirq.h>
@@ -1177,7 +1178,7 @@ int domain_soft_reset(struct domain *d)
 
     for_each_vcpu ( d, v )
     {
-        set_xen_guest_handle(runstate_guest(v), NULL);
+        unmap_runstate_area(v);
         unmap_vcpu_info(v);
     }
 
@@ -1318,6 +1319,96 @@ void unmap_vcpu_info(struct vcpu *v)
     put_page_and_type(mfn_to_page(mfn));
 }
 
+int map_runstate_area(struct vcpu *v,
+                      struct vcpu_register_runstate_memory_area *area)
+{
+    unsigned long offset;
+    unsigned int i;
+    size_t size =
+#ifdef CONFIG_COMPAT
+        has_32bit_shinfo((v)->domain) ? sizeof(*v->compat_runstate_guest) :
+#endif
+                                        sizeof(*v->runstate_guest);
+
+    if ( v->runstate_guest || v->runstate_nr )
+    {
+        ASSERT_UNREACHABLE();
+        return -EBUSY;
+    }
+
+    offset = area->addr.p & ~PAGE_MASK;
+
+    for ( i = 0; i < ARRAY_SIZE(v->runstate_mfn); i++ )
+    {
+        struct page_info *pg;
+#ifdef CONFIG_X86
+        p2m_type_t t;
+        struct domain *d = v->domain;
+        uint32_t pfec = PFEC_page_present;
+        gfn_t gfn = _gfn(paging_gva_to_gfn(v, area->addr.p, &pfec));
+
+        if ( gfn_eq(gfn, INVALID_GFN) )
+            goto release;
+
+        v->runstate_mfn[i] = get_gfn(d, gfn_x(gfn), &t);
+        if ( t != p2m_ram_rw || mfn_eq(v->runstate_mfn[i], INVALID_MFN) )
+            goto release;
+
+        pg = mfn_to_page(v->runstate_mfn[i]);
+        if ( !pg || !get_page_and_type(pg, d, PGT_writable_page) )
+        {
+            put_gfn(d, gfn_x(gfn));
+            goto release;
+        }
+        put_gfn(d, gfn_x(gfn));
+#elif defined(CONFIG_ARM)
+        pg = get_page_from_gva(v, area->addr.p, GV2M_WRITE);
+        if ( !pg || !get_page_type(pg, PGT_writable_page) )
+            goto release;
+
+        v->runstate_mfn[i] = page_to_mfn(pg);
+#else
+#error Unsopported arquitecture
+#endif
+
+        v->runstate_nr++;
+
+        if ( offset + size <= PAGE_SIZE )
+            break;
+
+        area->addr.p += PAGE_SIZE - offset;
+    }
+
+    v->runstate_guest = vmap(v->runstate_mfn, v->runstate_nr);
+    if ( !v->runstate_guest )
+        goto release;
+    v->runstate_guest = (void *)v->runstate_guest + offset;
+
+    return 0;
+
+ release:
+    for ( i = 0; i < v->runstate_nr; i++)
+        put_page_and_type(mfn_to_page(v->runstate_mfn[i]));
+    v->runstate_nr = 0;
+
+    return -EFAULT;
+}
+
+void unmap_runstate_area(struct vcpu *v)
+{
+    unsigned int i;
+
+    if ( !v->runstate_guest )
+        return;
+
+    vunmap(v->runstate_guest);
+    for ( i = 0; i < v->runstate_nr; i++ )
+        put_page_and_type(mfn_to_page(v->runstate_mfn[i]));
+
+    v->runstate_guest = NULL;
+    v->runstate_nr = 0;
+}
+
 int default_initialise_vcpu(struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg)
 {
     struct vcpu_guest_context *ctxt;
@@ -1495,27 +1586,17 @@ long do_vcpu_op(int cmd, unsigned int vcpuid, 
XEN_GUEST_HANDLE_PARAM(void) arg)
     case VCPUOP_register_runstate_memory_area:
     {
         struct vcpu_register_runstate_memory_area area;
-        struct vcpu_runstate_info runstate;
 
         rc = -EFAULT;
         if ( copy_from_guest(&area, arg, 1) )
             break;
 
-        if ( !guest_handle_okay(area.addr.h, 1) )
+        unmap_runstate_area(v);
+        rc = map_runstate_area(v, &area);
+        if ( rc )
             break;
 
-        rc = 0;
-        runstate_guest(v) = area.addr.h;
-
-        if ( v == current )
-        {
-            __copy_to_guest(runstate_guest(v), &v->runstate, 1);
-        }
-        else
-        {
-            vcpu_runstate_get(v, &runstate);
-            __copy_to_guest(runstate_guest(v), &runstate, 1);
-        }
+        update_runstate_area(v);
 
         break;
     }
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 277f99f633..5cf22a32a2 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -554,7 +554,6 @@ struct pv_vcpu
     uint32_t dr7_emul;
 
     /* Deferred VA-based update state. */
-    bool_t need_update_runstate_area;
     struct vcpu_time_info pending_system_time;
 };
 
@@ -646,7 +645,6 @@ struct guest_memory_policy
 void update_guest_memory_policy(struct vcpu *v,
                                 struct guest_memory_policy *policy);
 
-bool update_runstate_area(struct vcpu *);
 bool update_secondary_system_time(struct vcpu *,
                                   struct vcpu_time_info *);
 
diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
index d1bfc82f57..88d3d96317 100644
--- a/xen/include/xen/domain.h
+++ b/xen/include/xen/domain.h
@@ -118,4 +118,10 @@ struct vnuma_info {
 
 void vnuma_destroy(struct vnuma_info *vnuma);
 
+struct vcpu_register_runstate_memory_area;
+int map_runstate_area(struct vcpu *v,
+                      struct vcpu_register_runstate_memory_area *area);
+void unmap_runstate_area(struct vcpu *v);
+void update_runstate_area(struct vcpu *);
+
 #endif /* __XEN_DOMAIN_H__ */
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 86f15b11e0..cb4bec9e0c 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -163,15 +163,15 @@ struct vcpu
     void            *sched_priv;    /* scheduler-specific data */
 
     struct vcpu_runstate_info runstate;
+    mfn_t runstate_mfn[2];
+    unsigned int runstate_nr;
 #ifndef CONFIG_COMPAT
-# define runstate_guest(v) ((v)->runstate_guest)
-    XEN_GUEST_HANDLE(vcpu_runstate_info_t) runstate_guest; /* guest address */
+    struct vcpu_runstate_info *runstate_guest;
 #else
-# define runstate_guest(v) ((v)->runstate_guest.native)
     union {
-        XEN_GUEST_HANDLE(vcpu_runstate_info_t) native;
-        XEN_GUEST_HANDLE(vcpu_runstate_info_compat_t) compat;
-    } runstate_guest; /* guest address */
+        struct vcpu_runstate_info *runstate_guest;
+        struct compat_vcpu_runstate_info *compat_runstate_guest;
+    };
 #endif
 
     /* last time when vCPU is scheduled out */


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

 


Rackspace

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