root/arch/m68k/kernel/signal.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_sigsuspend
  2. do_sigreturn
  3. setup_frame
  4. do_signal

   1 /*
   2  *  linux/arch/m68k/kernel/signal.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  *
   6  * This file is subject to the terms and conditions of the GNU General Public
   7  * License.  See the file README.legal in the main directory of this archive
   8  * for more details.
   9  */
  10 
  11 /*
  12  * 680x0 support by Hamish Macdonald
  13  */
  14 
  15 #include <linux/sched.h>
  16 #include <linux/mm.h>
  17 #include <linux/kernel.h>
  18 #include <linux/signal.h>
  19 #include <linux/errno.h>
  20 #include <linux/wait.h>
  21 #include <linux/ptrace.h>
  22 #include <linux/unistd.h>
  23 
  24 #include <asm/segment.h>
  25 #include <asm/pgtable.h>
  26 #include <asm/traps.h>
  27 #include <asm/bootinfo.h>
  28 
  29 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
  30 
  31 #define _S(nr) (1<<((nr)-1))
  32 
  33 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  34 
  35 asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
  36 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
  37 
  38 static const int extra_sizes[16] = {
  39   0,
  40   -1, /* sizeof(((struct frame *)0)->un.fmt1), */
  41   sizeof(((struct frame *)0)->un.fmt2),
  42   sizeof(((struct frame *)0)->un.fmt3),
  43   sizeof(((struct frame *)0)->un.fmt4),
  44   -1, /* sizeof(((struct frame *)0)->un.fmt5), */
  45   -1, /* sizeof(((struct frame *)0)->un.fmt6), */
  46   sizeof(((struct frame *)0)->un.fmt7),
  47   -1, /* sizeof(((struct frame *)0)->un.fmt8), */
  48   sizeof(((struct frame *)0)->un.fmt9),
  49   sizeof(((struct frame *)0)->un.fmta),
  50   sizeof(((struct frame *)0)->un.fmtb),
  51   -1, /* sizeof(((struct frame *)0)->un.fmtc), */
  52   -1, /* sizeof(((struct frame *)0)->un.fmtd), */
  53   -1, /* sizeof(((struct frame *)0)->un.fmte), */
  54   -1, /* sizeof(((struct frame *)0)->un.fmtf), */
  55 };
  56 
  57 /*
  58  * atomically swap in the new signal mask, and wait for a signal.
  59  */
  60 asmlinkage int do_sigsuspend(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         unsigned long oldmask = current->blocked;
  63         unsigned long newmask = regs->d3;
  64 
  65         current->blocked = newmask & _BLOCKABLE;
  66         regs->d0 = -EINTR;
  67         while (1) {
  68                 current->state = TASK_INTERRUPTIBLE;
  69                 schedule();
  70                 if (do_signal(oldmask, regs))
  71                         return -EINTR;
  72         }
  73 }
  74 
  75 static unsigned char fpu_version = 0;   /* version number of fpu, set by setup_frame */
  76 
  77 /*
  78  * This sets regs->usp even though we don't actually use sigstacks yet..
  79  */
  80 asmlinkage int do_sigreturn(unsigned long __unused)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82         struct sigcontext_struct context;
  83         struct frame * regs;
  84         struct switch_stack *sw;
  85         int fsize = 0;
  86         int formatvec = 0;
  87         unsigned long fp;
  88         unsigned long usp = rdusp();
  89 
  90 #if 0
  91         printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
  92 #endif
  93 
  94         /* get stack frame pointer */
  95         sw = (struct switch_stack *) &__unused;
  96         regs = (struct frame *) (sw + 1);
  97 
  98         /* get previous context (including pointer to possible extra junk) */
  99         if (verify_area(VERIFY_READ, (void *)usp, sizeof(context)))
 100                 goto badframe;
 101 
 102         memcpy_fromfs(&context,(void *)usp, sizeof(context));
 103 
 104         fp = usp + sizeof (context);
 105 
 106         /* restore signal mask */
 107         current->blocked = context.sc_mask & _BLOCKABLE;
 108 
 109         /* restore passed registers */
 110         regs->ptregs.d0 = context.sc_d0;
 111         regs->ptregs.d1 = context.sc_d1;
 112         regs->ptregs.a0 = context.sc_a0;
 113         regs->ptregs.a1 = context.sc_a1;
 114         regs->ptregs.sr = (regs->ptregs.sr & 0xff00)|(context.sc_sr & 0xff);
 115         regs->ptregs.pc = context.sc_pc;
 116 
 117         wrusp(context.sc_usp);
 118         formatvec = context.sc_formatvec;
 119         regs->ptregs.format = formatvec >> 12;
 120         regs->ptregs.vector = formatvec & 0xfff;
 121         if (context.sc_fpstate[0])
 122           {
 123             /* Verify the frame format.  */
 124             if (context.sc_fpstate[0] != fpu_version){
 125 #if DEBUG
 126             printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
 127                    context.sc_fpcntl); 
 128             printk("Wrong fpu: sc_fpstate[0]=%02x fpu_version=%02x\n",
 129                    (unsigned) context.sc_fpstate[0], (unsigned) fpu_version);
 130             {
 131               int i;
 132               printk("Saved fp_state: ");
 133               for (i = 0; i < 216; i++){
 134                 printk("%02x ", context.sc_fpstate[i]);
 135               }
 136               printk("\n");
 137             }
 138 #endif
 139               goto badframe;
 140             }
 141             if (boot_info.cputype & FPU_68881)
 142               {
 143                 if (context.sc_fpstate[1] != 0x18
 144                     && context.sc_fpstate[1] != 0xb4)
 145                   goto badframe;
 146               }
 147             else if (boot_info.cputype & FPU_68882)
 148               {
 149                 if (context.sc_fpstate[1] != 0x38
 150                     && context.sc_fpstate[1] != 0xd4){
 151 #if 0
 152                   printk("Wrong 68882 fpu-state\n");
 153 #endif
 154                   goto badframe;
 155                 }
 156               }
 157             else if (boot_info.cputype & FPU_68040)
 158               {
 159                 if (!((context.sc_fpstate[1] == 0x00)|| \
 160                       (context.sc_fpstate[1] == 0x28)|| \
 161                       (context.sc_fpstate[1] == 0x60))){
 162 #if 0
 163                   printk("Wrong 68040 fpu-state\n");
 164 #endif
 165                   goto badframe;
 166                 }
 167               }
 168             else if (boot_info.cputype & FPU_68060)
 169               {
 170                 if (!((context.sc_fpstate[1] == 0x00)|| \
 171                       (context.sc_fpstate[1] == 0x60)|| \
 172                       (context.sc_fpstate[1] == 0xe0))){
 173 #if 0
 174                   printk("Wrong 68060 fpu-state\n");
 175 #endif
 176                   goto badframe;
 177                 }
 178               }
 179             __asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t"
 180                               "fmoveml %1,%/fpcr/%/fpsr/%/fpiar"
 181                               : /* no outputs */
 182                               : "m" (*context.sc_fpregs),
 183                                 "m" (*context.sc_fpcntl));
 184           }
 185         __asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate));
 186 
 187         fsize = extra_sizes[regs->ptregs.format];
 188         if (fsize < 0) {
 189                 /*
 190                  * user process trying to return with weird frame format
 191                  */
 192 #if DEBUG
 193               printk("user process returning with weird frame format\n");
 194 #endif
 195                 goto badframe;
 196         }
 197 
 198         /* OK.  Make room on the supervisor stack for the extra junk,
 199          * if necessary.
 200          */
 201 
 202         if (fsize) {
 203                 if (verify_area(VERIFY_READ, (void *)fp, fsize))
 204                         goto badframe;
 205 
 206 #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
 207                 __asm__ __volatile__
 208                         ("movel %0,%/a0\n\t"
 209                          "subl %1,%/a0\n\t"     /* make room on stack */
 210                          "movel %/a0,%/sp\n\t"  /* set stack pointer */
 211                          /* move switch_stack and pt_regs */
 212                          "1: movel %0@+,%/a0@+\n\t"
 213                          "   dbra %2,1b\n\t"
 214                          "lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt stuff */
 215                          "lsrl  #2,%1\n\t"
 216                          "subql #1,%1\n\t"
 217                          "2: movesl %4@+,%2\n\t"
 218                          "   movel %2,%/a0@+\n\t"
 219                          "   dbra %1,2b\n\t"
 220                          "bral " SYMBOL_NAME_STR(ret_from_signal)
 221                          : /* no outputs, it doesn't ever return */
 222                          : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
 223                            "n" (frame_offset), "a" (fp)
 224                          : "a0");
 225 #undef frame_offset
 226                 goto badframe;
 227                 /* NOTREACHED */
 228         }
 229 
 230         return regs->ptregs.d0;
 231 badframe:
 232         do_exit(SIGSEGV);
 233 }
 234 
 235 /*
 236  * Set up a signal frame...
 237  *
 238  * This routine is somewhat complicated by the fact that if the
 239  * kernel may be entered by an exception other than a system call;
 240  * e.g. a bus error or other "bad" exception.  If this is the case,
 241  * then *all* the context on the kernel stack frame must be saved.
 242  *
 243  * For a large number of exceptions, the stack frame format is the same
 244  * as that which will be created when the process traps back to the kernel
 245  * when finished executing the signal handler.  In this case, nothing
 246  * must be done.  This is exception frame format "0".  For exception frame
 247  * formats "2", "9", "A" and "B", the extra information on the frame must
 248  * be saved.  This information is saved on the user stack and restored
 249  * when the signal handler is returned.
 250  *
 251  * The format of the user stack when executing the signal handler is:
 252  *
 253  *     usp ->  RETADDR (points to code below)
 254  *             signum  (parm #1)
 255  *             sigcode (parm #2 ; vector number)
 256  *             scp     (parm #3 ; sigcontext pointer, pointer to #1 below)
 257  *             code1   (addaw #20,sp) ; pop parms and code off stack
 258  *             code2   (moveq #119,d0; trap #0) ; sigreturn syscall
 259  *     #1|     oldmask
 260  *       |     old usp
 261  *       |     d0      (first saved reg)
 262  *       |     d1
 263  *       |     a0
 264  *       |     a1
 265  *       |     sr      (saved status register)
 266  *       |     pc      (old pc; one to return to)
 267  *       |     forvec  (format and vector word of old supervisor stack frame)
 268  *       |     floating point context
 269  *
 270  * These are optionally followed by some extra stuff, depending on the
 271  * stack frame interrupted. This is 1 longword for format "2", 3
 272  * longwords for format "9", 6 longwords for format "A", and 21
 273  * longwords for format "B".
 274  */
 275 
 276 #define UFRAME_SIZE(fs) (sizeof(struct sigcontext_struct)/4 + 6 + fs/4)
 277 
 278 static void setup_frame (struct sigaction * sa, unsigned long **fp,
     /* [previous][next][first][last][top][bottom][index][help] */
 279                          unsigned long pc, struct frame *regs, int
 280                          signr, unsigned long oldmask)
 281 {
 282         struct sigcontext_struct context;
 283         unsigned long *frame, *tframe;
 284         int fsize = extra_sizes[regs->ptregs.format];
 285 
 286         if (fsize < 0) {
 287                 printk ("setup_frame: Unknown frame format %#x\n",
 288                         regs->ptregs.format);
 289                 do_exit(SIGSEGV);
 290         }
 291         frame = *fp - UFRAME_SIZE(fsize);
 292         if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4))
 293                 do_exit(SIGSEGV);
 294         if (fsize) {
 295                 memcpy_tofs (frame + UFRAME_SIZE(0), &regs->un, fsize);
 296                 regs->ptregs.stkadj = fsize;
 297         }
 298 
 299 /* set up the "normal" stack seen by the signal handler */
 300         tframe = frame;
 301 
 302         /* return address points to code on stack */
 303         put_user((ulong)(frame+4), tframe); tframe++;
 304         if (current->exec_domain && current->exec_domain->signal_invmap)
 305             put_user(current->exec_domain->signal_invmap[signr], tframe);
 306         else
 307             put_user(signr, tframe);
 308         tframe++;
 309 
 310         put_user(regs->ptregs.vector, tframe); tframe++;
 311         /* "scp" parameter.  points to sigcontext */
 312         put_user((ulong)(frame+6), tframe); tframe++;
 313 
 314 /* set up the return code... */
 315         put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */
 316         put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
 317 
 318 /* Flush caches so the instructions will be correctly executed. (MA) */
 319         cache_push_v ((unsigned long)frame, (int)tframe - (int)frame);
 320 
 321 /* setup and copy the sigcontext structure */
 322         context.sc_mask       = oldmask;
 323         context.sc_usp        = (unsigned long)*fp;
 324         context.sc_d0         = regs->ptregs.d0;
 325         context.sc_d1         = regs->ptregs.d1;
 326         context.sc_a0         = regs->ptregs.a0;
 327         context.sc_a1         = regs->ptregs.a1;
 328         context.sc_sr         = regs->ptregs.sr;
 329         context.sc_pc         = pc;
 330         context.sc_formatvec  = (regs->ptregs.format << 12 |
 331                                  regs->ptregs.vector);
 332 #if DEBUG
 333         printk("formatvec: %02x\n", (unsigned) context.sc_formatvec);
 334 #endif
 335         __asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory");
 336         if (context.sc_fpstate[0])
 337           {
 338             fpu_version = context.sc_fpstate[0];
 339 #if DEBUG
 340             {
 341               int i;
 342               printk("Saved fp_state: ");
 343               for (i = 0; i < 216; i++){
 344                 printk("%02x ", context.sc_fpstate[i]);
 345               }
 346               printk("\n");
 347             }
 348             printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
 349                    context.sc_fpcntl); 
 350 #endif
 351             __asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t"
 352                               "fmoveml %/fpcr/%/fpsr/%/fpiar,%1"
 353                               : /* no outputs */
 354                               : "m" (*context.sc_fpregs),
 355                                 "m" (*context.sc_fpcntl)
 356                               : "memory");
 357           }
 358 #if DEBUG
 359         {
 360           int i;
 361           printk("Saved fp_state: ");
 362           for (i = 0; i < 216; i++){
 363             printk("%02x ", context.sc_fpstate[i]);
 364           }
 365           printk("\n");
 366         }
 367 #endif
 368         memcpy_tofs (tframe, &context, sizeof(context));
 369         /*
 370          * no matter what frame format we were using before, we
 371          * will do the "RTE" using a normal 4 word frame.
 372          */
 373         regs->ptregs.format = 0;
 374 
 375         /* "return" new usp to caller */
 376         *fp = frame;
 377 }
 378 
 379 /*
 380  * Note that 'init' is a special process: it doesn't get signals it doesn't
 381  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 382  * mistake.
 383  *
 384  * Note that we go through the signals twice: once to check the signals
 385  * that the kernel can handle, and then we build all the user-level signal
 386  * handling stack-frames in one go after that.
 387  */
 388 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs_in)
     /* [previous][next][first][last][top][bottom][index][help] */
 389 {
 390         unsigned long mask = ~current->blocked;
 391         unsigned long handler_signal = 0;
 392         unsigned long *frame = NULL;
 393         unsigned long pc = 0;
 394         unsigned long signr;
 395         struct frame *regs = (struct frame *)regs_in;
 396         struct sigaction * sa;
 397 
 398         current->tss.esp0 = (unsigned long) regs;
 399 
 400         while ((signr = current->signal & mask)) {
 401                 __asm__("bfffo  %2,#0,#0,%1\n\t"
 402                         "bfclr  %0,%1,#1\n\t"
 403                         "eorw   #31,%1"
 404                         :"=m" (current->signal),"=r" (signr)
 405                         :"1" (signr));
 406                 sa = current->sig->action + signr;
 407                 signr++;
 408 
 409                 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 410                         current->exit_code = signr;
 411                         current->state = TASK_STOPPED;
 412                         notify_parent(current);
 413                         schedule();
 414                         if (!(signr = current->exit_code)) {
 415                         discard_frame:
 416                                 /* Make sure that a faulted bus cycle
 417                                    isn't restarted.  */
 418                                 switch (regs->ptregs.format) {
 419                                 case 7:
 420                                 case 9:
 421                                 case 10:
 422                                 case 11:
 423                                   regs->ptregs.stkadj = extra_sizes[regs->ptregs.format];
 424                                   regs->ptregs.format = 0;
 425                                   break;
 426                                 }
 427                                 continue;
 428                         }
 429                         current->exit_code = 0;
 430                         if (signr == SIGSTOP)
 431                                 goto discard_frame;
 432                         if (_S(signr) & current->blocked) {
 433                                 current->signal |= _S(signr);
 434                                 continue;
 435                         }
 436                         sa = current->sig->action + signr - 1;
 437                 }
 438                 if (sa->sa_handler == SIG_IGN) {
 439                         if (signr != SIGCHLD)
 440                                 continue;
 441                         /* check for SIGCHLD: it's special */
 442                         while (sys_waitpid(-1,NULL,WNOHANG) > 0)
 443                                 /* nothing */;
 444                         continue;
 445                 }
 446                 if (sa->sa_handler == SIG_DFL) {
 447                         if (current->pid == 1)
 448                                 continue;
 449                         switch (signr) {
 450                             case SIGCONT: case SIGCHLD: case SIGWINCH:
 451                                 continue;
 452 
 453                             case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
 454                                 if (current->flags & PF_PTRACED)
 455                                         continue;
 456                                 current->state = TASK_STOPPED;
 457                                 current->exit_code = signr;
 458                                 if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 459                                       SA_NOCLDSTOP))
 460                                         notify_parent(current);
 461                                 schedule();
 462                                 continue;
 463 
 464                             case SIGQUIT: case SIGILL: case SIGTRAP:
 465                             case SIGIOT: case SIGFPE: case SIGSEGV:
 466                                 if (current->binfmt && current->binfmt->core_dump) {
 467                                     if (current->binfmt->core_dump(signr, (struct pt_regs *)regs))
 468                                         signr |= 0x80;
 469                                 }
 470                                 /* fall through */
 471                             default:
 472                                 current->signal |= _S(signr & 0x7f);
 473                                 do_exit(signr);
 474                         }
 475                 }
 476                 /*
 477                  * OK, we're invoking a handler
 478                  */
 479                 if (regs->ptregs.orig_d0 >= 0) {
 480                   if (regs->ptregs.d0 == -ERESTARTNOHAND ||
 481                       (regs->ptregs.d0 == -ERESTARTSYS &&
 482                        !(sa->sa_flags & SA_RESTART)))
 483                     regs->ptregs.d0 = -EINTR;
 484                 }
 485                 handler_signal |= 1 << (signr-1);
 486                 mask &= ~sa->sa_mask;
 487         }
 488         if (regs->ptregs.orig_d0 >= 0 &&
 489             (regs->ptregs.d0 == -ERESTARTNOHAND ||
 490              regs->ptregs.d0 == -ERESTARTSYS ||
 491              regs->ptregs.d0 == -ERESTARTNOINTR)) {
 492                 regs->ptregs.d0 = regs->ptregs.orig_d0;
 493                 regs->ptregs.pc -= 2;
 494         }
 495         if (!handler_signal)    /* no handler will be called - return 0 */
 496           {
 497             /* If we are about to discard some frame stuff we must
 498                copy over the remaining frame. */
 499             if (regs->ptregs.stkadj)
 500               {
 501                 struct frame *tregs =
 502                   (struct frame *) ((ulong) regs + regs->ptregs.stkadj);
 503 
 504                 /* This must be copied with decreasing addresses to
 505                    handle overlaps.  */
 506                 tregs->ptregs.vector = regs->ptregs.vector;
 507                 tregs->ptregs.format = regs->ptregs.format;
 508                 tregs->ptregs.pc = regs->ptregs.pc;
 509                 tregs->ptregs.sr = regs->ptregs.sr;
 510               }
 511             return 0;
 512           }
 513         pc = regs->ptregs.pc;
 514         frame = (unsigned long *)rdusp();
 515         signr = 1;
 516         sa = current->sig->action;
 517         for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
 518                 if (mask > handler_signal)
 519                         break;
 520                 if (!(mask & handler_signal))
 521                         continue;
 522                 setup_frame(sa,&frame,pc,regs,signr,oldmask);
 523                 pc = (unsigned long) sa->sa_handler;
 524                 if (sa->sa_flags & SA_ONESHOT)
 525                         sa->sa_handler = NULL;
 526 /* force a supervisor-mode page-in of the signal handler to reduce races */
 527                 __asm__ __volatile__("movesb %0,%/d0": :"m" (*(char *)pc):"d0");
 528                 current->blocked |= sa->sa_mask;
 529                 oldmask |= sa->sa_mask;
 530         }
 531         wrusp((unsigned long)frame);
 532         regs->ptregs.pc = pc;
 533 
 534         /*
 535          * if setup_frame saved some extra frame junk, we need to
 536          * skip over that stuff when doing the RTE.  This means we have
 537          * to move the machine portion of the stack frame to where the
 538          * "RTE" instruction expects it. The signal that we need to
 539          * do this is that regs->stkadj is nonzero.
 540          */
 541         if (regs->ptregs.stkadj) {
 542                 struct frame *tregs =
 543                         (struct frame *)((ulong)regs + regs->ptregs.stkadj);
 544 #if DEBUG
 545           printk("Performing stackadjust=%04x\n", (unsigned)
 546                  regs->ptregs.stkadj);
 547 #endif
 548                 /* This must be copied with decreasing addresses to
 549                    handle overlaps.  */
 550                 tregs->ptregs.vector = regs->ptregs.vector;
 551                 tregs->ptregs.format = regs->ptregs.format;
 552                 tregs->ptregs.pc = regs->ptregs.pc;
 553                 tregs->ptregs.sr = regs->ptregs.sr;
 554         }
 555 
 556         return 1;
 557 }

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