diff options
Diffstat (limited to 'arch/frv/kernel/signal.c')
-rw-r--r-- | arch/frv/kernel/signal.c | 155 |
1 files changed, 85 insertions, 70 deletions
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index d4ccc0728dfe..5b7146f54fd5 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c | |||
@@ -35,7 +35,7 @@ struct fdpic_func_descriptor { | |||
35 | unsigned long GOT; | 35 | unsigned long GOT; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | 38 | static int do_signal(sigset_t *oldset); |
39 | 39 | ||
40 | /* | 40 | /* |
41 | * Atomically swap in the new signal mask, and wait for a signal. | 41 | * Atomically swap in the new signal mask, and wait for a signal. |
@@ -55,7 +55,7 @@ asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) | |||
55 | while (1) { | 55 | while (1) { |
56 | current->state = TASK_INTERRUPTIBLE; | 56 | current->state = TASK_INTERRUPTIBLE; |
57 | schedule(); | 57 | schedule(); |
58 | if (do_signal(__frame, &saveset)) | 58 | if (do_signal(&saveset)) |
59 | /* return the signal number as the return value of this function | 59 | /* return the signal number as the return value of this function |
60 | * - this is an utterly evil hack. syscalls should not invoke do_signal() | 60 | * - this is an utterly evil hack. syscalls should not invoke do_signal() |
61 | * as entry.S sets regs->gr8 to the return value of the system call | 61 | * as entry.S sets regs->gr8 to the return value of the system call |
@@ -91,7 +91,7 @@ asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) | |||
91 | while (1) { | 91 | while (1) { |
92 | current->state = TASK_INTERRUPTIBLE; | 92 | current->state = TASK_INTERRUPTIBLE; |
93 | schedule(); | 93 | schedule(); |
94 | if (do_signal(__frame, &saveset)) | 94 | if (do_signal(&saveset)) |
95 | /* return the signal number as the return value of this function | 95 | /* return the signal number as the return value of this function |
96 | * - this is an utterly evil hack. syscalls should not invoke do_signal() | 96 | * - this is an utterly evil hack. syscalls should not invoke do_signal() |
97 | * as entry.S sets regs->gr8 to the return value of the system call | 97 | * as entry.S sets regs->gr8 to the return value of the system call |
@@ -276,13 +276,12 @@ static int setup_sigcontext(struct sigcontext __user *sc, unsigned long mask) | |||
276 | * Determine which stack to use.. | 276 | * Determine which stack to use.. |
277 | */ | 277 | */ |
278 | static inline void __user *get_sigframe(struct k_sigaction *ka, | 278 | static inline void __user *get_sigframe(struct k_sigaction *ka, |
279 | struct pt_regs *regs, | ||
280 | size_t frame_size) | 279 | size_t frame_size) |
281 | { | 280 | { |
282 | unsigned long sp; | 281 | unsigned long sp; |
283 | 282 | ||
284 | /* Default to using normal stack */ | 283 | /* Default to using normal stack */ |
285 | sp = regs->sp; | 284 | sp = __frame->sp; |
286 | 285 | ||
287 | /* This is the X/Open sanctioned signal stack switching. */ | 286 | /* This is the X/Open sanctioned signal stack switching. */ |
288 | if (ka->sa.sa_flags & SA_ONSTACK) { | 287 | if (ka->sa.sa_flags & SA_ONSTACK) { |
@@ -291,18 +290,19 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, | |||
291 | } | 290 | } |
292 | 291 | ||
293 | return (void __user *) ((sp - frame_size) & ~7UL); | 292 | return (void __user *) ((sp - frame_size) & ~7UL); |
293 | |||
294 | } /* end get_sigframe() */ | 294 | } /* end get_sigframe() */ |
295 | 295 | ||
296 | /*****************************************************************************/ | 296 | /*****************************************************************************/ |
297 | /* | 297 | /* |
298 | * | 298 | * |
299 | */ | 299 | */ |
300 | static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) | 300 | static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) |
301 | { | 301 | { |
302 | struct sigframe __user *frame; | 302 | struct sigframe __user *frame; |
303 | int rsig; | 303 | int rsig; |
304 | 304 | ||
305 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 305 | frame = get_sigframe(ka, sizeof(*frame)); |
306 | 306 | ||
307 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 307 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
308 | goto give_sigsegv; | 308 | goto give_sigsegv; |
@@ -346,47 +346,51 @@ static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct p | |||
346 | } | 346 | } |
347 | 347 | ||
348 | /* set up registers for signal handler */ | 348 | /* set up registers for signal handler */ |
349 | regs->sp = (unsigned long) frame; | 349 | __frame->sp = (unsigned long) frame; |
350 | regs->lr = (unsigned long) &frame->retcode; | 350 | __frame->lr = (unsigned long) &frame->retcode; |
351 | regs->gr8 = sig; | 351 | __frame->gr8 = sig; |
352 | 352 | ||
353 | if (get_personality & FDPIC_FUNCPTRS) { | 353 | if (get_personality & FDPIC_FUNCPTRS) { |
354 | struct fdpic_func_descriptor __user *funcptr = | 354 | struct fdpic_func_descriptor __user *funcptr = |
355 | (struct fdpic_func_descriptor *) ka->sa.sa_handler; | 355 | (struct fdpic_func_descriptor *) ka->sa.sa_handler; |
356 | __get_user(regs->pc, &funcptr->text); | 356 | __get_user(__frame->pc, &funcptr->text); |
357 | __get_user(regs->gr15, &funcptr->GOT); | 357 | __get_user(__frame->gr15, &funcptr->GOT); |
358 | } else { | 358 | } else { |
359 | regs->pc = (unsigned long) ka->sa.sa_handler; | 359 | __frame->pc = (unsigned long) ka->sa.sa_handler; |
360 | regs->gr15 = 0; | 360 | __frame->gr15 = 0; |
361 | } | 361 | } |
362 | 362 | ||
363 | set_fs(USER_DS); | 363 | set_fs(USER_DS); |
364 | 364 | ||
365 | /* the tracer may want to single-step inside the handler */ | ||
366 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
367 | ptrace_notify(SIGTRAP); | ||
368 | |||
365 | #if DEBUG_SIG | 369 | #if DEBUG_SIG |
366 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", | 370 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", |
367 | sig, current->comm, current->pid, frame, regs->pc, frame->pretcode); | 371 | sig, current->comm, current->pid, frame, __frame->pc, |
372 | frame->pretcode); | ||
368 | #endif | 373 | #endif |
369 | 374 | ||
370 | return; | 375 | return 1; |
371 | 376 | ||
372 | give_sigsegv: | 377 | give_sigsegv: |
373 | if (sig == SIGSEGV) | ||
374 | ka->sa.sa_handler = SIG_DFL; | ||
375 | |||
376 | force_sig(SIGSEGV, current); | 378 | force_sig(SIGSEGV, current); |
379 | return 0; | ||
380 | |||
377 | } /* end setup_frame() */ | 381 | } /* end setup_frame() */ |
378 | 382 | ||
379 | /*****************************************************************************/ | 383 | /*****************************************************************************/ |
380 | /* | 384 | /* |
381 | * | 385 | * |
382 | */ | 386 | */ |
383 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 387 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
384 | sigset_t *set, struct pt_regs * regs) | 388 | sigset_t *set) |
385 | { | 389 | { |
386 | struct rt_sigframe __user *frame; | 390 | struct rt_sigframe __user *frame; |
387 | int rsig; | 391 | int rsig; |
388 | 392 | ||
389 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 393 | frame = get_sigframe(ka, sizeof(*frame)); |
390 | 394 | ||
391 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 395 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
392 | goto give_sigsegv; | 396 | goto give_sigsegv; |
@@ -409,7 +413,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
409 | if (__put_user(0, &frame->uc.uc_flags) || | 413 | if (__put_user(0, &frame->uc.uc_flags) || |
410 | __put_user(0, &frame->uc.uc_link) || | 414 | __put_user(0, &frame->uc.uc_link) || |
411 | __put_user((void*)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || | 415 | __put_user((void*)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || |
412 | __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags) || | 416 | __put_user(sas_ss_flags(__frame->sp), &frame->uc.uc_stack.ss_flags) || |
413 | __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size)) | 417 | __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size)) |
414 | goto give_sigsegv; | 418 | goto give_sigsegv; |
415 | 419 | ||
@@ -440,34 +444,38 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
440 | } | 444 | } |
441 | 445 | ||
442 | /* Set up registers for signal handler */ | 446 | /* Set up registers for signal handler */ |
443 | regs->sp = (unsigned long) frame; | 447 | __frame->sp = (unsigned long) frame; |
444 | regs->lr = (unsigned long) &frame->retcode; | 448 | __frame->lr = (unsigned long) &frame->retcode; |
445 | regs->gr8 = sig; | 449 | __frame->gr8 = sig; |
446 | regs->gr9 = (unsigned long) &frame->info; | 450 | __frame->gr9 = (unsigned long) &frame->info; |
447 | 451 | ||
448 | if (get_personality & FDPIC_FUNCPTRS) { | 452 | if (get_personality & FDPIC_FUNCPTRS) { |
449 | struct fdpic_func_descriptor *funcptr = | 453 | struct fdpic_func_descriptor *funcptr = |
450 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; | 454 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; |
451 | __get_user(regs->pc, &funcptr->text); | 455 | __get_user(__frame->pc, &funcptr->text); |
452 | __get_user(regs->gr15, &funcptr->GOT); | 456 | __get_user(__frame->gr15, &funcptr->GOT); |
453 | } else { | 457 | } else { |
454 | regs->pc = (unsigned long) ka->sa.sa_handler; | 458 | __frame->pc = (unsigned long) ka->sa.sa_handler; |
455 | regs->gr15 = 0; | 459 | __frame->gr15 = 0; |
456 | } | 460 | } |
457 | 461 | ||
458 | set_fs(USER_DS); | 462 | set_fs(USER_DS); |
459 | 463 | ||
464 | /* the tracer may want to single-step inside the handler */ | ||
465 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
466 | ptrace_notify(SIGTRAP); | ||
467 | |||
460 | #if DEBUG_SIG | 468 | #if DEBUG_SIG |
461 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", | 469 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", |
462 | sig, current->comm, current->pid, frame, regs->pc, frame->pretcode); | 470 | sig, current->comm, current->pid, frame, __frame->pc, |
471 | frame->pretcode); | ||
463 | #endif | 472 | #endif |
464 | 473 | ||
465 | return; | 474 | return 1; |
466 | 475 | ||
467 | give_sigsegv: | 476 | give_sigsegv: |
468 | if (sig == SIGSEGV) | ||
469 | ka->sa.sa_handler = SIG_DFL; | ||
470 | force_sig(SIGSEGV, current); | 477 | force_sig(SIGSEGV, current); |
478 | return 0; | ||
471 | 479 | ||
472 | } /* end setup_rt_frame() */ | 480 | } /* end setup_rt_frame() */ |
473 | 481 | ||
@@ -475,43 +483,51 @@ give_sigsegv: | |||
475 | /* | 483 | /* |
476 | * OK, we're invoking a handler | 484 | * OK, we're invoking a handler |
477 | */ | 485 | */ |
478 | static void handle_signal(unsigned long sig, siginfo_t *info, | 486 | static int handle_signal(unsigned long sig, siginfo_t *info, |
479 | struct k_sigaction *ka, sigset_t *oldset, | 487 | struct k_sigaction *ka, sigset_t *oldset) |
480 | struct pt_regs *regs) | ||
481 | { | 488 | { |
489 | int ret; | ||
490 | |||
482 | /* Are we from a system call? */ | 491 | /* Are we from a system call? */ |
483 | if (in_syscall(regs)) { | 492 | if (in_syscall(__frame)) { |
484 | /* If so, check system call restarting.. */ | 493 | /* If so, check system call restarting.. */ |
485 | switch (regs->gr8) { | 494 | switch (__frame->gr8) { |
486 | case -ERESTART_RESTARTBLOCK: | 495 | case -ERESTART_RESTARTBLOCK: |
487 | case -ERESTARTNOHAND: | 496 | case -ERESTARTNOHAND: |
488 | regs->gr8 = -EINTR; | 497 | __frame->gr8 = -EINTR; |
489 | break; | 498 | break; |
490 | 499 | ||
491 | case -ERESTARTSYS: | 500 | case -ERESTARTSYS: |
492 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 501 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
493 | regs->gr8 = -EINTR; | 502 | __frame->gr8 = -EINTR; |
494 | break; | 503 | break; |
495 | } | 504 | } |
505 | |||
496 | /* fallthrough */ | 506 | /* fallthrough */ |
497 | case -ERESTARTNOINTR: | 507 | case -ERESTARTNOINTR: |
498 | regs->gr8 = regs->orig_gr8; | 508 | __frame->gr8 = __frame->orig_gr8; |
499 | regs->pc -= 4; | 509 | __frame->pc -= 4; |
500 | } | 510 | } |
501 | } | 511 | } |
502 | 512 | ||
503 | /* Set up the stack frame */ | 513 | /* Set up the stack frame */ |
504 | if (ka->sa.sa_flags & SA_SIGINFO) | 514 | if (ka->sa.sa_flags & SA_SIGINFO) |
505 | setup_rt_frame(sig, ka, info, oldset, regs); | 515 | ret = setup_rt_frame(sig, ka, info, oldset); |
506 | else | 516 | else |
507 | setup_frame(sig, ka, oldset, regs); | 517 | ret = setup_frame(sig, ka, oldset); |
518 | |||
519 | if (ret) { | ||
520 | spin_lock_irq(¤t->sighand->siglock); | ||
521 | sigorsets(¤t->blocked, ¤t->blocked, | ||
522 | &ka->sa.sa_mask); | ||
523 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
524 | sigaddset(¤t->blocked, sig); | ||
525 | recalc_sigpending(); | ||
526 | spin_unlock_irq(¤t->sighand->siglock); | ||
527 | } | ||
528 | |||
529 | return ret; | ||
508 | 530 | ||
509 | spin_lock_irq(¤t->sighand->siglock); | ||
510 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | ||
511 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
512 | sigaddset(¤t->blocked, sig); | ||
513 | recalc_sigpending(); | ||
514 | spin_unlock_irq(¤t->sighand->siglock); | ||
515 | } /* end handle_signal() */ | 531 | } /* end handle_signal() */ |
516 | 532 | ||
517 | /*****************************************************************************/ | 533 | /*****************************************************************************/ |
@@ -520,7 +536,7 @@ static void handle_signal(unsigned long sig, siginfo_t *info, | |||
520 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 536 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
521 | * mistake. | 537 | * mistake. |
522 | */ | 538 | */ |
523 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 539 | static int do_signal(sigset_t *oldset) |
524 | { | 540 | { |
525 | struct k_sigaction ka; | 541 | struct k_sigaction ka; |
526 | siginfo_t info; | 542 | siginfo_t info; |
@@ -532,7 +548,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
532 | * kernel mode. Just return without doing anything | 548 | * kernel mode. Just return without doing anything |
533 | * if so. | 549 | * if so. |
534 | */ | 550 | */ |
535 | if (!user_mode(regs)) | 551 | if (!user_mode(__frame)) |
536 | return 1; | 552 | return 1; |
537 | 553 | ||
538 | if (try_to_freeze()) | 554 | if (try_to_freeze()) |
@@ -541,30 +557,29 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
541 | if (!oldset) | 557 | if (!oldset) |
542 | oldset = ¤t->blocked; | 558 | oldset = ¤t->blocked; |
543 | 559 | ||
544 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 560 | signr = get_signal_to_deliver(&info, &ka, __frame, NULL); |
545 | if (signr > 0) { | 561 | if (signr > 0) |
546 | handle_signal(signr, &info, &ka, oldset, regs); | 562 | return handle_signal(signr, &info, &ka, oldset); |
547 | return 1; | ||
548 | } | ||
549 | 563 | ||
550 | no_signal: | 564 | no_signal: |
551 | /* Did we come from a system call? */ | 565 | /* Did we come from a system call? */ |
552 | if (regs->syscallno >= 0) { | 566 | if (__frame->syscallno >= 0) { |
553 | /* Restart the system call - no handlers present */ | 567 | /* Restart the system call - no handlers present */ |
554 | if (regs->gr8 == -ERESTARTNOHAND || | 568 | if (__frame->gr8 == -ERESTARTNOHAND || |
555 | regs->gr8 == -ERESTARTSYS || | 569 | __frame->gr8 == -ERESTARTSYS || |
556 | regs->gr8 == -ERESTARTNOINTR) { | 570 | __frame->gr8 == -ERESTARTNOINTR) { |
557 | regs->gr8 = regs->orig_gr8; | 571 | __frame->gr8 = __frame->orig_gr8; |
558 | regs->pc -= 4; | 572 | __frame->pc -= 4; |
559 | } | 573 | } |
560 | 574 | ||
561 | if (regs->gr8 == -ERESTART_RESTARTBLOCK){ | 575 | if (__frame->gr8 == -ERESTART_RESTARTBLOCK){ |
562 | regs->gr8 = __NR_restart_syscall; | 576 | __frame->gr8 = __NR_restart_syscall; |
563 | regs->pc -= 4; | 577 | __frame->pc -= 4; |
564 | } | 578 | } |
565 | } | 579 | } |
566 | 580 | ||
567 | return 0; | 581 | return 0; |
582 | |||
568 | } /* end do_signal() */ | 583 | } /* end do_signal() */ |
569 | 584 | ||
570 | /*****************************************************************************/ | 585 | /*****************************************************************************/ |
@@ -580,6 +595,6 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) | |||
580 | 595 | ||
581 | /* deal with pending signal delivery */ | 596 | /* deal with pending signal delivery */ |
582 | if (thread_info_flags & _TIF_SIGPENDING) | 597 | if (thread_info_flags & _TIF_SIGPENDING) |
583 | do_signal(__frame, NULL); | 598 | do_signal(NULL); |
584 | 599 | ||
585 | } /* end do_notify_resume() */ | 600 | } /* end do_notify_resume() */ |