diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/entry-common.S | 8 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 85 | ||||
-rw-r--r-- | arch/arm/kernel/signal.h | 2 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 2 |
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: | |||
53 | work_pending: | 53 | work_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 4e5fdd9bd9e3..17fc36c41cff 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 | */ | ||
59 | const 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 | */ |
67 | asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) | 54 | asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) |
@@ -82,10 +69,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
82 | old_sigset_t mask; | 69 | old_sigset_t mask; |
83 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 70 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
84 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 71 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
85 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 72 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || |
73 | __get_user(new_ka.sa.sa_flags, &act->sa_flags) || | ||
74 | __get_user(mask, &act->sa_mask)) | ||
86 | return -EFAULT; | 75 | return -EFAULT; |
87 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
88 | __get_user(mask, &act->sa_mask); | ||
89 | siginitset(&new_ka.sa.sa_mask, mask); | 76 | siginitset(&new_ka.sa.sa_mask, mask); |
90 | } | 77 | } |
91 | 78 | ||
@@ -94,10 +81,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
94 | if (!ret && oact) { | 81 | if (!ret && oact) { |
95 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 82 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
96 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 83 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
97 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 84 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || |
85 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || | ||
86 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) | ||
98 | return -EFAULT; | 87 | return -EFAULT; |
99 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
100 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
101 | } | 88 | } |
102 | 89 | ||
103 | return ret; | 90 | return ret; |
@@ -602,15 +589,6 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
602 | int signr; | 589 | int signr; |
603 | 590 | ||
604 | /* | 591 | /* |
605 | * We want the common case to go fast, which | ||
606 | * is why we may in certain cases get here from | ||
607 | * kernel mode. Just return without doing anything | ||
608 | * if so. | ||
609 | */ | ||
610 | if (!user_mode(regs)) | ||
611 | return; | ||
612 | |||
613 | /* | ||
614 | * If we were from a system call, check for system call restarting... | 592 | * If we were from a system call, check for system call restarting... |
615 | */ | 593 | */ |
616 | if (syscall) { | 594 | if (syscall) { |
@@ -626,18 +604,13 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
626 | case -ERESTARTNOHAND: | 604 | case -ERESTARTNOHAND: |
627 | case -ERESTARTSYS: | 605 | case -ERESTARTSYS: |
628 | case -ERESTARTNOINTR: | 606 | case -ERESTARTNOINTR: |
607 | case -ERESTART_RESTARTBLOCK: | ||
629 | regs->ARM_r0 = regs->ARM_ORIG_r0; | 608 | regs->ARM_r0 = regs->ARM_ORIG_r0; |
630 | regs->ARM_pc = restart_addr; | 609 | regs->ARM_pc = restart_addr; |
631 | break; | 610 | break; |
632 | case -ERESTART_RESTARTBLOCK: | ||
633 | regs->ARM_r0 = -EINTR; | ||
634 | break; | ||
635 | } | 611 | } |
636 | } | 612 | } |
637 | 613 | ||
638 | if (try_to_freeze()) | ||
639 | goto no_signal; | ||
640 | |||
641 | /* | 614 | /* |
642 | * Get the signal to deliver. When running under ptrace, at this | 615 | * Get the signal to deliver. When running under ptrace, at this |
643 | * point the debugger may change all our registers ... | 616 | * point the debugger may change all our registers ... |
@@ -652,12 +625,14 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
652 | * debugger has chosen to restart at a different PC. | 625 | * debugger has chosen to restart at a different PC. |
653 | */ | 626 | */ |
654 | if (regs->ARM_pc == restart_addr) { | 627 | if (regs->ARM_pc == restart_addr) { |
655 | if (retval == -ERESTARTNOHAND | 628 | if (retval == -ERESTARTNOHAND || |
629 | retval == -ERESTART_RESTARTBLOCK | ||
656 | || (retval == -ERESTARTSYS | 630 | || (retval == -ERESTARTSYS |
657 | && !(ka.sa.sa_flags & SA_RESTART))) { | 631 | && !(ka.sa.sa_flags & SA_RESTART))) { |
658 | regs->ARM_r0 = -EINTR; | 632 | regs->ARM_r0 = -EINTR; |
659 | regs->ARM_pc = continue_addr; | 633 | regs->ARM_pc = continue_addr; |
660 | } | 634 | } |
635 | clear_thread_flag(TIF_SYSCALL_RESTARTSYS); | ||
661 | } | 636 | } |
662 | 637 | ||
663 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 638 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
@@ -677,7 +652,6 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
677 | return; | 652 | return; |
678 | } | 653 | } |
679 | 654 | ||
680 | no_signal: | ||
681 | if (syscall) { | 655 | if (syscall) { |
682 | /* | 656 | /* |
683 | * Handle restarting a different system call. As above, | 657 | * Handle restarting a different system call. As above, |
@@ -685,38 +659,15 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
685 | * ignore the restart. | 659 | * ignore the restart. |
686 | */ | 660 | */ |
687 | if (retval == -ERESTART_RESTARTBLOCK | 661 | if (retval == -ERESTART_RESTARTBLOCK |
688 | && regs->ARM_pc == continue_addr) { | 662 | && regs->ARM_pc == restart_addr) |
689 | if (thumb_mode(regs)) { | 663 | set_thread_flag(TIF_SYSCALL_RESTARTSYS); |
690 | regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; | ||
691 | regs->ARM_pc -= 2; | ||
692 | } else { | ||
693 | #if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) | ||
694 | regs->ARM_r7 = __NR_restart_syscall; | ||
695 | regs->ARM_pc -= 4; | ||
696 | #else | ||
697 | u32 __user *usp; | ||
698 | |||
699 | regs->ARM_sp -= 4; | ||
700 | usp = (u32 __user *)regs->ARM_sp; | ||
701 | |||
702 | if (put_user(regs->ARM_pc, usp) == 0) { | ||
703 | regs->ARM_pc = KERN_RESTART_CODE; | ||
704 | } else { | ||
705 | regs->ARM_sp += 4; | ||
706 | force_sigsegv(0, current); | ||
707 | } | ||
708 | #endif | ||
709 | } | ||
710 | } | ||
711 | |||
712 | /* If there's no signal to deliver, we just put the saved sigmask | ||
713 | * back. | ||
714 | */ | ||
715 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
716 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
717 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
718 | } | ||
719 | } | 664 | } |
665 | |||
666 | /* If there's no signal to deliver, we just put the saved sigmask | ||
667 | * back. | ||
668 | */ | ||
669 | if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) | ||
670 | set_current_blocked(¤t->saved_sigmask); | ||
720 | } | 671 | } |
721 | 672 | ||
722 | asmlinkage void | 673 | asmlinkage 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 | ||
13 | extern const unsigned long sigreturn_codes[7]; | 12 | extern const unsigned long sigreturn_codes[7]; |
14 | extern 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); |