diff options
Diffstat (limited to 'arch/sparc/kernel/signal_32.c')
-rw-r--r-- | arch/sparc/kernel/signal_32.c | 175 |
1 files changed, 61 insertions, 114 deletions
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 68f9c8650af4..7d5d8e1f8415 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c | |||
@@ -59,18 +59,6 @@ struct rt_signal_frame { | |||
59 | #define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7))) | 59 | #define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7))) |
60 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) | 60 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) |
61 | 61 | ||
62 | static int _sigpause_common(old_sigset_t set) | ||
63 | { | ||
64 | sigset_t blocked; | ||
65 | siginitset(&blocked, set); | ||
66 | return sigsuspend(&blocked); | ||
67 | } | ||
68 | |||
69 | asmlinkage int sys_sigsuspend(old_sigset_t set) | ||
70 | { | ||
71 | return _sigpause_common(set); | ||
72 | } | ||
73 | |||
74 | asmlinkage void do_sigreturn(struct pt_regs *regs) | 62 | asmlinkage void do_sigreturn(struct pt_regs *regs) |
75 | { | 63 | { |
76 | struct signal_frame __user *sf; | 64 | struct signal_frame __user *sf; |
@@ -141,9 +129,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) | |||
141 | unsigned int psr, pc, npc; | 129 | unsigned int psr, pc, npc; |
142 | __siginfo_fpu_t __user *fpu_save; | 130 | __siginfo_fpu_t __user *fpu_save; |
143 | __siginfo_rwin_t __user *rwin_save; | 131 | __siginfo_rwin_t __user *rwin_save; |
144 | mm_segment_t old_fs; | ||
145 | sigset_t set; | 132 | sigset_t set; |
146 | stack_t st; | ||
147 | int err; | 133 | int err; |
148 | 134 | ||
149 | synchronize_user_stack(); | 135 | synchronize_user_stack(); |
@@ -171,8 +157,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) | |||
171 | if (!err && fpu_save) | 157 | if (!err && fpu_save) |
172 | err |= restore_fpu_state(regs, fpu_save); | 158 | err |= restore_fpu_state(regs, fpu_save); |
173 | err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); | 159 | err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); |
174 | 160 | err |= restore_altstack(&sf->stack); | |
175 | err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t)); | ||
176 | 161 | ||
177 | if (err) | 162 | if (err) |
178 | goto segv; | 163 | goto segv; |
@@ -180,14 +165,6 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) | |||
180 | regs->pc = pc; | 165 | regs->pc = pc; |
181 | regs->npc = npc; | 166 | regs->npc = npc; |
182 | 167 | ||
183 | /* It is more difficult to avoid calling this function than to | ||
184 | * call it and ignore errors. | ||
185 | */ | ||
186 | old_fs = get_fs(); | ||
187 | set_fs(KERNEL_DS); | ||
188 | do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf); | ||
189 | set_fs(old_fs); | ||
190 | |||
191 | err |= __get_user(rwin_save, &sf->rwin_save); | 168 | err |= __get_user(rwin_save, &sf->rwin_save); |
192 | if (!err && rwin_save) { | 169 | if (!err && rwin_save) { |
193 | if (restore_rwin_state(rwin_save)) | 170 | if (restore_rwin_state(rwin_save)) |
@@ -209,7 +186,7 @@ static inline int invalid_frame_pointer(void __user *fp, int fplen) | |||
209 | return 0; | 186 | return 0; |
210 | } | 187 | } |
211 | 188 | ||
212 | static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) | 189 | static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) |
213 | { | 190 | { |
214 | unsigned long sp = regs->u_regs[UREG_FP]; | 191 | unsigned long sp = regs->u_regs[UREG_FP]; |
215 | 192 | ||
@@ -221,12 +198,7 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re | |||
221 | return (void __user *) -1L; | 198 | return (void __user *) -1L; |
222 | 199 | ||
223 | /* This is the X/Open sanctioned signal stack switching. */ | 200 | /* This is the X/Open sanctioned signal stack switching. */ |
224 | if (sa->sa_flags & SA_ONSTACK) { | 201 | sp = sigsp(sp, ksig) - framesize; |
225 | if (sas_ss_flags(sp) == 0) | ||
226 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
227 | } | ||
228 | |||
229 | sp -= framesize; | ||
230 | 202 | ||
231 | /* Always align the stack frame. This handles two cases. First, | 203 | /* Always align the stack frame. This handles two cases. First, |
232 | * sigaltstack need not be mindful of platform specific stack | 204 | * sigaltstack need not be mindful of platform specific stack |
@@ -239,8 +211,8 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re | |||
239 | return (void __user *) sp; | 211 | return (void __user *) sp; |
240 | } | 212 | } |
241 | 213 | ||
242 | static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | 214 | static int setup_frame(struct ksignal *ksig, struct pt_regs *regs, |
243 | int signo, sigset_t *oldset) | 215 | sigset_t *oldset) |
244 | { | 216 | { |
245 | struct signal_frame __user *sf; | 217 | struct signal_frame __user *sf; |
246 | int sigframe_size, err, wsaved; | 218 | int sigframe_size, err, wsaved; |
@@ -258,10 +230,12 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
258 | sigframe_size += sizeof(__siginfo_rwin_t); | 230 | sigframe_size += sizeof(__siginfo_rwin_t); |
259 | 231 | ||
260 | sf = (struct signal_frame __user *) | 232 | sf = (struct signal_frame __user *) |
261 | get_sigframe(&ka->sa, regs, sigframe_size); | 233 | get_sigframe(ksig, regs, sigframe_size); |
262 | 234 | ||
263 | if (invalid_frame_pointer(sf, sigframe_size)) | 235 | if (invalid_frame_pointer(sf, sigframe_size)) { |
264 | goto sigill_and_return; | 236 | do_exit(SIGILL); |
237 | return -EINVAL; | ||
238 | } | ||
265 | 239 | ||
266 | tail = sf + 1; | 240 | tail = sf + 1; |
267 | 241 | ||
@@ -300,21 +274,21 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
300 | err |= __copy_to_user(sf, rp, sizeof(struct reg_window32)); | 274 | err |= __copy_to_user(sf, rp, sizeof(struct reg_window32)); |
301 | } | 275 | } |
302 | if (err) | 276 | if (err) |
303 | goto sigsegv; | 277 | return err; |
304 | 278 | ||
305 | /* 3. signal handler back-trampoline and parameters */ | 279 | /* 3. signal handler back-trampoline and parameters */ |
306 | regs->u_regs[UREG_FP] = (unsigned long) sf; | 280 | regs->u_regs[UREG_FP] = (unsigned long) sf; |
307 | regs->u_regs[UREG_I0] = signo; | 281 | regs->u_regs[UREG_I0] = ksig->sig; |
308 | regs->u_regs[UREG_I1] = (unsigned long) &sf->info; | 282 | regs->u_regs[UREG_I1] = (unsigned long) &sf->info; |
309 | regs->u_regs[UREG_I2] = (unsigned long) &sf->info; | 283 | regs->u_regs[UREG_I2] = (unsigned long) &sf->info; |
310 | 284 | ||
311 | /* 4. signal handler */ | 285 | /* 4. signal handler */ |
312 | regs->pc = (unsigned long) ka->sa.sa_handler; | 286 | regs->pc = (unsigned long) ksig->ka.sa.sa_handler; |
313 | regs->npc = (regs->pc + 4); | 287 | regs->npc = (regs->pc + 4); |
314 | 288 | ||
315 | /* 5. return to kernel instructions */ | 289 | /* 5. return to kernel instructions */ |
316 | if (ka->ka_restorer) | 290 | if (ksig->ka.ka_restorer) |
317 | regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; | 291 | regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer; |
318 | else { | 292 | else { |
319 | regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); | 293 | regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); |
320 | 294 | ||
@@ -324,24 +298,16 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
324 | /* t 0x10 */ | 298 | /* t 0x10 */ |
325 | err |= __put_user(0x91d02010, &sf->insns[1]); | 299 | err |= __put_user(0x91d02010, &sf->insns[1]); |
326 | if (err) | 300 | if (err) |
327 | goto sigsegv; | 301 | return err; |
328 | 302 | ||
329 | /* Flush instruction space. */ | 303 | /* Flush instruction space. */ |
330 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); | 304 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); |
331 | } | 305 | } |
332 | return 0; | 306 | return 0; |
333 | |||
334 | sigill_and_return: | ||
335 | do_exit(SIGILL); | ||
336 | return -EINVAL; | ||
337 | |||
338 | sigsegv: | ||
339 | force_sigsegv(signo, current); | ||
340 | return -EFAULT; | ||
341 | } | 307 | } |
342 | 308 | ||
343 | static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | 309 | static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs, |
344 | int signo, sigset_t *oldset, siginfo_t *info) | 310 | sigset_t *oldset) |
345 | { | 311 | { |
346 | struct rt_signal_frame __user *sf; | 312 | struct rt_signal_frame __user *sf; |
347 | int sigframe_size, wsaved; | 313 | int sigframe_size, wsaved; |
@@ -357,9 +323,11 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
357 | if (wsaved) | 323 | if (wsaved) |
358 | sigframe_size += sizeof(__siginfo_rwin_t); | 324 | sigframe_size += sizeof(__siginfo_rwin_t); |
359 | sf = (struct rt_signal_frame __user *) | 325 | sf = (struct rt_signal_frame __user *) |
360 | get_sigframe(&ka->sa, regs, sigframe_size); | 326 | get_sigframe(ksig, regs, sigframe_size); |
361 | if (invalid_frame_pointer(sf, sigframe_size)) | 327 | if (invalid_frame_pointer(sf, sigframe_size)) { |
362 | goto sigill; | 328 | do_exit(SIGILL); |
329 | return -EINVAL; | ||
330 | } | ||
363 | 331 | ||
364 | tail = sf + 1; | 332 | tail = sf + 1; |
365 | err = __put_user(regs->pc, &sf->regs.pc); | 333 | err = __put_user(regs->pc, &sf->regs.pc); |
@@ -391,9 +359,7 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
391 | err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t)); | 359 | err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t)); |
392 | 360 | ||
393 | /* Setup sigaltstack */ | 361 | /* Setup sigaltstack */ |
394 | err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); | 362 | err |= __save_altstack(&sf->stack, regs->u_regs[UREG_FP]); |
395 | err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); | ||
396 | err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); | ||
397 | 363 | ||
398 | if (!wsaved) { | 364 | if (!wsaved) { |
399 | err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], | 365 | err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], |
@@ -405,21 +371,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
405 | err |= __copy_to_user(sf, rp, sizeof(struct reg_window32)); | 371 | err |= __copy_to_user(sf, rp, sizeof(struct reg_window32)); |
406 | } | 372 | } |
407 | 373 | ||
408 | err |= copy_siginfo_to_user(&sf->info, info); | 374 | err |= copy_siginfo_to_user(&sf->info, &ksig->info); |
409 | 375 | ||
410 | if (err) | 376 | if (err) |
411 | goto sigsegv; | 377 | return err; |
412 | 378 | ||
413 | regs->u_regs[UREG_FP] = (unsigned long) sf; | 379 | regs->u_regs[UREG_FP] = (unsigned long) sf; |
414 | regs->u_regs[UREG_I0] = signo; | 380 | regs->u_regs[UREG_I0] = ksig->sig; |
415 | regs->u_regs[UREG_I1] = (unsigned long) &sf->info; | 381 | regs->u_regs[UREG_I1] = (unsigned long) &sf->info; |
416 | regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; | 382 | regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; |
417 | 383 | ||
418 | regs->pc = (unsigned long) ka->sa.sa_handler; | 384 | regs->pc = (unsigned long) ksig->ka.sa.sa_handler; |
419 | regs->npc = (regs->pc + 4); | 385 | regs->npc = (regs->pc + 4); |
420 | 386 | ||
421 | if (ka->ka_restorer) | 387 | if (ksig->ka.ka_restorer) |
422 | regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; | 388 | regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer; |
423 | else { | 389 | else { |
424 | regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); | 390 | regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); |
425 | 391 | ||
@@ -429,38 +395,25 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
429 | /* t 0x10 */ | 395 | /* t 0x10 */ |
430 | err |= __put_user(0x91d02010, &sf->insns[1]); | 396 | err |= __put_user(0x91d02010, &sf->insns[1]); |
431 | if (err) | 397 | if (err) |
432 | goto sigsegv; | 398 | return err; |
433 | 399 | ||
434 | /* Flush instruction space. */ | 400 | /* Flush instruction space. */ |
435 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); | 401 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); |
436 | } | 402 | } |
437 | return 0; | 403 | return 0; |
438 | |||
439 | sigill: | ||
440 | do_exit(SIGILL); | ||
441 | return -EINVAL; | ||
442 | |||
443 | sigsegv: | ||
444 | force_sigsegv(signo, current); | ||
445 | return -EFAULT; | ||
446 | } | 404 | } |
447 | 405 | ||
448 | static inline void | 406 | static inline void |
449 | handle_signal(unsigned long signr, struct k_sigaction *ka, | 407 | handle_signal(struct ksignal *ksig, struct pt_regs *regs) |
450 | siginfo_t *info, struct pt_regs *regs) | ||
451 | { | 408 | { |
452 | sigset_t *oldset = sigmask_to_save(); | 409 | sigset_t *oldset = sigmask_to_save(); |
453 | int err; | 410 | int err; |
454 | 411 | ||
455 | if (ka->sa.sa_flags & SA_SIGINFO) | 412 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) |
456 | err = setup_rt_frame(ka, regs, signr, oldset, info); | 413 | err = setup_rt_frame(ksig, regs, oldset); |
457 | else | 414 | else |
458 | err = setup_frame(ka, regs, signr, oldset); | 415 | err = setup_frame(ksig, regs, oldset); |
459 | 416 | signal_setup_done(err, ksig, 0); | |
460 | if (err) | ||
461 | return; | ||
462 | |||
463 | signal_delivered(signr, info, ka, regs, 0); | ||
464 | } | 417 | } |
465 | 418 | ||
466 | static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | 419 | static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, |
@@ -490,10 +443,9 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | |||
490 | */ | 443 | */ |
491 | static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | 444 | static void do_signal(struct pt_regs *regs, unsigned long orig_i0) |
492 | { | 445 | { |
493 | struct k_sigaction ka; | 446 | struct ksignal ksig; |
494 | int restart_syscall; | 447 | int restart_syscall; |
495 | siginfo_t info; | 448 | bool has_handler; |
496 | int signr; | ||
497 | 449 | ||
498 | /* It's a lot of work and synchronization to add a new ptrace | 450 | /* It's a lot of work and synchronization to add a new ptrace |
499 | * register for GDB to save and restore in order to get | 451 | * register for GDB to save and restore in order to get |
@@ -516,7 +468,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
516 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) | 468 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) |
517 | regs->u_regs[UREG_G6] = orig_i0; | 469 | regs->u_regs[UREG_G6] = orig_i0; |
518 | 470 | ||
519 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 471 | has_handler = get_signal(&ksig); |
520 | 472 | ||
521 | /* If the debugger messes with the program counter, it clears | 473 | /* If the debugger messes with the program counter, it clears |
522 | * the software "in syscall" bit, directing us to not perform | 474 | * the software "in syscall" bit, directing us to not perform |
@@ -528,35 +480,30 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
528 | orig_i0 = regs->u_regs[UREG_G6]; | 480 | orig_i0 = regs->u_regs[UREG_G6]; |
529 | } | 481 | } |
530 | 482 | ||
531 | 483 | if (has_handler) { | |
532 | if (signr > 0) { | ||
533 | if (restart_syscall) | 484 | if (restart_syscall) |
534 | syscall_restart(orig_i0, regs, &ka.sa); | 485 | syscall_restart(orig_i0, regs, &ksig.ka.sa); |
535 | handle_signal(signr, &ka, &info, regs); | 486 | handle_signal(&ksig, regs); |
536 | return; | 487 | } else { |
537 | } | 488 | if (restart_syscall) { |
538 | if (restart_syscall && | 489 | switch (regs->u_regs[UREG_I0]) { |
539 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | 490 | case ERESTARTNOHAND: |
540 | regs->u_regs[UREG_I0] == ERESTARTSYS || | 491 | case ERESTARTSYS: |
541 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | 492 | case ERESTARTNOINTR: |
542 | /* replay the system call when we are done */ | 493 | /* replay the system call when we are done */ |
543 | regs->u_regs[UREG_I0] = orig_i0; | 494 | regs->u_regs[UREG_I0] = orig_i0; |
544 | regs->pc -= 4; | 495 | regs->pc -= 4; |
545 | regs->npc -= 4; | 496 | regs->npc -= 4; |
546 | pt_regs_clear_syscall(regs); | 497 | pt_regs_clear_syscall(regs); |
547 | } | 498 | case ERESTART_RESTARTBLOCK: |
548 | if (restart_syscall && | 499 | regs->u_regs[UREG_G1] = __NR_restart_syscall; |
549 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | 500 | regs->pc -= 4; |
550 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | 501 | regs->npc -= 4; |
551 | regs->pc -= 4; | 502 | pt_regs_clear_syscall(regs); |
552 | regs->npc -= 4; | 503 | } |
553 | pt_regs_clear_syscall(regs); | 504 | } |
505 | restore_saved_sigmask(); | ||
554 | } | 506 | } |
555 | |||
556 | /* if there's no signal to deliver, we just put the saved sigmask | ||
557 | * back | ||
558 | */ | ||
559 | restore_saved_sigmask(); | ||
560 | } | 507 | } |
561 | 508 | ||
562 | void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, | 509 | void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, |