[ARM] 3626/1: ARM EABI: fix syscall restarting
authorNicolas Pitre <nico@cam.org>
Thu, 22 Jun 2006 21:18:45 +0000 (22:18 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 22 Jun 2006 21:18:45 +0000 (22:18 +0100)
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>
arch/arm/kernel/signal.c

index a0cd0a90a10d06f4bd266db044937796337c1eb3..e9fe78033361c676d714194457152d7e8d4185dd 100644 (file)
@@ -665,17 +665,33 @@ 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]);
 
@@ -683,6 +699,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
                                                   (unsigned long)(usp + 3));
 
                                regs->ARM_pc = regs->ARM_sp + 4;
+#endif
                        }
                }
                if (regs->ARM_r0 == -ERESTARTNOHAND ||