root/arch/sparc/kernel/signal.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _sigpause_common
  2. do_sigpause
  3. do_sigsuspend
  4. do_sigreturn
  5. setup_frame
  6. do_signal
  7. sys_sigstack

   1 /*  $Id: signal.c,v 1.32 1996/04/22 19:37:48 davem Exp $
   2  *  linux/arch/sparc/kernel/signal.c
   3  *
   4  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   5  */
   6 
   7 #include <linux/sched.h>
   8 #include <linux/kernel.h>
   9 #include <linux/signal.h>
  10 #include <linux/errno.h>
  11 #include <linux/wait.h>
  12 #include <linux/ptrace.h>
  13 #include <linux/unistd.h>
  14 #include <linux/mm.h>
  15 
  16 #include <asm/segment.h>
  17 #include <asm/bitops.h>
  18 #include <asm/ptrace.h>
  19 
  20 #define _S(nr) (1<<((nr)-1))
  21 
  22 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  23 
  24 asmlinkage int sys_waitpid(pid_t pid, unsigned long *stat_addr, int options);
  25 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
  26 
  27 /*
  28  * atomically swap in the new signal mask, and wait for a signal.
  29  * This is really tricky on the Sparc, watch out...
  30  */
  31 asmlinkage inline void _sigpause_common(unsigned int set, struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33         unsigned long mask;
  34 
  35         mask = current->blocked;
  36         current->blocked = set & _BLOCKABLE;
  37 
  38         /* Advance over the syscall instruction for when
  39          * we return.  We want setup_frame to save the proper
  40          * state, including the error return number & condition
  41          * codes.
  42          */
  43         regs->pc = regs->npc;
  44         regs->npc += 4;
  45         regs->psr |= PSR_C;
  46         regs->u_regs[UREG_I0] = EINTR;
  47 
  48         while (1) {
  49                 current->state = TASK_INTERRUPTIBLE;
  50                 schedule();
  51                 if (do_signal(mask, regs))
  52                         return;
  53         }
  54 }
  55 
  56 asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58         _sigpause_common(set, regs);
  59 }
  60 
  61 asmlinkage void do_sigsuspend (struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63         unsigned long mask;
  64         unsigned long set;
  65 
  66         set = regs->u_regs [UREG_I0];
  67         mask = current->blocked;
  68         current->blocked = set & _BLOCKABLE;
  69         regs->pc = regs->npc;
  70         regs->npc += 4;
  71         while (1) {
  72                 current->state = TASK_INTERRUPTIBLE;
  73                 schedule();
  74                 if (do_signal(mask,regs)){
  75                         regs->psr |= PSR_C;
  76                         regs->u_regs [UREG_I0] = EINTR;
  77                         return;
  78                 }
  79         }
  80 }
  81 
  82 asmlinkage void do_sigreturn(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84         struct sigcontext_struct *scptr =
  85                 (struct sigcontext_struct *) regs->u_regs[UREG_I0];
  86 
  87         synchronize_user_stack();
  88 
  89         /* Check sanity of the user arg. */
  90         if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext_struct)) ||
  91            ((((unsigned long) scptr)) & 0x3)) {
  92                 printk("%s [%d]: do_sigreturn, scptr is invalid at pc<%08lx> scptr<%p>\n",
  93                        current->comm, current->pid, regs->pc, scptr);
  94                 do_exit(SIGSEGV);
  95         }
  96 
  97         if((scptr->sigc_pc | scptr->sigc_npc) & 3)
  98                 return; /* Nice try. */
  99 
 100         current->blocked = scptr->sigc_mask & _BLOCKABLE;
 101         current->tss.sstk_info.cur_status = (scptr->sigc_onstack & 1);
 102         regs->pc = scptr->sigc_pc;
 103         regs->npc = scptr->sigc_npc;
 104         regs->u_regs[UREG_FP] = scptr->sigc_sp;
 105         regs->u_regs[UREG_I0] = scptr->sigc_o0;
 106         regs->u_regs[UREG_G1] = scptr->sigc_g1;
 107 
 108         /* User can only change condition codes in %psr. */
 109         regs->psr &= (~PSR_ICC);
 110         regs->psr |= (scptr->sigc_psr & PSR_ICC);
 111 }
 112 
 113 /*
 114  * Set up a signal frame... Make the stack look the way SunOS
 115  * expects it to look which is basically:
 116  *
 117  * ---------------------------------- <-- %sp at signal time
 118  * Struct sigcontext
 119  * Signal address
 120  * Ptr to sigcontext area above
 121  * Signal code
 122  * The signal number itself
 123  * One register window
 124  * ---------------------------------- <-- New %sp
 125  */
 126 struct signal_sframe {
 127         struct reg_window sig_window;
 128         int sig_num;
 129         int sig_code;
 130         struct sigcontext_struct *sig_scptr;
 131         int sig_address;
 132         struct sigcontext_struct sig_context;
 133 };
 134 /* To align the structure properly. */
 135 #define SF_ALIGNEDSZ  (((sizeof(struct signal_sframe) + 7) & (~7)))
 136 
 137 static inline void
 138 setup_frame(struct sigaction *sa, struct sigcontext_struct **fp,
     /* [previous][next][first][last][top][bottom][index][help] */
 139             unsigned long pc, unsigned long npc, struct pt_regs *regs,
 140             int signr, unsigned long oldmask)
 141 {
 142         struct signal_sframe *sframep;
 143         struct sigcontext_struct *sc;
 144         int window = 0;
 145         int old_status = current->tss.sstk_info.cur_status;
 146 
 147         synchronize_user_stack();
 148         sframep = (struct signal_sframe *) *fp;
 149         sframep = (struct signal_sframe *) (((unsigned long) sframep)-SF_ALIGNEDSZ);
 150         sc = &sframep->sig_context;
 151         if(verify_area(VERIFY_WRITE, sframep, sizeof(*sframep)) ||
 152            (((unsigned long) sframep) & 7) ||
 153            (((unsigned long) sframep) >= KERNBASE) ||
 154            ((sparc_cpu_model == sun4 || sparc_cpu_model == sun4c) &&
 155             ((unsigned long) sframep < 0xe0000000 && (unsigned long) sframep >= 0x20000000))) {
 156 #if 0 /* fills up the console logs... */
 157                 printk("%s [%d]: User has trashed signal stack\n",
 158                        current->comm, current->pid);
 159                 printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n",
 160                        sframep, pc, signr);
 161 #endif
 162                 /* Don't change signal code and address, so that
 163                  * post mortem debuggers can have a look.
 164                  */
 165                 current->sig->action[SIGILL-1].sa_handler = SIG_DFL;
 166                 current->blocked &= ~(1<<(SIGILL-1));
 167                 send_sig(SIGILL,current,1);
 168                 return;
 169         }
 170         *fp = (struct sigcontext_struct *) sframep;
 171 
 172         sc->sigc_onstack = old_status;
 173         sc->sigc_mask = oldmask;
 174         sc->sigc_sp = regs->u_regs[UREG_FP];
 175         sc->sigc_pc = pc;
 176         sc->sigc_npc = npc;
 177         sc->sigc_psr = regs->psr;
 178         sc->sigc_g1 = regs->u_regs[UREG_G1];
 179         sc->sigc_o0 = regs->u_regs[UREG_I0];
 180         sc->sigc_oswins = current->tss.w_saved;
 181         if(current->tss.w_saved)
 182                 for(window = 0; window < current->tss.w_saved; window++) {
 183                         sc->sigc_spbuf[window] =
 184                                 (char *)current->tss.rwbuf_stkptrs[window];
 185                         memcpy(&sc->sigc_wbuf[window],
 186                                &current->tss.reg_window[window],
 187                                sizeof(struct reg_window));
 188                 }
 189         else
 190                 memcpy(sframep, (char *)regs->u_regs[UREG_FP],
 191                        sizeof(struct reg_window));
 192 
 193         current->tss.w_saved = 0; /* So process is allowed to execute. */
 194         sframep->sig_num = signr;
 195         if(signr == SIGSEGV ||
 196            signr == SIGILL ||
 197            signr == SIGFPE ||
 198            signr == SIGBUS ||
 199            signr == SIGEMT) {
 200                 sframep->sig_code = current->tss.sig_desc;
 201                 sframep->sig_address = current->tss.sig_address;
 202         } else {
 203                 sframep->sig_code = 0;
 204                 sframep->sig_address = 0;
 205         }
 206         sframep->sig_scptr = sc;
 207         regs->u_regs[UREG_FP] = (unsigned long) *fp;
 208 }
 209 
 210 /*
 211  * Note that 'init' is a special process: it doesn't get signals it doesn't
 212  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 213  * mistake.
 214  *
 215  * Note that we go through the signals twice: once to check the signals that
 216  * the kernel can handle, and then we build all the user-level signal handling
 217  * stack-frames in one go after that.
 218  */
 219 
 220 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222         unsigned long mask = ~current->blocked;
 223         unsigned long handler_signal = 0;
 224         struct sigcontext_struct *frame = NULL;
 225         unsigned long pc = 0;
 226         unsigned long npc = 0;
 227         unsigned long signr;
 228         struct sigaction *sa;
 229 
 230         while ((signr = current->signal & mask) != 0) {
 231                 signr = ffz(~signr);
 232                 clear_bit(signr, &current->signal);
 233                 sa = current->sig->action + signr;
 234                 signr++;
 235                 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 236                         current->exit_code = signr;
 237                         current->state = TASK_STOPPED;
 238                         notify_parent(current);
 239                         schedule();
 240                         if (!(signr = current->exit_code))
 241                                 continue;
 242                         current->exit_code = 0;
 243                         if (signr == SIGSTOP)
 244                                 continue;
 245                         if (_S(signr) & current->blocked) {
 246                                 current->signal |= _S(signr);
 247                                 continue;
 248                         }
 249                         sa = current->sig->action + signr - 1;
 250                 }
 251                 if(sa->sa_handler == SIG_IGN) {
 252                         if(signr != SIGCHLD)
 253                                 continue;
 254                         while(sys_waitpid(-1,NULL,WNOHANG) > 0);
 255                         continue;
 256                 }
 257                 if(sa->sa_handler == SIG_DFL) {
 258                         if(current->pid == 1)
 259                                 continue;
 260                         switch(signr) {
 261                         case SIGCONT: case SIGCHLD: case SIGWINCH:
 262                                 continue;
 263 
 264                         case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
 265                                 current->state = TASK_STOPPED;
 266                                 current->exit_code = signr;
 267                                 if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
 268                                      SA_NOCLDSTOP))
 269                                         notify_parent(current);
 270                                 schedule();
 271                                 continue;
 272 
 273                         case SIGQUIT: case SIGILL: case SIGTRAP:
 274                         case SIGABRT: case SIGFPE: case SIGSEGV:
 275                                 if(current->binfmt && current->binfmt->core_dump) {
 276                                         if(current->binfmt->core_dump(signr, regs))
 277                                                 signr |= 0x80;
 278                                 }
 279                                 /* fall through */
 280                         default:
 281                                 current->signal |= _S(signr & 0x7f);
 282                                 current->flags |= PF_SIGNALED;
 283                                 do_exit(signr);
 284                         }
 285                 }
 286                 /* OK, we're invoking a handler. */
 287                 if(regs->psr & PSR_C) {
 288                         if(regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
 289                            (regs->u_regs[UREG_I0] == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
 290                                 regs->u_regs[UREG_I0] = EINTR;
 291                 }
 292                 handler_signal |= 1 << (signr - 1);
 293                 mask &= ~sa->sa_mask;
 294         }
 295         if((regs->psr & PSR_C) &&
 296            (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
 297             regs->u_regs[UREG_I0] == ERESTARTSYS ||
 298             regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
 299                 /* replay the system call when we are done */
 300                 regs->u_regs[UREG_I0] = regs->u_regs[UREG_G0];
 301                 regs->pc -= 4;
 302                 regs->npc -= 4;
 303         }
 304         if(!handler_signal)
 305                 return 0;
 306         pc = regs->pc;
 307         npc = regs->npc;
 308         frame = (struct sigcontext_struct *) regs->u_regs[UREG_FP];
 309         signr = 1;
 310         sa = current->sig->action;
 311         for(mask = 1; mask; sa++, signr++, mask += mask) {
 312                 if(mask > handler_signal)
 313                         break;
 314                 if(!(mask & handler_signal))
 315                         continue;
 316                 setup_frame(sa, &frame, pc, npc, regs, signr, oldmask);
 317                 pc = (unsigned long) sa->sa_handler;
 318                 npc = pc + 4;
 319                 if(sa->sa_flags & SA_ONESHOT)
 320                         sa->sa_handler = NULL;
 321                 current->blocked |= sa->sa_mask;
 322                 oldmask |= sa->sa_mask;
 323         }
 324         regs->pc = pc;
 325         regs->npc = npc;
 326         return 1;
 327 }
 328 
 329 asmlinkage int
 330 sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332         /* First see if old state is wanted. */
 333         if(ossptr) {
 334                 if(verify_area(VERIFY_WRITE, ossptr, sizeof(struct sigstack)))
 335                         return -EFAULT;
 336                 memcpy(ossptr, &current->tss.sstk_info, sizeof(struct sigstack));
 337         }
 338 
 339         /* Now see if we want to update the new state. */
 340         if(ssptr) {
 341                 if(verify_area(VERIFY_READ, ssptr, sizeof(struct sigstack)))
 342                         return -EFAULT;
 343                 memcpy(&current->tss.sstk_info, ssptr, sizeof(struct sigstack));
 344         }
 345         return 0;
 346 }

/* [previous][next][first][last][top][bottom][index][help] */