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. sys_sigpause
  3. sys_sigsuspend
  4. do_sigreturn
  5. do_magic_sparc_stuff
  6. setup_frame
  7. do_signal
  8. sys_sigstack

   1 /*  $Id: signal.c,v 1.20 1995/11/26 02:29:09 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 int _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         /* Advance over the syscall instruction for when
  38          * we return.  We want setup_frame to save the proper
  39          * state, but then below we set ourselves backwards
  40          * to compensate for what ret_sys_call does. Ick!
  41          */
  42         regs->pc += 4;
  43         regs->npc += 4;
  44 
  45         while (1) {
  46                 current->state = TASK_INTERRUPTIBLE;
  47                 schedule();
  48                 if (do_signal(mask, regs)) {
  49                         /* If we actually post the signal then we
  50                          * will get our PCs advanced in entry.S, to
  51                          * compensate we throw the PCs back one insn.
  52                          */
  53                         regs->pc -= 4;
  54                         regs->npc -= 4;
  55                         return -EINTR;
  56                 }
  57         }
  58 }
  59 
  60 asmlinkage int sys_sigpause(unsigned int set)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         struct pt_regs *regs;
  63         unsigned long fp;
  64 
  65         __asm__ __volatile__("mov %%fp, %0\n\t" :
  66                              "=r" (fp));
  67         regs = ((struct pt_regs *) (fp + STACKFRAME_SZ));
  68         return _sigpause_common(set, regs);
  69 }
  70 
  71 asmlinkage int sys_sigsuspend(unsigned int *sigmaskp)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73         struct pt_regs *regs;
  74         unsigned long fp;
  75         unsigned int set;
  76 
  77         __asm__ __volatile__("mov %%fp, %0\n\t" :
  78                              "=r" (fp));
  79         regs = ((struct pt_regs *) (fp + STACKFRAME_SZ));
  80         if(verify_area(VERIFY_READ, sigmaskp, sizeof(unsigned int)))
  81                 return -EFAULT;
  82         set = *sigmaskp;
  83         return _sigpause_common(set, regs);
  84 }
  85 
  86 extern unsigned long nwindows;
  87 
  88 asmlinkage void do_sigreturn(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90         struct sigcontext_struct *scptr =
  91                 (struct sigcontext_struct *) regs->u_regs[UREG_I0];
  92 
  93         /* Make the stack consistant. */
  94         flush_user_windows();
  95 
  96         /* Check sanity of the user arg. */
  97         if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext_struct)) ||
  98            ((((unsigned long) scptr)) & 0x3))
  99                 do_exit(SIGSEGV);
 100 
 101         if((scptr->sigc_pc | scptr->sigc_npc) & 3)
 102                 return; /* Nice try. */
 103 
 104         current->blocked = scptr->sigc_mask & _BLOCKABLE;
 105         current->tss.sstk_info.cur_status = (scptr->sigc_onstack & 0x1);
 106         regs->pc = scptr->sigc_pc;
 107         regs->npc = scptr->sigc_npc;
 108         regs->u_regs[UREG_FP] = scptr->sigc_sp;
 109         regs->u_regs[UREG_I0] = scptr->sigc_o0;
 110         regs->u_regs[UREG_G1] = scptr->sigc_g1;
 111 
 112         /* User can only change condition codes in %psr. */
 113         regs->psr &= (~PSR_ICC);
 114         regs->psr |= (scptr->sigc_psr & PSR_ICC);
 115 }
 116 
 117 /* I love register windows...
 118  * Basically, this tries to get as many of the current user
 119  * windows on the stack as possible, even if unaligned.  Failing
 120  * that the windows end up in the per-task window save buffer
 121  * in the thread struct, these will be copied onto the signal
 122  * stack for possible inspection by the process.
 123  */
 124 static inline void
 125 do_magic_sparc_stuff(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127         unsigned long sp;
 128         int this_win;
 129 
 130         flush_user_windows();
 131         this_win = (current->tss.w_saved - 1);
 132         while(this_win >= 0) {
 133                 sp = current->tss.rwbuf_stkptrs[this_win];
 134                 if(!(sp & 7) && !verify_area(VERIFY_WRITE, (char *)sp,
 135                                              sizeof(struct reg_window))) {
 136                         memcpy((char *)sp,
 137                                (char *)&current->tss.reg_window[this_win],
 138                                sizeof(struct reg_window));
 139                         current->tss.w_saved--;
 140                         memcpy((char *)&current->tss.reg_window[this_win],
 141                                (char *)&current->tss.reg_window[this_win+1],
 142                                (sizeof(struct reg_window) *
 143                                (current->tss.w_saved-this_win)));
 144                 }
 145                 this_win -= 1;
 146         }
 147 }
 148 
 149 /*
 150  * Set up a signal frame... Make the stack look the way SunOS
 151  * expects it to look which is basically:
 152  *
 153  * ---------------------------------- <-- %sp at signal time
 154  * Struct sigcontext
 155  * Signal address
 156  * Ptr to sigcontext area above
 157  * Signal code
 158  * The signal number itself
 159  * One register window
 160  * ---------------------------------- <-- New %sp
 161  */
 162 struct signal_sframe {
 163         struct reg_window sig_window;
 164         int sig_num;
 165         int sig_code;
 166         struct sigcontext_struct *sig_scptr;
 167         int sig_address;
 168         struct sigcontext_struct sig_context;
 169 };
 170 /* To align the structure properly. */
 171 #define SF_ALIGNEDSZ  (((sizeof(struct signal_sframe) + 7) & (~7)))
 172 
 173 static inline void
 174 setup_frame(struct sigaction *sa, struct sigcontext_struct **fp,
     /* [previous][next][first][last][top][bottom][index][help] */
 175             unsigned long pc, struct pt_regs *regs, int signr,
 176             unsigned long oldmask)
 177 {
 178         struct signal_sframe *sframep;
 179         struct sigcontext_struct *sc;
 180         int window = 0;
 181         int old_status = current->tss.sstk_info.cur_status;
 182 
 183         sframep = (struct signal_sframe *) *fp;
 184         sframep = (struct signal_sframe *) (((unsigned long) sframep)-SF_ALIGNEDSZ);
 185         sc = &sframep->sig_context;
 186         if(verify_area(VERIFY_WRITE, sframep, sizeof(*sframep)) ||
 187            (((unsigned long) sframep) & 7) ||
 188            (((unsigned long) sframep) >= KERNBASE)) {
 189                 printk("%s [%d]: User has trashed signal stack\n",
 190                        current->comm, current->pid);
 191                 printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n",
 192                        sframep, pc, signr);
 193                 show_regs(regs);
 194                 /* Don't change signal code and address, so that
 195                  * post mortem debuggers can have a look.
 196                  */
 197                 current->sig->action[SIGILL-1].sa_handler = SIG_DFL;
 198                 current->blocked &= ~(1<<(SIGILL-1));
 199                 send_sig(SIGILL,current,1);
 200                 return;
 201         }
 202         *fp = (struct sigcontext_struct *) sframep;
 203         do_magic_sparc_stuff();
 204 
 205         sc->sigc_onstack = old_status;
 206         sc->sigc_mask = oldmask;
 207         sc->sigc_sp = regs->u_regs[UREG_FP];
 208         sc->sigc_pc = regs->pc;
 209         sc->sigc_npc = regs->npc;
 210         sc->sigc_psr = regs->psr;
 211         sc->sigc_g1 = regs->u_regs[UREG_G1];
 212         sc->sigc_o0 = regs->u_regs[UREG_I0];
 213         sc->sigc_oswins = current->tss.w_saved;
 214         if(current->tss.w_saved)
 215                 for(window = 0; window < current->tss.w_saved; window++) {
 216                         sc->sigc_spbuf[window] =
 217                                 (char *)current->tss.rwbuf_stkptrs[window];
 218                         memcpy(&sc->sigc_wbuf[window],
 219                                &current->tss.reg_window[window],
 220                                sizeof(struct reg_window));
 221                 }
 222         else
 223                 /* This is so that gdb and friends can trace back
 224                  * through the stack properly.  An alternative
 225                  * is to set the fp in this new window to the
 226                  * sp of the frame at the time of the signal and
 227                  * I see some problems with that maneuver.
 228                  */
 229                 memcpy(sframep, (char *)regs->u_regs[UREG_FP],
 230                        sizeof(struct reg_window));
 231 
 232         current->tss.w_saved = 0; /* So process is allowed to execute. */
 233         sframep->sig_num = signr;
 234         if(signr == SIGSEGV ||
 235            signr == SIGILL ||
 236            signr == SIGFPE ||
 237            signr == SIGBUS ||
 238            signr == SIGEMT) {
 239                 sframep->sig_code = current->tss.sig_desc;
 240                 sframep->sig_address = current->tss.sig_address;
 241         } else {
 242                 sframep->sig_code = 0;
 243                 sframep->sig_address = 0;
 244         }
 245         sframep->sig_scptr = sc;
 246 }
 247 
 248 /*
 249  * Note that 'init' is a special process: it doesn't get signals it doesn't
 250  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 251  * mistake.
 252  *
 253  * Note that we go through the signals twice: once to check the signals that
 254  * the kernel can handle, and then we build all the user-level signal handling
 255  * stack-frames in one go after that.
 256  */
 257 
 258 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 259 {
 260         unsigned long mask = ~current->blocked;
 261         unsigned long handler_signal = 0;
 262         struct sigcontext_struct *frame = NULL;
 263         unsigned long pc = 0;
 264         unsigned long signr;
 265         struct sigaction *sa;
 266 
 267         while ((signr = current->signal & mask) != 0) {
 268                 signr = ffz(~signr);
 269                 clear_bit(signr, &current->signal);
 270                 sa = current->sig->action + signr;
 271                 signr++;
 272                 if((current->flags & PF_PTRACED) && signr != SIGKILL) {
 273                         current->exit_code = signr;
 274                         current->state = TASK_STOPPED;
 275                         notify_parent(current);
 276                         schedule();
 277                         if(!(signr = current->exit_code))
 278                                 continue;
 279                         current->exit_code = 0;
 280                         if(signr == SIGSTOP)
 281                                 continue;
 282                         if(_S(signr) & current->blocked) {
 283                                 current->signal |= _S(signr);
 284                                 continue;
 285                         }
 286                         sa = current->sig->action + signr - 1;
 287                 }
 288                 if(sa->sa_handler == SIG_IGN) {
 289                         if(signr != SIGCHLD)
 290                                 continue;
 291                         while(sys_waitpid(-1,NULL,WNOHANG) > 0);
 292                         continue;
 293                 }
 294                 if(sa->sa_handler == SIG_DFL) {
 295                         if(current->pid == 1)
 296                                 continue;
 297                         switch(signr) {
 298                         case SIGCONT: case SIGCHLD: case SIGWINCH:
 299                                 continue;
 300 
 301                         case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
 302                                 if(current->flags & PF_PTRACED)
 303                                         continue;
 304                                 current->state = TASK_STOPPED;
 305                                 current->exit_code = signr;
 306                                 if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
 307                                      SA_NOCLDSTOP))
 308                                         notify_parent(current);
 309                                 schedule();
 310                                 continue;
 311 
 312                         case SIGQUIT: case SIGILL: case SIGTRAP:
 313                         case SIGABRT: case SIGFPE: case SIGSEGV:
 314                                 if(current->binfmt && current->binfmt->core_dump) {
 315                                         if(current->binfmt->core_dump(signr, regs))
 316                                                 signr |= 0x80;
 317                                 }
 318                                 /* fall through */
 319                         default:
 320                                 current->signal |= _S(signr & 0x7f);
 321                                 do_exit(signr);
 322                         }
 323                 }
 324                 /* OK, we're invoking a handler. */
 325                 handler_signal |= 1 << (signr - 1);
 326                 mask &= ~sa->sa_mask;
 327         }
 328         if(!handler_signal)
 329                 return 0;
 330         pc = regs->pc;
 331         frame = (struct sigcontext_struct *) regs->u_regs[UREG_FP];
 332         signr = 1;
 333         sa = current->sig->action;
 334         for(mask = 1; mask; sa++, signr++, mask += mask) {
 335                 if(mask > handler_signal)
 336                         break;
 337                 if(!(mask & handler_signal))
 338                         continue;
 339                 setup_frame(sa, &frame, pc, regs, signr, oldmask);
 340                 pc = (unsigned long) sa->sa_handler;
 341                 if(sa->sa_flags & SA_ONESHOT)
 342                         sa->sa_handler = NULL;
 343                 current->blocked |= sa->sa_mask;
 344                 oldmask |= sa->sa_mask;
 345         }
 346         regs->u_regs[UREG_FP] = (unsigned long) frame;
 347         regs->npc = (regs->pc = pc) + 4;
 348         return 1;
 349 }
 350 
 351 asmlinkage int
 352 sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354         /* First see if old state is wanted. */
 355         if(ossptr) {
 356                 if(verify_area(VERIFY_WRITE, ossptr, sizeof(struct sigstack)))
 357                         return -EFAULT;
 358                 memcpy(ossptr, &current->tss.sstk_info, sizeof(struct sigstack));
 359         }
 360 
 361         /* Now see if we want to update the new state. */
 362         if(ssptr) {
 363                 if(verify_area(VERIFY_READ, ssptr, sizeof(struct sigstack)))
 364                         return -EFAULT;
 365                 memcpy(&current->tss.sstk_info, ssptr, sizeof(struct sigstack));
 366         }
 367         return 0;
 368 }

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