/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * arch/sh64/kernel/signal.c * * Copyright (C) 2000, 2001 Paolo Alberelli * * Started from sh version. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define REG_RET 9 #define REG_ARG1 2 #define REG_ARG2 3 #define REG_SP 15 #define REG_PR 18 #define REF_REG_RET regs->regs[REG_RET] #define REF_REG_SP regs->regs[REG_SP] #define DEREF_REG_PR regs->regs[REG_PR] #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) { if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) return -EFAULT; if (from->si_code < 0) return __copy_to_user(to, from, sizeof(siginfo_t)); else { int err; /* If you change siginfo_t structure, please be sure this code is fixed accordingly. It should never copy any pad contained in the structure to avoid security leaks, but must copy the generic 3 ints plus the relevant union member. */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user((short)from->si_code, &to->si_code); /* First 32bits of unions are always present. */ err |= __put_user(from->si_pid, &to->si_pid); switch (from->si_code >> 16) { case __SI_FAULT >> 16: break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); default: err |= __put_user(from->si_uid, &to->si_uid); break; /* case __SI_RT: This is not generated by the kernel as of now. */ } return err; } } /* * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs * regs) { sigset_t saveset; mask &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); REF_REG_RET = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); regs->pc += 4; /* because sys_sigreturn decrements the pc */ if (do_signal (regs, &saveset)) { /* pc now points at signal handler. Need to decrement it because entry.S will increment it. */ regs->pc -= 4; return -EINTR; } } } asmlinkage int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs * regs) { sigset_t saveset, newset; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); REF_REG_RET = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); regs->pc += 4; /* because sys_sigreturn decrements the pc */ if (do_signal (regs, &saveset)) { /* pc now points at signal handler. Need to decrement it because entry.S will increment it. */ regs->pc -= 4; return -EINTR; } } } asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact) { struct k_sigaction new_ka, old_ka; int ret; if (act) { old_sigset_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) return -EFAULT; __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) return -EFAULT; __put_user(old_ka.sa.sa_flags, &oact->sa_flags); __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; } asmlinkage int sys_sigaltstack(const stack_t *uss, stack_t *uoss, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs * regs) { return do_sigaltstack(uss, uoss, REF_REG_SP); } /* * Do a signal return; undo the signal stack. */ struct sigframe { struct sigcontext sc; unsigned long extramask[_NSIG_WORDS-1]; long long retcode[2]; }; struct rt_sigframe { struct siginfo *pinfo; void *puc; struct siginfo info; struct ucontext uc; long long retcode[2]; }; #ifndef CONFIG_NOFPU_SUPPORT static inline int restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext *sc) { int err = 0; int fpvalid; err |= __get_user (fpvalid, &sc->sc_fpvalid); current->used_math = fpvalid; if (! fpvalid) return err; if (current == last_task_used_math) { last_task_used_math = NULL; regs->sr |= SR_FD; } err |= __copy_from_user(¤t->thread.fpu.hard, &sc->sc_fpregs[0], (sizeof(long long) * 32) + (sizeof(int) * 1)); return err; } static inline int setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext *sc) { int err = 0; int fpvalid; fpvalid = current->used_math; err |= __put_user(fpvalid, &sc->sc_fpvalid); if (! fpvalid) return err; if (current == last_task_used_math) { grab_fpu(); fpsave(¤t->thread.fpu.hard); release_fpu(); last_task_used_math = NULL; regs->sr |= SR_FD; } err |= __copy_to_user(&sc->sc_fpregs[0], ¤t->thread.fpu.hard, (sizeof(long long) * 32) + (sizeof(int) * 1)); current->used_math = 0; return err; } #else static inline int restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext *sc) {} static inline int setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext *sc) {} #endif static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, long long *r2_p) { unsigned int err = 0; #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]); COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]); COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]); COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]); COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]); COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]); COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]); COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]); COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]); COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]); COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]); COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]); COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]); COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]); COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]); COPY(regs[60]); COPY(regs[61]); COPY(regs[62]); COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); COPY(sr); COPY(pc); #undef COPY /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr * has been restored above.) */ err |= restore_sigcontext_fpu(regs, sc); regs->syscall_nr = -1; /* disable syscall checks */ err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]); return err; } asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs * regs) { struct sigframe *frame = (struct sigframe *) (long) REF_REG_SP; sigset_t set; long long ret; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask)))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(regs, &frame->sc, &ret)) goto badframe; regs->pc -= 4; return (int) ret; badframe: force_sig(SIGSEGV, current); return 0; } asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs * regs) { struct rt_sigframe *frame = (struct rt_sigframe *) (long) REF_REG_SP; sigset_t set; stack_t st; long long ret; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret)) goto badframe; regs->pc -= 4; if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ do_sigaltstack(&st, NULL, REF_REG_SP); return (int) ret; badframe: force_sig(SIGSEGV, current); return 0; } /* * Set up a signal frame. */ static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask) { int err = 0; /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */ err |= setup_sigcontext_fpu(regs, sc); #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]); COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]); COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]); COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]); COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]); COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]); COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]); COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]); COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]); COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]); COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]); COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]); COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]); COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]); COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]); COPY(regs[60]); COPY(regs[61]); COPY(regs[62]); COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); COPY(sr); COPY(pc); #undef COPY err |= __put_user(mask, &sc->oldmask); return err; } /* * Determine which stack to use.. */ static inline void * get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) { if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) sp = current->sas_ss_sp + current->sas_ss_size; return (void *)((sp - frame_size) & -8ul); } void sa_default_restorer(void); /* See comments below */ void sa_default_rt_restorer(void); /* See comments below */ static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { struct sigframe *frame; int err = 0; int signal; frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; signal = current->exec_domain && current->exec_domain->signal_invmap && sig < 32 ? current->exec_domain->signal_invmap[sig] : sig; err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); /* Give up earlier as i386, in case */ if (err) goto give_sigsegv; if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } /* Give up earlier as i386, in case */ if (err) goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER) { DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; /* * On SH5 all edited pointers are subject to NEFF */ DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; } else { /* * Different approach on SH5. * . Endianness independent asm code gets placed in entry.S . * This is limited to four ASM instructions corresponding * to two long longs in size. * . err checking is done on the else branch only * . flush_icache_range() is called upon __put_user() only * . all edited pointers are subject to NEFF * . being code, linker turns ShMedia bit on, always * dereference index -1. */ DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; if (__copy_to_user(frame->retcode, (unsigned long long)sa_default_restorer & (~1), 16) != 0) goto give_sigsegv; /* Cohere the trampoline with the I-cache. */ flush_cache_sigtramp(DEREF_REG_PR-1, DEREF_REG_PR-1+16); } /* * Set up registers for signal handler. * All edited pointers are subject to NEFF. */ regs->regs[REG_SP] = (unsigned long) frame; regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc; regs->pc = (unsigned long) ka->sa.sa_handler; regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; set_fs(USER_DS); #if DEBUG_SIG /* Broken %016Lx */ printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", signal, current->comm, current->pid, frame, regs->pc >> 32, regs->pc & 0xffffffff, DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); #endif return; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe *frame; int err = 0; int signal; frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; signal = current->exec_domain && current->exec_domain->signal_invmap && sig < 32 ? current->exec_domain->signal_invmap[sig] : sig; err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); /* Give up earlier as i386, in case */ if (err) goto give_sigsegv; /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->regs[REG_SP]), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Give up earlier as i386, in case */ if (err) goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER) { DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; /* * On SH5 all edited pointers are subject to NEFF */ DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; } else { /* * Different approach on SH5. * . Endianness independent asm code gets placed in entry.S . * This is limited to four ASM instructions corresponding * to two long longs in size. * . err checking is done on the else branch only * . flush_icache_range() is called upon __put_user() only * . all edited pointers are subject to NEFF * . being code, linker turns ShMedia bit on, always * dereference index -1. */ DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; if (__copy_to_user(frame->retcode, (unsigned long long)sa_default_rt_restorer & (~1), 16) != 0) goto give_sigsegv; flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15); } /* * Set up registers for signal handler. * All edited pointers are subject to NEFF. */ regs->regs[REG_SP] = (unsigned long) frame; regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext; regs->pc = (unsigned long) ka->sa.sa_handler; regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; set_fs(USER_DS); #if DEBUG_SIG /* Broken %016Lx */ printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", signal, current->comm, current->pid, frame, regs->pc >> 32, regs->pc & 0xffffffff, DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); #endif return; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); } /* * OK, we're invoking a handler */ static void handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { /* Are we from a system call? */ if (regs->syscall_nr >= 0) { /* If so, check system call restarting.. */ switch (regs->regs[REG_RET]) { case -ERESTARTNOHAND: regs->regs[REG_RET] = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { regs->regs[REG_RET] = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: /* Decode syscall # */ regs->regs[REG_RET] = regs->syscall_nr; regs->pc -= 4; } } /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame(sig, ka, info, oldset, regs); else setup_frame(sig, ka, oldset, regs); if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sigmask_lock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); } } /* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. * * Note that we go through the signals twice: once to check the signals that * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ int do_signal(struct pt_regs *regs, sigset_t *oldset) { siginfo_t info; struct k_sigaction *ka; /* * We want the common case to go fast, which * is why we may in certain cases get here from * kernel mode. Just return without doing anything * if so. */ if (!user_mode(regs)) return 1; if (!oldset) oldset = ¤t->blocked; for (;;) { unsigned long signr; spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) continue; current->exit_code = 0; /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) continue; /* Update the siginfo structure. Is this good? */ if (signr != info.si_signo) { info.si_signo = signr; info.si_errno = 0; info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, &info, current); continue; } } ka = ¤t->sig->action[signr-1]; if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; /* Check for SIGCHLD: it's special. */ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; /* Init gets no signals it doesn't want. */ if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; /* FALLTHRU */ case SIGSTOP: current->state = TASK_STOPPED; current->exit_code = signr; if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ default: sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); return 1; } /* Did we come from a system call? */ if (regs->syscall_nr >= 0) { /* Restart the system call - no handlers present */ if (regs->regs[REG_RET] == -ERESTARTNOHAND || regs->regs[REG_RET] == -ERESTARTSYS || regs->regs[REG_RET] == -ERESTARTNOINTR) { /* Decode Syscall # */ regs->regs[REG_RET] = regs->syscall_nr; regs->pc -= 4; } } return 0; }