aboutsummaryrefslogtreecommitdiffstats
path: root/arch/openrisc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-30 20:08:41 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-30 20:08:41 -0500
commit04a24ae45d018e177db7e4ae2d03a70f79149782 (patch)
tree4ff6f4a560d146c3e8547cfe0fc6b7c37b45f73a /arch/openrisc
parent4bcec913d0a98d991c750034a04675443d1f10b5 (diff)
parent548dafe880ad84d0accc0a5596c26e3348b103e1 (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
Diffstat (limited to 'arch/openrisc')
-rw-r--r--arch/openrisc/kernel/entry.S59
-rw-r--r--arch/openrisc/kernel/signal.c233
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
8701:
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
8841:
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
36struct rt_sigframe { 37struct 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
44static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) 43static 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(&regs->pc, &sc->regs.pc, sizeof(unsigned long));
58 if (__copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long))) 58 err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
59 goto badframe;
60 if (__copy_from_user(&regs->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
73badframe:
74 return 1;
75} 71}
76 72
77asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) 73asmlinkage 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
114static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, 110static 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, &regs->pc, sizeof(unsigned long)); 119 err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long));
123 err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long)); 120 err |= __copy_to_user(&sc->regs.sr, &regs->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 */
176static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 169static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
177 sigset_t *set, struct pt_regs *regs) 170 struct pt_regs *regs)
178{ 171{
179 struct rt_sigframe *frame; 172 struct rt_sigframe *frame;
180 unsigned long return_ip; 173 unsigned long return_ip;
181 int err = 0; 174 int err = 0;
182 175
183 frame = get_sigframe(ka, regs, sizeof(*frame)); 176 frame = get_sigframe(&ksig->ka, regs, sizeof(*frame));
184 177
185 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) 178 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
186 goto give_sigsegv; 179 return -EFAULT;
187 180
188 err |= __put_user(&frame->info, &frame->pinfo); 181 /* Create siginfo. */
189 err |= __put_user(&frame->uc, &frame->puc); 182 if (ksig->ka.sa.sa_flags & SA_SIGINFO)
183 err |= copy_siginfo_to_user(&frame->info, &ksig->info);
190 184
191 if (ka->sa.sa_flags & SA_SIGINFO) 185 /* Create the ucontext. */
192 err |= copy_siginfo_to_user(&frame->info, info);
193 if (err)
194 goto give_sigsegv;
195
196 /* Clear all the bits of the ucontext we don't use. */
197 err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
198 err |= __put_user(0, &frame->uc.uc_flags); 186 err |= __put_user(0, &frame->uc.uc_flags);
199 err |= __put_user(NULL, &frame->uc.uc_link); 187 err |= __put_user(NULL, &frame->uc.uc_link);
200 err |= __save_altstack(&frame->uc.uc_stack, regs->sp); 188 err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
201 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); 189 err |= setup_sigcontext(regs, &frame->uc.uc_mcontext);
202 190
203 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 191 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
204 192
205 if (err) 193 if (err)
206 goto give_sigsegv; 194 return -EFAULT;
207 195
208 /* trampoline - the desired return ip is the retcode itself */ 196 /* trampoline - the desired return ip is the retcode itself */
209 return_ip = (unsigned long)&frame->retcode; 197 return_ip = (unsigned long)&frame->retcode;
210 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */ 198 /* This is:
211 err |= __put_user(0xa960, (short *)(frame->retcode + 0)); 199 l.ori r11,r0,__NR_sigreturn
212 err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2)); 200 l.sys 1
201 */
202 err |= __put_user(0xa960, (short *)(frame->retcode + 0));
203 err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2));
213 err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4)); 204 err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
214 err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8)); 205 err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
215 206
216 if (err) 207 if (err)
217 goto give_sigsegv; 208 return -EFAULT;
218 209
219 /* TODO what is the current->exec_domain stuff and invmap ? */ 210 /* TODO what is the current->exec_domain stuff and invmap ? */
220 211
221 /* Set up registers for signal handler */ 212 /* Set up registers for signal handler */
222 regs->pc = (unsigned long)ka->sa.sa_handler; /* what we enter NOW */ 213 regs->pc = (unsigned long)ksig->ka.sa.sa_handler; /* what we enter NOW */
223 regs->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */ 214 regs->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
224 regs->gpr[3] = (unsigned long)sig; /* arg 1: signo */ 215 regs->gpr[3] = (unsigned long)ksig->sig; /* arg 1: signo */
225 regs->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */ 216 regs->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
226 regs->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */ 217 regs->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
227 218
@@ -229,25 +220,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
229 regs->sp = (unsigned long)frame; 220 regs->sp = (unsigned long)frame;
230 221
231 return 0; 222 return 0;
232
233give_sigsegv:
234 force_sigsegv(sig, current);
235 return -EFAULT;
236} 223}
237 224
238static inline void 225static inline void
239handle_signal(unsigned long sig, 226handle_signal(struct ksignal *ksig, struct pt_regs *regs)
240 siginfo_t *info, struct k_sigaction *ka,
241 struct pt_regs *regs)
242{ 227{
243 int ret; 228 int ret;
244 229
245 ret = setup_rt_frame(sig, ka, info, sigmask_to_save(), regs); 230 ret = setup_rt_frame(ksig, sigmask_to_save(), regs);
246 if (ret)
247 return;
248 231
249 signal_delivered(sig, info, ka, regs, 232 signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
250 test_thread_flag(TIF_SINGLESTEP));
251} 233}
252 234
253/* 235/*
@@ -262,82 +244,99 @@ handle_signal(unsigned long sig,
262 * mode below. 244 * mode below.
263 */ 245 */
264 246
265void do_signal(struct pt_regs *regs) 247int do_signal(struct pt_regs *regs, int syscall)
266{ 248{
267 siginfo_t info; 249 struct ksignal ksig;
268 int signr; 250 unsigned long continue_addr = 0;
269 struct k_sigaction ka; 251 unsigned long restart_addr = 0;
270 252 unsigned long retval = 0;
271 /* 253 int restart = 0;
272 * We want the common case to go fast, which 254
273 * is why we may in certain cases get here from 255 if (syscall) {
274 * kernel mode. Just return without doing anything 256 continue_addr = regs->pc;
275 * if so. 257 restart_addr = continue_addr - 4;
276 */ 258 retval = regs->gpr[11];
277 if (!user_mode(regs)) 259
278 return; 260 /*
279 261 * Setup syscall restart here so that a debugger will
280 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 262 * see the already changed PC.
281 263 */
282 /* If we are coming out of a syscall then we need 264 switch (retval) {
283 * to check if the syscall was interrupted and wants to be
284 * restarted after handling the signal. If so, the original
285 * syscall number is put back into r11 and the PC rewound to
286 * point at the l.sys instruction that resulted in the
287 * original syscall. Syscall results other than the four
288 * below mean that the syscall executed to completion and no
289 * restart is necessary.
290 */
291 if (regs->orig_gpr11) {
292 int restart = 0;
293
294 switch (regs->gpr[11]) {
295 case -ERESTART_RESTARTBLOCK: 265 case -ERESTART_RESTARTBLOCK:
266 restart = -2;
267 /* Fall through */
296 case -ERESTARTNOHAND: 268 case -ERESTARTNOHAND:
297 /* Restart if there is no signal handler */
298 restart = (signr <= 0);
299 break;
300 case -ERESTARTSYS: 269 case -ERESTARTSYS:
301 /* Restart if there no signal handler or
302 * SA_RESTART flag is set */
303 restart = (signr <= 0 || (ka.sa.sa_flags & SA_RESTART));
304 break;
305 case -ERESTARTNOINTR: 270 case -ERESTARTNOINTR:
306 /* Always restart */ 271 restart++;
307 restart = 1; 272 regs->gpr[11] = regs->orig_gpr11;
273 regs->pc = restart_addr;
308 break; 274 break;
309 } 275 }
310
311 if (restart) {
312 if (regs->gpr[11] == -ERESTART_RESTARTBLOCK)
313 regs->gpr[11] = __NR_restart_syscall;
314 else
315 regs->gpr[11] = regs->orig_gpr11;
316 regs->pc -= 4;
317 } else {
318 regs->gpr[11] = -EINTR;
319 }
320 } 276 }
321 277
322 if (signr <= 0) { 278 /*
323 /* no signal to deliver so we just put the saved sigmask 279 * Get the signal to deliver. During the call to get_signal the
324 * back */ 280 * debugger may change all our registers so we may need to revert
281 * the decision to restart the syscall; specifically, if the PC is
282 * changed, don't restart the syscall.
283 */
284 if (get_signal(&ksig)) {
285 if (unlikely(restart) && regs->pc == restart_addr) {
286 if (retval == -ERESTARTNOHAND ||
287 retval == -ERESTART_RESTARTBLOCK
288 || (retval == -ERESTARTSYS
289 && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
290 /* No automatic restart */
291 regs->gpr[11] = -EINTR;
292 regs->pc = continue_addr;
293 }
294 }
295 handle_signal(&ksig, regs);
296 } else {
297 /* no handler */
325 restore_saved_sigmask(); 298 restore_saved_sigmask();
326 } else { /* signr > 0 */ 299 /*
327 /* Whee! Actually deliver the signal. */ 300 * Restore pt_regs PC as syscall restart will be handled by
328 handle_signal(signr, &info, &ka, regs); 301 * kernel without return to userspace
302 */
303 if (unlikely(restart) && regs->pc == restart_addr) {
304 regs->pc = continue_addr;
305 return restart;
306 }
329 } 307 }
330 308
331 return; 309 return 0;
332} 310}
333 311
334asmlinkage void do_notify_resume(struct pt_regs *regs) 312asmlinkage int
313do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
335{ 314{
336 if (current_thread_info()->flags & _TIF_SIGPENDING) 315 do {
337 do_signal(regs); 316 if (likely(thread_flags & _TIF_NEED_RESCHED)) {
338 317 schedule();
339 if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) { 318 } else {
340 clear_thread_flag(TIF_NOTIFY_RESUME); 319 if (unlikely(!user_mode(regs)))
341 tracehook_notify_resume(regs); 320 return 0;
342 } 321 local_irq_enable();
322 if (thread_flags & _TIF_SIGPENDING) {
323 int restart = do_signal(regs, syscall);
324 if (unlikely(restart)) {
325 /*
326 * Restart without handlers.
327 * Deal with it without leaving
328 * the kernel space.
329 */
330 return restart;
331 }
332 syscall = 0;
333 } else {
334 clear_thread_flag(TIF_NOTIFY_RESUME);
335 tracehook_notify_resume(regs);
336 }
337 }
338 local_irq_disable();
339 thread_flags = current_thread_info()->flags;
340 } while (thread_flags & _TIF_WORK_MASK);
341 return 0;
343} 342}