aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/signal.c')
-rw-r--r--arch/arm/kernel/signal.c45
1 files changed, 21 insertions, 24 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 1423a341978..e7714f367eb 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * linux/arch/arm/kernel/signal.c 2 * linux/arch/arm/kernel/signal.c
3 * 3 *
4 * Copyright (C) 1995-2002 Russell King 4 * Copyright (C) 1995-2009 Russell King
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
@@ -29,6 +29,7 @@
29 */ 29 */
30#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)) 30#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))
31#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) 31#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE))
32#define SWI_SYS_RESTART (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE)
32 33
33/* 34/*
34 * With EABI, the syscall number has to be loaded into r7. 35 * With EABI, the syscall number has to be loaded into r7.
@@ -49,6 +50,18 @@ const unsigned long sigreturn_codes[7] = {
49}; 50};
50 51
51/* 52/*
53 * Either we support OABI only, or we have EABI with the OABI
54 * compat layer enabled. In the later case we don't know if
55 * user space is EABI or not, and if not we must not clobber r7.
56 * Always using the OABI syscall solves that issue and works for
57 * all those cases.
58 */
59const unsigned long syscall_restart_code[2] = {
60 SWI_SYS_RESTART, /* swi __NR_restart_syscall */
61 0xe49df004, /* ldr pc, [sp], #4 */
62};
63
64/*
52 * atomically swap in the new signal mask, and wait for a signal. 65 * atomically swap in the new signal mask, and wait for a signal.
53 */ 66 */
54asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) 67asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
@@ -645,32 +658,16 @@ static void do_signal(struct pt_regs *regs, int syscall)
645 regs->ARM_pc -= 4; 658 regs->ARM_pc -= 4;
646#else 659#else
647 u32 __user *usp; 660 u32 __user *usp;
648 u32 swival = __NR_restart_syscall;
649 661
650 regs->ARM_sp -= 12; 662 regs->ARM_sp -= 4;
651 usp = (u32 __user *)regs->ARM_sp; 663 usp = (u32 __user *)regs->ARM_sp;
652 664
653 /* 665 if (put_user(regs->ARM_pc, usp) == 0) {
654 * Either we supports OABI only, or we have 666 regs->ARM_pc = KERN_RESTART_CODE;
655 * EABI with the OABI compat layer enabled. 667 } else {
656 * In the later case we don't know if user 668 regs->ARM_sp += 4;
657 * space is EABI or not, and if not we must 669 force_sigsegv(0, current);
658 * not clobber r7. Always using the OABI 670 }
659 * syscall solves that issue and works for
660 * all those cases.
661 */
662 swival = swival - __NR_SYSCALL_BASE + __NR_OABI_SYSCALL_BASE;
663
664 put_user(regs->ARM_pc, &usp[0]);
665 /* swi __NR_restart_syscall */
666 put_user(0xef000000 | swival, &usp[1]);
667 /* ldr pc, [sp], #12 */
668 put_user(0xe49df00c, &usp[2]);
669
670 flush_icache_range((unsigned long)usp,
671 (unsigned long)(usp + 3));
672
673 regs->ARM_pc = regs->ARM_sp + 4;
674#endif 671#endif
675 } 672 }
676 } 673 }