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

[Xen-devel] [PATCH v2] xen: arm: correctly handle continuations for 64-bit guests



The 64-bit ABI is different to 32-bit:

 - uses x16 as the op register rather than r12.
 - arguments in x0..x5 and not r0..r5. Using rN here potentially
   truncates.
 - return value goes in x0, not r0.

Hypercalls can only be made directly from kernel space, so checking
the domain's size is sufficient.

Spotted due to spurious -EFAULT when destroying a domain, due to the
hypercall's pointer argument being truncated. I'm unclear why I am
only seeing this now.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
Reviewed-by: Julien Grall <julien.grall@xxxxxxxxxx>
---
I imagine this needs backporting everywhere...

v2: Pull regs->pc update out of the conditional blocks, no need to
mess around with thumb.

For reference the git diff -b version of this is:
                diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
                index 939d8cd..887fc10 100644
                --- a/xen/arch/arm/domain.c
                +++ b/xen/arch/arm/domain.c
                @@ -357,11 +357,38 @@ unsigned long 
hypercall_create_continuation(
                     else
                     {
                         regs = guest_cpu_user_regs();
                -        regs->r12 = op;

                         /* Ensure the hypercall trap instruction is 
re-executed. */
                         regs->pc -= 4;  /* re-execute 'hvc #XEN_HYPERCALL_TAG' 
*/

                +#ifdef CONFIG_ARM_64
                +        if ( !is_32bit_domain(current->domain) )
                +        {
                +            regs->x16 = op;
                +
                +            for ( i = 0; *p != '\0'; i++ )
                +            {
                +                arg = next_arg(p, args);
                +
                +                switch ( i )
                +                {
                +                case 0: regs->x0 = arg; break;
                +                case 1: regs->x1 = arg; break;
                +                case 2: regs->x2 = arg; break;
                +                case 3: regs->x3 = arg; break;
                +                case 4: regs->x4 = arg; break;
                +                case 5: regs->x5 = arg; break;
                +                }
                +            }
                +
                +            /* Return value gets written back to x0 */
                +            rc = regs->x0;
                +        }
                +        else
                +#endif
                +        {
                +            regs->r12 = op;
                +
                             for ( i = 0; *p != '\0'; i++ )
                             {
                                 arg = next_arg(p, args);
                @@ -380,6 +407,7 @@ unsigned long hypercall_create_continuation(
                             /* Return value gets written back to r0 */
                             rc = regs->r0;
                         }
                +    }

                     va_end(args);
---
 xen/arch/arm/domain.c |   54 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 41 insertions(+), 13 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 939d8cd..887fc10 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -356,29 +356,57 @@ unsigned long hypercall_create_continuation(
     }
     else
     {
-        regs      = guest_cpu_user_regs();
-        regs->r12 = op;
+        regs = guest_cpu_user_regs();
 
         /* Ensure the hypercall trap instruction is re-executed. */
         regs->pc -= 4;  /* re-execute 'hvc #XEN_HYPERCALL_TAG' */
 
-        for ( i = 0; *p != '\0'; i++ )
+#ifdef CONFIG_ARM_64
+        if ( !is_32bit_domain(current->domain) )
         {
-            arg = next_arg(p, args);
+            regs->x16 = op;
 
-            switch ( i )
+            for ( i = 0; *p != '\0'; i++ )
             {
-            case 0: regs->r0 = arg; break;
-            case 1: regs->r1 = arg; break;
-            case 2: regs->r2 = arg; break;
-            case 3: regs->r3 = arg; break;
-            case 4: regs->r4 = arg; break;
-            case 5: regs->r5 = arg; break;
+                arg = next_arg(p, args);
+
+                switch ( i )
+                {
+                case 0: regs->x0 = arg; break;
+                case 1: regs->x1 = arg; break;
+                case 2: regs->x2 = arg; break;
+                case 3: regs->x3 = arg; break;
+                case 4: regs->x4 = arg; break;
+                case 5: regs->x5 = arg; break;
+                }
             }
+
+            /* Return value gets written back to x0 */
+            rc = regs->x0;
         }
+        else
+#endif
+        {
+            regs->r12 = op;
 
-        /* Return value gets written back to r0 */
-        rc = regs->r0;
+            for ( i = 0; *p != '\0'; i++ )
+            {
+                arg = next_arg(p, args);
+
+                switch ( i )
+                {
+                case 0: regs->r0 = arg; break;
+                case 1: regs->r1 = arg; break;
+                case 2: regs->r2 = arg; break;
+                case 3: regs->r3 = arg; break;
+                case 4: regs->r4 = arg; break;
+                case 5: regs->r5 = arg; break;
+                }
+            }
+
+            /* Return value gets written back to r0 */
+            rc = regs->r0;
+        }
     }
 
     va_end(args);
-- 
1.7.10.4


_______________________________________________
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®.