diff options
-rw-r--r-- | arch/alpha/kernel/signal.c | 111 |
1 files changed, 45 insertions, 66 deletions
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index b5f385055244..6cec2881acbf 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c | |||
@@ -272,12 +272,9 @@ give_sigsegv: | |||
272 | */ | 272 | */ |
273 | 273 | ||
274 | static inline void __user * | 274 | static inline void __user * |
275 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | 275 | get_sigframe(struct ksignal *ksig, unsigned long sp, size_t frame_size) |
276 | { | 276 | { |
277 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) | 277 | return (void __user *)((sigsp(sp, ksig) - frame_size) & -32ul); |
278 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
279 | |||
280 | return (void __user *)((sp - frame_size) & -32ul); | ||
281 | } | 278 | } |
282 | 279 | ||
283 | static long | 280 | static long |
@@ -338,14 +335,13 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
338 | } | 335 | } |
339 | 336 | ||
340 | static int | 337 | static int |
341 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 338 | setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) |
342 | struct pt_regs *regs) | ||
343 | { | 339 | { |
344 | unsigned long oldsp, r26, err = 0; | 340 | unsigned long oldsp, r26, err = 0; |
345 | struct sigframe __user *frame; | 341 | struct sigframe __user *frame; |
346 | 342 | ||
347 | oldsp = rdusp(); | 343 | oldsp = rdusp(); |
348 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); | 344 | frame = get_sigframe(ksig, oldsp, sizeof(*frame)); |
349 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 345 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
350 | return -EFAULT; | 346 | return -EFAULT; |
351 | 347 | ||
@@ -355,9 +351,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
355 | 351 | ||
356 | /* Set up to return from userspace. If provided, use a stub | 352 | /* Set up to return from userspace. If provided, use a stub |
357 | already in userspace. */ | 353 | already in userspace. */ |
358 | if (ka->ka_restorer) { | 354 | r26 = (unsigned long) ksig->ka.ka_restorer; |
359 | r26 = (unsigned long) ka->ka_restorer; | 355 | if (!r26) { |
360 | } else { | ||
361 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); | 356 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); |
362 | err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); | 357 | err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); |
363 | err |= __put_user(INSN_CALLSYS, frame->retcode+2); | 358 | err |= __put_user(INSN_CALLSYS, frame->retcode+2); |
@@ -371,8 +366,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
371 | 366 | ||
372 | /* "Return" to the handler */ | 367 | /* "Return" to the handler */ |
373 | regs->r26 = r26; | 368 | regs->r26 = r26; |
374 | regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; | 369 | regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler; |
375 | regs->r16 = sig; /* a0: signal number */ | 370 | regs->r16 = ksig->sig; /* a0: signal number */ |
376 | regs->r17 = 0; /* a1: exception code */ | 371 | regs->r17 = 0; /* a1: exception code */ |
377 | regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ | 372 | regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ |
378 | wrusp((unsigned long) frame); | 373 | wrusp((unsigned long) frame); |
@@ -385,18 +380,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
385 | } | 380 | } |
386 | 381 | ||
387 | static int | 382 | static int |
388 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 383 | setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) |
389 | sigset_t *set, struct pt_regs *regs) | ||
390 | { | 384 | { |
391 | unsigned long oldsp, r26, err = 0; | 385 | unsigned long oldsp, r26, err = 0; |
392 | struct rt_sigframe __user *frame; | 386 | struct rt_sigframe __user *frame; |
393 | 387 | ||
394 | oldsp = rdusp(); | 388 | oldsp = rdusp(); |
395 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); | 389 | frame = get_sigframe(ksig, oldsp, sizeof(*frame)); |
396 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 390 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
397 | return -EFAULT; | 391 | return -EFAULT; |
398 | 392 | ||
399 | err |= copy_siginfo_to_user(&frame->info, info); | 393 | err |= copy_siginfo_to_user(&frame->info, &ksig->info); |
400 | 394 | ||
401 | /* Create the ucontext. */ | 395 | /* Create the ucontext. */ |
402 | err |= __put_user(0, &frame->uc.uc_flags); | 396 | err |= __put_user(0, &frame->uc.uc_flags); |
@@ -411,9 +405,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
411 | 405 | ||
412 | /* Set up to return from userspace. If provided, use a stub | 406 | /* Set up to return from userspace. If provided, use a stub |
413 | already in userspace. */ | 407 | already in userspace. */ |
414 | if (ka->ka_restorer) { | 408 | r26 = (unsigned long) ksig->ka.ka_restorer; |
415 | r26 = (unsigned long) ka->ka_restorer; | 409 | if (!r26) { |
416 | } else { | ||
417 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); | 410 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); |
418 | err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, | 411 | err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, |
419 | frame->retcode+1); | 412 | frame->retcode+1); |
@@ -427,8 +420,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
427 | 420 | ||
428 | /* "Return" to the handler */ | 421 | /* "Return" to the handler */ |
429 | regs->r26 = r26; | 422 | regs->r26 = r26; |
430 | regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; | 423 | regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler; |
431 | regs->r16 = sig; /* a0: signal number */ | 424 | regs->r16 = ksig->sig; /* a0: signal number */ |
432 | regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ | 425 | regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ |
433 | regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */ | 426 | regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */ |
434 | wrusp((unsigned long) frame); | 427 | wrusp((unsigned long) frame); |
@@ -446,22 +439,17 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
446 | * OK, we're invoking a handler. | 439 | * OK, we're invoking a handler. |
447 | */ | 440 | */ |
448 | static inline void | 441 | static inline void |
449 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 442 | handle_signal(struct ksignal *ksig, struct pt_regs *regs) |
450 | struct pt_regs * regs) | ||
451 | { | 443 | { |
452 | sigset_t *oldset = sigmask_to_save(); | 444 | sigset_t *oldset = sigmask_to_save(); |
453 | int ret; | 445 | int ret; |
454 | 446 | ||
455 | if (ka->sa.sa_flags & SA_SIGINFO) | 447 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) |
456 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 448 | ret = setup_rt_frame(ksig, oldset, regs); |
457 | else | 449 | else |
458 | ret = setup_frame(sig, ka, oldset, regs); | 450 | ret = setup_frame(ksig, oldset, regs); |
459 | 451 | ||
460 | if (ret) { | 452 | signal_setup_done(ret, ksig, 0); |
461 | force_sigsegv(sig, current); | ||
462 | return; | ||
463 | } | ||
464 | signal_delivered(sig, info, ka, regs, 0); | ||
465 | } | 453 | } |
466 | 454 | ||
467 | static inline void | 455 | static inline void |
@@ -504,47 +492,38 @@ syscall_restart(unsigned long r0, unsigned long r19, | |||
504 | static void | 492 | static void |
505 | do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) | 493 | do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19) |
506 | { | 494 | { |
507 | siginfo_t info; | ||
508 | int signr; | ||
509 | unsigned long single_stepping = ptrace_cancel_bpt(current); | 495 | unsigned long single_stepping = ptrace_cancel_bpt(current); |
510 | struct k_sigaction ka; | 496 | struct ksignal ksig; |
511 | 497 | ||
512 | /* This lets the debugger run, ... */ | 498 | /* This lets the debugger run, ... */ |
513 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 499 | if (get_signal(&ksig)) { |
514 | 500 | /* ... so re-check the single stepping. */ | |
515 | /* ... so re-check the single stepping. */ | 501 | single_stepping |= ptrace_cancel_bpt(current); |
516 | single_stepping |= ptrace_cancel_bpt(current); | ||
517 | |||
518 | if (signr > 0) { | ||
519 | /* Whee! Actually deliver the signal. */ | 502 | /* Whee! Actually deliver the signal. */ |
520 | if (r0) | 503 | if (r0) |
521 | syscall_restart(r0, r19, regs, &ka); | 504 | syscall_restart(r0, r19, regs, &ksig.ka); |
522 | handle_signal(signr, &ka, &info, regs); | 505 | handle_signal(&ksig, regs); |
523 | if (single_stepping) | 506 | } else { |
524 | ptrace_set_bpt(current); /* re-set bpt */ | 507 | single_stepping |= ptrace_cancel_bpt(current); |
525 | return; | 508 | if (r0) { |
526 | } | 509 | switch (regs->r0) { |
527 | 510 | case ERESTARTNOHAND: | |
528 | if (r0) { | 511 | case ERESTARTSYS: |
529 | switch (regs->r0) { | 512 | case ERESTARTNOINTR: |
530 | case ERESTARTNOHAND: | 513 | /* Reset v0 and a3 and replay syscall. */ |
531 | case ERESTARTSYS: | 514 | regs->r0 = r0; |
532 | case ERESTARTNOINTR: | 515 | regs->r19 = r19; |
533 | /* Reset v0 and a3 and replay syscall. */ | 516 | regs->pc -= 4; |
534 | regs->r0 = r0; | 517 | break; |
535 | regs->r19 = r19; | 518 | case ERESTART_RESTARTBLOCK: |
536 | regs->pc -= 4; | 519 | /* Set v0 to the restart_syscall and replay */ |
537 | break; | 520 | regs->r0 = __NR_restart_syscall; |
538 | case ERESTART_RESTARTBLOCK: | 521 | regs->pc -= 4; |
539 | /* Force v0 to the restart syscall and reply. */ | 522 | break; |
540 | regs->r0 = __NR_restart_syscall; | 523 | } |
541 | regs->pc -= 4; | ||
542 | break; | ||
543 | } | 524 | } |
525 | restore_saved_sigmask(); | ||
544 | } | 526 | } |
545 | |||
546 | /* If there's no signal to deliver, we just restore the saved mask. */ | ||
547 | restore_saved_sigmask(); | ||
548 | if (single_stepping) | 527 | if (single_stepping) |
549 | ptrace_set_bpt(current); /* re-set breakpoint */ | 528 | ptrace_set_bpt(current); /* re-set breakpoint */ |
550 | } | 529 | } |