diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-30 20:08:41 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-30 20:08:41 -0500 |
| commit | 04a24ae45d018e177db7e4ae2d03a70f79149782 (patch) | |
| tree | 4ff6f4a560d146c3e8547cfe0fc6b7c37b45f73a | |
| parent | 4bcec913d0a98d991c750034a04675443d1f10b5 (diff) | |
| parent | 548dafe880ad84d0accc0a5596c26e3348b103e1 (diff) | |
Merge tag 'for-3.14' of git://openrisc.net/~jonas/linux
Pull OpenRISC updates from Jonas Bonn:
"The interesting change here is a rework of the OpenRISC signal
handling to make it more like other architectures in the hopes that
this makes it easier for others to comment on and understand. This
rework fixes some real bugs, like the fact that syscall restart did
not work reliably"
* tag 'for-3.14' of git://openrisc.net/~jonas/linux:
openrisc: Use get_signal() signal_setup_done()
openrisc: Rework signal handling
| -rw-r--r-- | arch/openrisc/kernel/entry.S | 59 | ||||
| -rw-r--r-- | arch/openrisc/kernel/signal.c | 233 |
2 files changed, 149 insertions, 143 deletions
diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index d8a455ede5a7..fec8bf97d806 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S | |||
| @@ -853,37 +853,44 @@ UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) | |||
| 853 | 853 | ||
| 854 | /* ========================================================[ return ] === */ | 854 | /* ========================================================[ return ] === */ |
| 855 | 855 | ||
| 856 | _resume_userspace: | ||
| 857 | DISABLE_INTERRUPTS(r3,r4) | ||
| 858 | l.lwz r4,TI_FLAGS(r10) | ||
| 859 | l.andi r13,r4,_TIF_WORK_MASK | ||
| 860 | l.sfeqi r13,0 | ||
| 861 | l.bf _restore_all | ||
| 862 | l.nop | ||
| 863 | |||
| 856 | _work_pending: | 864 | _work_pending: |
| 857 | /* | 865 | l.lwz r5,PT_ORIG_GPR11(r1) |
| 858 | * if (current_thread_info->flags & _TIF_NEED_RESCHED) | 866 | l.sfltsi r5,0 |
| 859 | * schedule(); | 867 | l.bnf 1f |
| 860 | */ | ||
| 861 | l.lwz r5,TI_FLAGS(r10) | ||
| 862 | l.andi r3,r5,_TIF_NEED_RESCHED | ||
| 863 | l.sfnei r3,0 | ||
| 864 | l.bnf _work_notifysig | ||
| 865 | l.nop | 868 | l.nop |
| 866 | l.jal schedule | 869 | l.andi r5,r5,0 |
| 870 | 1: | ||
| 871 | l.jal do_work_pending | ||
| 872 | l.ori r3,r1,0 /* pt_regs */ | ||
| 873 | |||
| 874 | l.sfeqi r11,0 | ||
| 875 | l.bf _restore_all | ||
| 867 | l.nop | 876 | l.nop |
| 868 | l.j _resume_userspace | 877 | l.sfltsi r11,0 |
| 878 | l.bnf 1f | ||
| 869 | l.nop | 879 | l.nop |
| 870 | 880 | l.and r11,r11,r0 | |
| 871 | /* Handle pending signals and notify-resume requests. | 881 | l.ori r11,r11,__NR_restart_syscall |
| 872 | * do_notify_resume must be passed the latest pushed pt_regs, not | 882 | l.j _syscall_check_trace_enter |
| 873 | * necessarily the "userspace" ones. Also, pt_regs->syscallno | ||
| 874 | * must be set so that the syscall restart functionality works. | ||
| 875 | */ | ||
| 876 | _work_notifysig: | ||
| 877 | l.jal do_notify_resume | ||
| 878 | l.ori r3,r1,0 /* pt_regs */ | ||
| 879 | |||
| 880 | _resume_userspace: | ||
| 881 | DISABLE_INTERRUPTS(r3,r4) | ||
| 882 | l.lwz r3,TI_FLAGS(r10) | ||
| 883 | l.andi r3,r3,_TIF_WORK_MASK | ||
| 884 | l.sfnei r3,0 | ||
| 885 | l.bf _work_pending | ||
| 886 | l.nop | 883 | l.nop |
| 884 | 1: | ||
| 885 | l.lwz r11,PT_ORIG_GPR11(r1) | ||
| 886 | /* Restore arg registers */ | ||
| 887 | l.lwz r3,PT_GPR3(r1) | ||
| 888 | l.lwz r4,PT_GPR4(r1) | ||
| 889 | l.lwz r5,PT_GPR5(r1) | ||
| 890 | l.lwz r6,PT_GPR6(r1) | ||
| 891 | l.lwz r7,PT_GPR7(r1) | ||
| 892 | l.j _syscall_check_trace_enter | ||
| 893 | l.lwz r8,PT_GPR8(r1) | ||
| 887 | 894 | ||
| 888 | _restore_all: | 895 | _restore_all: |
| 889 | RESTORE_ALL | 896 | RESTORE_ALL |
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c index ae167f7e081a..66775bc07a8e 100644 --- a/arch/openrisc/kernel/signal.c +++ b/arch/openrisc/kernel/signal.c | |||
| @@ -28,24 +28,24 @@ | |||
| 28 | #include <linux/tracehook.h> | 28 | #include <linux/tracehook.h> |
| 29 | 29 | ||
| 30 | #include <asm/processor.h> | 30 | #include <asm/processor.h> |
| 31 | #include <asm/syscall.h> | ||
| 31 | #include <asm/ucontext.h> | 32 | #include <asm/ucontext.h> |
| 32 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
| 33 | 34 | ||
| 34 | #define DEBUG_SIG 0 | 35 | #define DEBUG_SIG 0 |
| 35 | 36 | ||
| 36 | struct rt_sigframe { | 37 | struct rt_sigframe { |
| 37 | struct siginfo *pinfo; | ||
| 38 | void *puc; | ||
| 39 | struct siginfo info; | 38 | struct siginfo info; |
| 40 | struct ucontext uc; | 39 | struct ucontext uc; |
| 41 | unsigned char retcode[16]; /* trampoline code */ | 40 | unsigned char retcode[16]; /* trampoline code */ |
| 42 | }; | 41 | }; |
| 43 | 42 | ||
| 44 | static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) | 43 | static int restore_sigcontext(struct pt_regs *regs, |
| 44 | struct sigcontext __user *sc) | ||
| 45 | { | 45 | { |
| 46 | unsigned int err = 0; | 46 | int err = 0; |
| 47 | 47 | ||
| 48 | /* Alwys make any pending restarted system call return -EINTR */ | 48 | /* Always make any pending restarted system calls return -EINTR */ |
| 49 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 49 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| 50 | 50 | ||
| 51 | /* | 51 | /* |
| @@ -53,25 +53,21 @@ static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) | |||
| 53 | * (sc is already checked for VERIFY_READ since the sigframe was | 53 | * (sc is already checked for VERIFY_READ since the sigframe was |
| 54 | * checked in sys_sigreturn previously) | 54 | * checked in sys_sigreturn previously) |
| 55 | */ | 55 | */ |
| 56 | if (__copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long))) | 56 | err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)); |
| 57 | goto badframe; | 57 | err |= __copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long)); |
| 58 | if (__copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long))) | 58 | err |= __copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long)); |
| 59 | goto badframe; | ||
| 60 | if (__copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long))) | ||
| 61 | goto badframe; | ||
| 62 | 59 | ||
| 63 | /* make sure the SM-bit is cleared so user-mode cannot fool us */ | 60 | /* make sure the SM-bit is cleared so user-mode cannot fool us */ |
| 64 | regs->sr &= ~SPR_SR_SM; | 61 | regs->sr &= ~SPR_SR_SM; |
| 65 | 62 | ||
| 63 | regs->orig_gpr11 = -1; /* Avoid syscall restart checks */ | ||
| 64 | |||
| 66 | /* TODO: the other ports use regs->orig_XX to disable syscall checks | 65 | /* TODO: the other ports use regs->orig_XX to disable syscall checks |
| 67 | * after this completes, but we don't use that mechanism. maybe we can | 66 | * after this completes, but we don't use that mechanism. maybe we can |
| 68 | * use it now ? | 67 | * use it now ? |
| 69 | */ | 68 | */ |
| 70 | 69 | ||
| 71 | return err; | 70 | return err; |
| 72 | |||
| 73 | badframe: | ||
| 74 | return 1; | ||
| 75 | } | 71 | } |
| 76 | 72 | ||
| 77 | asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) | 73 | asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) |
| @@ -111,21 +107,18 @@ badframe: | |||
| 111 | * Set up a signal frame. | 107 | * Set up a signal frame. |
| 112 | */ | 108 | */ |
| 113 | 109 | ||
| 114 | static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | 110 | static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
| 115 | unsigned long mask) | ||
| 116 | { | 111 | { |
| 117 | int err = 0; | 112 | int err = 0; |
| 118 | 113 | ||
| 119 | /* copy the regs */ | 114 | /* copy the regs */ |
| 120 | 115 | /* There should be no need to save callee-saved registers here... | |
| 116 | * ...but we save them anyway. Revisit this | ||
| 117 | */ | ||
| 121 | err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long)); | 118 | err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long)); |
| 122 | err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long)); | 119 | err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long)); |
| 123 | err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long)); | 120 | err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long)); |
| 124 | 121 | ||
| 125 | /* then some other stuff */ | ||
| 126 | |||
| 127 | err |= __put_user(mask, &sc->oldmask); | ||
| 128 | |||
| 129 | return err; | 122 | return err; |
| 130 | } | 123 | } |
| 131 | 124 | ||
| @@ -173,55 +166,53 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, | |||
| 173 | * trampoline which performs the syscall sigreturn, or a provided | 166 | * trampoline which performs the syscall sigreturn, or a provided |
| 174 | * user-mode trampoline. | 167 | * user-mode trampoline. |
| 175 | */ | 168 | */ |
| 176 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 169 | static int setup_rt_frame(struct ksignal *ksig, sig |
