aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2006-06-22 17:18:45 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-06-22 17:18:45 -0400
commitf606a6ff222dc7dceeb4d0e214ce4f55d9c6b0e6 (patch)
tree6a44374b8085d5523743268f67bae7fd70e25a43 /arch
parent92b7eb8ffc0741f1fd5fbd5458a466d608310442 (diff)
[ARM] 3626/1: ARM EABI: fix syscall restarting
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kernel/signal.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index a0cd0a90a10d..e9fe78033361 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -665,17 +665,33 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
665 if (syscall) { 665 if (syscall) {
666 if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { 666 if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
667 if (thumb_mode(regs)) { 667 if (thumb_mode(regs)) {
668 regs->ARM_r7 = __NR_restart_syscall; 668 regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
669 regs->ARM_pc -= 2; 669 regs->ARM_pc -= 2;
670 } else { 670 } else {
671#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
672 regs->ARM_r7 = __NR_restart_syscall;
673 regs->ARM_pc -= 4;
674#else
671 u32 __user *usp; 675 u32 __user *usp;
676 u32 swival = __NR_restart_syscall;
672 677
673 regs->ARM_sp -= 12; 678 regs->ARM_sp -= 12;
674 usp = (u32 __user *)regs->ARM_sp; 679 usp = (u32 __user *)regs->ARM_sp;
675 680
681 /*
682 * Either we supports OABI only, or we have
683 * EABI with the OABI compat layer enabled.
684 * In the later case we don't know if user
685 * space is EABI or not, and if not we must
686 * not clobber r7. Always using the OABI
687 * syscall solves that issue and works for
688 * all those cases.
689 */
690 swival = swival - __NR_SYSCAll_BASE + __NR_OABI_SYSCALL_BASE;
691
676 put_user(regs->ARM_pc, &usp[0]); 692 put_user(regs->ARM_pc, &usp[0]);
677 /* swi __NR_restart_syscall */ 693 /* swi __NR_restart_syscall */
678 put_user(0xef000000 | __NR_restart_syscall, &usp[1]); 694 put_user(0xef000000 | swival, &usp[1]);
679 /* ldr pc, [sp], #12 */ 695 /* ldr pc, [sp], #12 */
680 put_user(0xe49df00c, &usp[2]); 696 put_user(0xe49df00c, &usp[2]);
681 697
@@ -683,6 +699,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
683 (unsigned long)(usp + 3)); 699 (unsigned long)(usp + 3));
684 700
685 regs->ARM_pc = regs->ARM_sp + 4; 701 regs->ARM_pc = regs->ARM_sp + 4;
702#endif
686 } 703 }
687 } 704 }
688 if (regs->ARM_r0 == -ERESTARTNOHAND || 705 if (regs->ARM_r0 == -ERESTARTNOHAND ||