mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
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:
1 parent
c73c58741f
commit
7466b88ec2
1 file changed
+43
-15
+43
-15
@@ -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);
|
||||
|
||||