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@citrix.com>
Reviewed-by: Julien Grall <julien.grall@linaro.org>
This commit is contained in:
Ian Campbell committed 2015-03-30 09:35:12 +01:00
1 parent c73c58741f
commit 7466b88ec2
1 file changed
+43 -15
+43 -15
View File
@@ -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);
/* Return value gets written back to r0 */
rc = regs->r0;
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);
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);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.