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

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