diff options
Diffstat (limited to 'arch/sh/kernel/signal_32.c')
-rw-r--r-- | arch/sh/kernel/signal_32.c | 69 |
1 files changed, 41 insertions, 28 deletions
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 51689d29ad45..69d09c0b3498 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
31 | #include <asm/pgtable.h> | 31 | #include <asm/pgtable.h> |
32 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
33 | #include <asm/syscalls.h> | ||
33 | #include <asm/fpu.h> | 34 | #include <asm/fpu.h> |
34 | 35 | ||
35 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 36 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
@@ -215,6 +216,9 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, | |||
215 | sigset_t set; | 216 | sigset_t set; |
216 | int r0; | 217 | int r0; |
217 | 218 | ||
219 | /* Always make any pending restarted system calls return -EINTR */ | ||
220 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
221 | |||
218 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 222 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
219 | goto badframe; | 223 | goto badframe; |
220 | 224 | ||
@@ -247,9 +251,11 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, | |||
247 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | 251 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
248 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15]; | 252 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->regs[15]; |
249 | sigset_t set; | 253 | sigset_t set; |
250 | stack_t st; | ||
251 | int r0; | 254 | int r0; |
252 | 255 | ||
256 | /* Always make any pending restarted system calls return -EINTR */ | ||
257 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
258 | |||
253 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 259 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
254 | goto badframe; | 260 | goto badframe; |
255 | 261 | ||
@@ -265,11 +271,9 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, | |||
265 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) | 271 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) |
266 | goto badframe; | 272 | goto badframe; |
267 | 273 | ||
268 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) | 274 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, |
275 | regs->regs[15]) == -EFAULT) | ||
269 | goto badframe; | 276 | goto badframe; |
270 | /* It is more difficult to avoid calling this function than to | ||
271 | call it and ignore errors. */ | ||
272 | do_sigaltstack((const stack_t __user *)&st, NULL, (unsigned long)frame); | ||
273 | 277 | ||
274 | return r0; | 278 | return r0; |
275 | 279 | ||
@@ -429,7 +433,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
429 | 433 | ||
430 | /* Create the ucontext. */ | 434 | /* Create the ucontext. */ |
431 | err |= __put_user(0, &frame->uc.uc_flags); | 435 | err |= __put_user(0, &frame->uc.uc_flags); |
432 | err |= __put_user(0, &frame->uc.uc_link); | 436 | err |= __put_user(NULL, &frame->uc.uc_link); |
433 | err |= __put_user((void *)current->sas_ss_sp, | 437 | err |= __put_user((void *)current->sas_ss_sp, |
434 | &frame->uc.uc_stack.ss_sp); | 438 | &frame->uc.uc_stack.ss_sp); |
435 | err |= __put_user(sas_ss_flags(regs->regs[15]), | 439 | err |= __put_user(sas_ss_flags(regs->regs[15]), |
@@ -492,37 +496,43 @@ give_sigsegv: | |||
492 | return -EFAULT; | 496 | return -EFAULT; |
493 | } | 497 | } |
494 | 498 | ||
499 | static inline void | ||
500 | handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs, | ||
501 | struct sigaction *sa) | ||
502 | { | ||
503 | /* If we're not from a syscall, bail out */ | ||
504 | if (regs->tra < 0) | ||
505 | return; | ||
506 | |||
507 | /* check for system call restart.. */ | ||
508 | switch (regs->regs[0]) { | ||
509 | case -ERESTART_RESTARTBLOCK: | ||
510 | case -ERESTARTNOHAND: | ||
511 | no_system_call_restart: | ||
512 | regs->regs[0] = -EINTR; | ||
513 | regs->sr |= 1; | ||
514 | break; | ||
515 | |||
516 | case -ERESTARTSYS: | ||
517 | if (!(sa->sa_flags & SA_RESTART)) | ||
518 | goto no_system_call_restart; | ||
519 | /* fallthrough */ | ||
520 | case -ERESTARTNOINTR: | ||
521 | regs->regs[0] = save_r0; | ||
522 | regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); | ||
523 | break; | ||
524 | } | ||
525 | } | ||
526 | |||
495 | /* | 527 | /* |
496 | * OK, we're invoking a handler | 528 | * OK, we're invoking a handler |
497 | */ | 529 | */ |
498 | |||
499 | static int | 530 | static int |
500 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | 531 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, |
501 | sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0) | 532 | sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0) |
502 | { | 533 | { |
503 | int ret; | 534 | int ret; |
504 | 535 | ||
505 | /* Are we from a system call? */ | ||
506 | if (regs->tra >= 0) { | ||
507 | /* If so, check system call restarting.. */ | ||
508 | switch (regs->regs[0]) { | ||
509 | case -ERESTART_RESTARTBLOCK: | ||
510 | case -ERESTARTNOHAND: | ||
511 | no_system_call_restart: | ||
512 | regs->regs[0] = -EINTR; | ||
513 | break; | ||
514 | |||
515 | case -ERESTARTSYS: | ||
516 | if (!(ka->sa.sa_flags & SA_RESTART)) | ||
517 | goto no_system_call_restart; | ||
518 | /* fallthrough */ | ||
519 | case -ERESTARTNOINTR: | ||
520 | regs->regs[0] = save_r0; | ||
521 | regs->pc -= instruction_size( | ||
522 | ctrl_inw(regs->pc - 4)); | ||
523 | break; | ||
524 | } | ||
525 | } | ||
526 | 536 | ||
527 | /* Set up the stack frame */ | 537 | /* Set up the stack frame */ |
528 | if (ka->sa.sa_flags & SA_SIGINFO) | 538 | if (ka->sa.sa_flags & SA_SIGINFO) |
@@ -580,6 +590,9 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) | |||
580 | 590 | ||
581 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 591 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
582 | if (signr > 0) { | 592 | if (signr > 0) { |
593 | if (regs->sr & 1) | ||
594 | handle_syscall_restart(save_r0, regs, &ka.sa); | ||
595 | |||
583 | /* Whee! Actually deliver the signal. */ | 596 | /* Whee! Actually deliver the signal. */ |
584 | if (handle_signal(signr, &ka, &info, oldset, | 597 | if (handle_signal(signr, &ka, &info, oldset, |
585 | regs, save_r0) == 0) { | 598 | regs, save_r0) == 0) { |