Skip to content

Commit

Permalink
[ARM] 3626/1: ARM EABI: fix syscall restarting
Browse files Browse the repository at this point in the history
Patch from Nicolas Pitre

The RESTARTBLOCK case currently store some code on the stack to invoke
sys_restart_syscall.  However this is ABI dependent and there is a
mismatch with the way __NR_restart_syscall gets defined when the kernel
is compiled for EABI.

There is also a long standing bug in the thumb case since with OABI the
__NR_restart_syscall value includes __NR_SYSCALL_BASE which should not
be the case for Thumb syscalls.

Credits to Yauheni Kaliuta <yauheni.kaliuta@gmail.com> for finding the
EABI bug.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Nicolas Pitre authored and Russell King committed Jun 22, 2006
1 parent 92b7eb8 commit f606a6f
Showing 1 changed file with 19 additions and 2 deletions.
21 changes: 19 additions & 2 deletions arch/arm/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,24 +665,41 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
if (syscall) {
if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
if (thumb_mode(regs)) {
regs->ARM_r7 = __NR_restart_syscall;
regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
regs->ARM_pc -= 2;
} else {
#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
regs->ARM_r7 = __NR_restart_syscall;
regs->ARM_pc -= 4;
#else
u32 __user *usp;
u32 swival = __NR_restart_syscall;

regs->ARM_sp -= 12;
usp = (u32 __user *)regs->ARM_sp;

/*
* Either we supports OABI only, or we have
* EABI with the OABI compat layer enabled.
* In the later case we don't know if user
* space is EABI or not, and if not we must
* not clobber r7. Always using the OABI
* syscall solves that issue and works for
* all those cases.
*/
swival = swival - __NR_SYSCAll_BASE + __NR_OABI_SYSCALL_BASE;

put_user(regs->ARM_pc, &usp[0]);
/* swi __NR_restart_syscall */
put_user(0xef000000 | __NR_restart_syscall, &usp[1]);
put_user(0xef000000 | swival, &usp[1]);
/* ldr pc, [sp], #12 */
put_user(0xe49df00c, &usp[2]);

flush_icache_range((unsigned long)usp,
(unsigned long)(usp + 3));

regs->ARM_pc = regs->ARM_sp + 4;
#endif
}
}
if (regs->ARM_r0 == -ERESTARTNOHAND ||
Expand Down

0 comments on commit f606a6f

Please sign in to comment.