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.31 1996/04/18 01:00:41 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(sa->sa_handler == SIG_IGN) {
 236                         if(signr != SIGCHLD)
 237                                 continue;
 238                         while(sys_waitpid(-1,NULL,WNOHANG) > 0);
 239                         continue;
 240                 }
 241                 if(sa->sa_handler == SIG_DFL) {
 242                         if(current->pid == 1)
 243                                 continue;
 244                         switch(signr) {
 245                         case SIGCONT: case SIGCHLD: case SIGWINCH:
 246                                 continue;
 247 
 248                         case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
 249                                 current->state = TASK_STOPPED;
 250                                 current->exit_code = signr;
 251                                 if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
 252                                      SA_NOCLDSTOP))
 253                                         notify_parent(current);
 254                                 schedule();
 255                                 continue;
 256 
 257                         case SIGQUIT: case SIGILL: case SIGTRAP:
 258                         case SIGABRT: case SIGFPE: case SIGSEGV:
 259                                 if(current->binfmt && current->binfmt->core_dump) {
 260                                         if(current->binfmt->core_dump(signr, regs))
 261                                                 signr |= 0x80;
 262                                 }
 263                                 /* fall through */
 264                         default:
 265                                 current->signal |= _S(signr & 0x7f);
 266                                 current->flags |= PF_SIGNALED;
 267                                 do_exit(signr);
 268                         }
 269                 }
 270                 /* OK, we're invoking a handler. */
 271                 if(regs->psr & PSR_C) {
 272                         if(regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
 273                            (regs->u_regs[UREG_I0] == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
 274                                 regs->u_regs[UREG_I0] = EINTR;
 275                 }
 276                 handler_signal |= 1 << (signr - 1);
 277                 mask &= ~sa->sa_mask;
 278         }
 279         if((regs->psr & PSR_C) &&
 280            (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
 281             regs->u_regs[UREG_I0] == ERESTARTSYS ||
 282             regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
 283                 /* replay the system call when we are done */
 284                 regs->u_regs[UREG_I0] = regs->u_regs[UREG_G0];
 285                 regs->pc -= 4;
 286                 regs->npc -= 4;
 287         }
 288         if(!handler_signal)
 289                 return 0;
 290         pc = regs->pc;
 291         npc = regs->npc;
 292         frame = (struct sigcontext_struct *) regs->u_regs[UREG_FP];
 293         signr = 1;
 294         sa = current->sig->action;
 295         for(mask = 1; mask; sa++, signr++, mask += mask) {
 296                 if(mask > handler_signal)
 297                         break;
 298                 if(!(mask & handler_signal))
 299                         continue;
 300                 setup_frame(sa, &frame, pc, npc, regs, signr, oldmask);
 301                 pc = (unsigned long) sa->sa_handler;
 302                 npc = pc + 4;
 303                 if(sa->sa_flags & SA_ONESHOT)
 304                         sa->sa_handler = NULL;
 305                 current->blocked |= sa->sa_mask;
 306                 oldmask |= sa->sa_mask;
 307         }
 308         regs->pc = pc;
 309         regs->npc = npc;
 310         return 1;
 311 }
 312 
 313 asmlinkage int
 314 sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316         /* First see if old state is wanted. */
 317         if(ossptr) {
 318                 if(verify_area(VERIFY_WRITE, ossptr, sizeof(struct sigstack)))
 319                         return -EFAULT;
 320                 memcpy(ossptr, &current->tss.sstk_info, sizeof(struct sigstack));
 321         }
 322 
 323         /* Now see if we want to update the new state. */
 324         if(ssptr) {
 325                 if(verify_area(VERIFY_READ, ssptr, sizeof(struct sigstack)))
 326                         return -EFAULT;
 327                 memcpy(&current->tss.sstk_info, ssptr, sizeof(struct sigstack));
 328         }
 329         return 0;
 330 }

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