aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-05-29 17:13:55 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-05-29 17:13:55 -0400
commite94c805f0c234ef54609f23695b60add6b25ad40 (patch)
tree09e116c62b065316eb93070e78a1843d9055373a /arch/arm/kernel
parentef0c14842e6e04b860d0309c5d5a3c1ead344e35 (diff)
parent70b58d896b1b30e4b89d369fbeb244c0e952cf9f (diff)
Merge branch 'for-arm' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal.git into for-linus
Conflicts: arch/arm/kernel/ptrace.c
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/entry-common.S8
-rw-r--r--arch/arm/kernel/ptrace.c3
-rw-r--r--arch/arm/kernel/signal.c85
-rw-r--r--arch/arm/kernel/signal.h2
-rw-r--r--arch/arm/kernel/traps.c2
5 files changed, 27 insertions, 73 deletions
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 7bd2d3cb8957..4afed88d250a 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -53,9 +53,13 @@ fast_work_pending:
53work_pending: 53work_pending:
54 tst r1, #_TIF_NEED_RESCHED 54 tst r1, #_TIF_NEED_RESCHED
55 bne work_resched 55 bne work_resched
56 tst r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME 56 /*
57 beq no_work_pending 57 * TIF_SIGPENDING or TIF_NOTIFY_RESUME must've been set if we got here
58 */
59 ldr r2, [sp, #S_PSR]
58 mov r0, sp @ 'regs' 60 mov r0, sp @ 'regs'
61 tst r2, #15 @ are we returning to user mode?
62 bne no_work_pending @ no? just leave, then...
59 mov r2, why @ 'syscall' 63 mov r2, why @ 'syscall'
60 tst r1, #_TIF_SIGPENDING @ delivering a signal? 64 tst r1, #_TIF_SIGPENDING @ delivering a signal?
61 movne why, #0 @ prevent further restarts 65 movne why, #0 @ prevent further restarts
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 14e38261cd31..5700a7ae7f0b 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -25,6 +25,7 @@
25#include <linux/regset.h> 25#include <linux/regset.h>
26#include <linux/audit.h> 26#include <linux/audit.h>
27#include <linux/tracehook.h> 27#include <linux/tracehook.h>
28#include <linux/unistd.h>
28 29
29#include <asm/pgtable.h> 30#include <asm/pgtable.h>
30#include <asm/traps.h> 31#include <asm/traps.h>
@@ -917,6 +918,8 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
917 audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, 918 audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
918 regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); 919 regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
919 920
921 if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS))
922 scno = __NR_restart_syscall - __NR_SYSCALL_BASE;
920 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 923 if (!test_thread_flag(TIF_SYSCALL_TRACE))
921 return scno; 924 return scno;
922 925
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 73d9a420850d..b7ffda1ad8f2 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -29,7 +29,6 @@
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)
33 32
34/* 33/*
35 * With EABI, the syscall number has to be loaded into r7. 34 * With EABI, the syscall number has to be loaded into r7.
@@ -50,18 +49,6 @@ const unsigned long sigreturn_codes[7] = {
50}; 49};
51 50
52/* 51/*
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/*
65 * atomically swap in the new signal mask, and wait for a signal. 52 * atomically swap in the new signal mask, and wait for a signal.
66 */ 53 */
67asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) 54asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
@@ -91,10 +78,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
91 old_sigset_t mask; 78 old_sigset_t mask;
92 if (!access_ok(VERIFY_READ, act, sizeof(*act)) || 79 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
93 __get_user(new_ka.sa.sa_handler, &act->sa_handler) || 80 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
94 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) 81 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
82 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
83 __get_user(mask, &act->sa_mask))
95 return -EFAULT; 84 return -EFAULT;
96 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
97 __get_user(mask, &act->sa_mask);
98 siginitset(&new_ka.sa.sa_mask, mask); 85 siginitset(&new_ka.sa.sa_mask, mask);
99 } 86 }
100 87
@@ -103,10 +90,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
103 if (!ret && oact) { 90 if (!ret && oact) {
104 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || 91 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
105 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || 92 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
106 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) 93 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
94 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
95 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
107 return -EFAULT; 96 return -EFAULT;
108 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
109 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
110 } 97 }
111 98
112 return ret; 99 return ret;
@@ -611,15 +598,6 @@ static void do_signal(struct pt_regs *regs, int syscall)
611 int signr; 598 int signr;
612 599
613 /* 600 /*
614 * We want the common case to go fast, which
615 * is why we may in certain cases get here from
616 * kernel mode. Just return without doing anything
617 * if so.
618 */
619 if (!user_mode(regs))
620 return;
621
622 /*
623 * If we were from a system call, check for system call restarting... 601 * If we were from a system call, check for system call restarting...
624 */ 602 */
625 if (syscall) { 603 if (syscall) {
@@ -635,18 +613,13 @@ static void do_signal(struct pt_regs *regs, int syscall)
635 case -ERESTARTNOHAND: 613 case -ERESTARTNOHAND:
636 case -ERESTARTSYS: 614 case -ERESTARTSYS:
637 case -ERESTARTNOINTR: 615 case -ERESTARTNOINTR:
616 case -ERESTART_RESTARTBLOCK:
638 regs->ARM_r0 = regs->ARM_ORIG_r0; 617 regs->ARM_r0 = regs->ARM_ORIG_r0;
639 regs->ARM_pc = restart_addr; 618 regs->ARM_pc = restart_addr;
640 break; 619 break;
641 case -ERESTART_RESTARTBLOCK:
642 regs->ARM_r0 = -EINTR;
643 break;
644 } 620 }
645 } 621 }
646 622
647 if (try_to_freeze())
648 goto no_signal;
649
650 /* 623 /*
651 * Get the signal to deliver. When running under ptrace, at this 624 * Get the signal to deliver. When running under ptrace, at this
652 * point the debugger may change all our registers ... 625 * point the debugger may change all our registers ...
@@ -661,12 +634,14 @@ static void do_signal(struct pt_regs *regs, int syscall)
661 * debugger has chosen to restart at a different PC. 634 * debugger has chosen to restart at a different PC.
662 */ 635 */
663 if (regs->ARM_pc == restart_addr) { 636 if (regs->ARM_pc == restart_addr) {
664 if (retval == -ERESTARTNOHAND 637 if (retval == -ERESTARTNOHAND ||
638 retval == -ERESTART_RESTARTBLOCK
665 || (retval == -ERESTARTSYS 639 || (retval == -ERESTARTSYS
666 && !(ka.sa.sa_flags & SA_RESTART))) { 640 && !(ka.sa.sa_flags & SA_RESTART))) {
667 regs->ARM_r0 = -EINTR; 641 regs->ARM_r0 = -EINTR;
668 regs->ARM_pc = continue_addr; 642 regs->ARM_pc = continue_addr;
669 } 643 }
644 clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
670 } 645 }
671 646
672 if (test_thread_flag(TIF_RESTORE_SIGMASK)) 647 if (test_thread_flag(TIF_RESTORE_SIGMASK))
@@ -686,7 +661,6 @@ static void do_signal(struct pt_regs *regs, int syscall)
686 return; 661 return;
687 } 662 }
688 663
689 no_signal:
690 if (syscall) { 664 if (syscall) {
691 /* 665 /*
692 * Handle restarting a different system call. As above, 666 * Handle restarting a different system call. As above,
@@ -694,38 +668,15 @@ static void do_signal(struct pt_regs *regs, int syscall)
694 * ignore the restart. 668 * ignore the restart.
695 */ 669 */
696 if (retval == -ERESTART_RESTARTBLOCK 670 if (retval == -ERESTART_RESTARTBLOCK
697 && regs->ARM_pc == continue_addr) { 671 && regs->ARM_pc == restart_addr)
698 if (thumb_mode(regs)) { 672 set_thread_flag(TIF_SYSCALL_RESTARTSYS);
699 regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
700 regs->ARM_pc -= 2;
701 } else {
702#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
703 regs->ARM_r7 = __NR_restart_syscall;
704 regs->ARM_pc -= 4;
705#else
706 u32 __user *usp;
707
708 regs->ARM_sp -= 4;
709 usp = (u32 __user *)regs->ARM_sp;
710
711 if (put_user(regs->ARM_pc, usp) == 0) {
712 regs->ARM_pc = KERN_RESTART_CODE;
713 } else {
714 regs->ARM_sp += 4;
715 force_sigsegv(0, current);
716 }
717#endif
718 }
719 }
720
721 /* If there's no signal to deliver, we just put the saved sigmask
722 * back.
723 */
724 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
725 clear_thread_flag(TIF_RESTORE_SIGMASK);
726 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
727 }
728 } 673 }
674
675 /* If there's no signal to deliver, we just put the saved sigmask
676 * back.
677 */
678 if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
679 set_current_blocked(&current->saved_sigmask);
729} 680}
730 681
731asmlinkage void 682asmlinkage void
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
index 6fcfe8398aa4..5ff067b7c752 100644
--- a/arch/arm/kernel/signal.h
+++ b/arch/arm/kernel/signal.h
@@ -8,7 +8,5 @@
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) 10#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500)
11#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
12 11
13extern const unsigned long sigreturn_codes[7]; 12extern const unsigned long sigreturn_codes[7];
14extern const unsigned long syscall_restart_code[2];
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 3647170e9a16..4928d89758f4 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -820,8 +820,6 @@ void __init early_trap_init(void *vectors_base)
820 */ 820 */
821 memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), 821 memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
822 sigreturn_codes, sizeof(sigreturn_codes)); 822 sigreturn_codes, sizeof(sigreturn_codes));
823 memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
824 syscall_restart_code, sizeof(syscall_restart_code));
825 823
826 flush_icache_range(vectors, vectors + PAGE_SIZE); 824 flush_icache_range(vectors, vectors + PAGE_SIZE);
827 modify_domain(DOMAIN_USER, DOMAIN_CLIENT); 825 modify_domain(DOMAIN_USER, DOMAIN_CLIENT);