home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / mips / kernel / signal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-23  |  8.1 KB  |  313 lines

  1. /*
  2.  *  linux/arch/mips/kernel/signal.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. #include <linux/sched.h>
  8. #include <linux/mm.h>
  9. #include <linux/kernel.h>
  10. #include <linux/signal.h>
  11. #include <linux/errno.h>
  12. #include <linux/wait.h>
  13. #include <linux/ptrace.h>
  14. #include <linux/unistd.h>
  15.  
  16. #include <asm/segment.h>
  17. #include <asm/cachectl.h>
  18.  
  19. #define _S(nr) (1<<((nr)-1))
  20.  
  21. #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  22.  
  23. asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
  24.  
  25. /*
  26.  * atomically swap in the new signal mask, and wait for a signal.
  27.  */
  28. asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
  29. {
  30.     unsigned long mask;
  31.     struct pt_regs * regs = (struct pt_regs *) &restart;
  32.  
  33.     mask = current->blocked;
  34.     current->blocked = set & _BLOCKABLE;
  35.     regs->reg2 = -EINTR;
  36.     while (1) {
  37.         current->state = TASK_INTERRUPTIBLE;
  38.         schedule();
  39.         if (do_signal(mask,regs))
  40.             return -EINTR;
  41.     }
  42. }
  43.  
  44. /*
  45.  * This sets regs->reg29 even though we don't actually use sigstacks yet..
  46.  */
  47. asmlinkage int sys_sigreturn(unsigned long __unused)
  48. {
  49.     struct sigcontext_struct context;
  50.     struct pt_regs * regs;
  51.  
  52.     regs = (struct pt_regs *) &__unused;
  53.     if (verify_area(VERIFY_READ, (void *) regs->reg29, sizeof(context)))
  54.         goto badframe;
  55.     memcpy_fromfs(&context,(void *) regs->reg29, sizeof(context));
  56.     current->blocked = context.oldmask & _BLOCKABLE;
  57.     regs->reg1  = context.sc_at;
  58.     regs->reg2  = context.sc_v0;
  59.     regs->reg3  = context.sc_v1;
  60.     regs->reg4  = context.sc_a0;
  61.     regs->reg5  = context.sc_a1;
  62.     regs->reg6  = context.sc_a2;
  63.     regs->reg7  = context.sc_a3;
  64.     regs->reg8  = context.sc_t0;
  65.     regs->reg9  = context.sc_t1;
  66.     regs->reg10 = context.sc_t2;
  67.     regs->reg11 = context.sc_t3;
  68.     regs->reg12 = context.sc_t4;
  69.     regs->reg13 = context.sc_t5;
  70.     regs->reg14 = context.sc_t6;
  71.     regs->reg15 = context.sc_t7;
  72.     regs->reg16 = context.sc_s0;
  73.     regs->reg17 = context.sc_s1;
  74.     regs->reg18 = context.sc_s2;
  75.     regs->reg19 = context.sc_s3;
  76.     regs->reg20 = context.sc_s4;
  77.     regs->reg21 = context.sc_s5;
  78.     regs->reg22 = context.sc_s6;
  79.     regs->reg23 = context.sc_s7;
  80.     regs->reg24 = context.sc_t8;
  81.     regs->reg25 = context.sc_t9;
  82.     /*
  83.      * Skip k0/k1
  84.      */
  85.     regs->reg28 = context.sc_gp;
  86.     regs->reg29 = context.sc_sp;
  87.     regs->reg30 = context.sc_fp;
  88.     regs->reg31 = context.sc_ra;
  89.     regs->cp0_epc = context.sc_epc;
  90.     regs->cp0_cause = context.sc_cause;
  91.  
  92.     /*
  93.      * disable syscall checks
  94.      */
  95.     regs->orig_reg2 = -1;
  96.     return regs->orig_reg2;
  97. badframe:
  98.     do_exit(SIGSEGV);
  99. }
  100.  
  101. /*
  102.  * Set up a signal frame...
  103.  */
  104. static void setup_frame(struct sigaction * sa, unsigned long ** fp,
  105.                         unsigned long pc, struct pt_regs *regs,
  106.                         int signr, unsigned long oldmask)
  107. {
  108.     unsigned long * frame;
  109.  
  110.     frame = *fp;
  111.     frame -= 32;
  112.     if (verify_area(VERIFY_WRITE,frame,21*4))
  113.         do_exit(SIGSEGV);
  114.     /*
  115.      * set up the "normal" stack seen by the signal handler
  116.      */
  117.     put_fs_long(regs->reg1 , frame   );
  118.     put_fs_long(regs->reg2 , frame+ 1);
  119.     put_fs_long(regs->reg3 , frame+ 2);
  120.     put_fs_long(regs->reg4 , frame+ 3);
  121.     put_fs_long(regs->reg5 , frame+ 4);
  122.     put_fs_long(regs->reg6 , frame+ 5);
  123.     put_fs_long(regs->reg7 , frame+ 6);
  124.     put_fs_long(regs->reg8 , frame+ 7);
  125.     put_fs_long(regs->reg9 , frame+ 8);
  126.     put_fs_long(regs->reg10, frame+ 9);
  127.     put_fs_long(regs->reg11, frame+10);
  128.     put_fs_long(regs->reg12, frame+11);
  129.     put_fs_long(regs->reg13, frame+12);
  130.     put_fs_long(regs->reg14, frame+13);
  131.     put_fs_long(regs->reg15, frame+14);
  132.     put_fs_long(regs->reg16, frame+15);
  133.     put_fs_long(regs->reg17, frame+16);
  134.     put_fs_long(regs->reg18, frame+17);
  135.     put_fs_long(regs->reg19, frame+18);
  136.     put_fs_long(regs->reg20, frame+19);
  137.     put_fs_long(regs->reg21, frame+20);
  138.     put_fs_long(regs->reg22, frame+21);
  139.     put_fs_long(regs->reg23, frame+22);
  140.     put_fs_long(regs->reg24, frame+23);
  141.     put_fs_long(regs->reg25, frame+24);
  142.     /*
  143.      * Don't copy k0/k1
  144.      */
  145.     put_fs_long(regs->reg28, frame+25);
  146.     put_fs_long(regs->reg29, frame+26);
  147.     put_fs_long(regs->reg30, frame+27);
  148.     put_fs_long(regs->reg31, frame+28);
  149.     put_fs_long(pc         , frame+29);
  150.     put_fs_long(oldmask    , frame+30);
  151.     /*
  152.      * set up the return code...
  153.      *
  154.      *         .set    noreorder
  155.      *         .set    noat
  156.      *         syscall
  157.      *         li      $1,__NR_sigreturn
  158.      *         .set    at
  159.      *         .set    reorder
  160.      */
  161.     put_fs_long(0x24010077, frame+31);        /* li    $1,119 */
  162.     put_fs_long(0x000000c0, frame+32);        /* syscall     */
  163.     *fp = frame;
  164.     /*
  165.      * Flush caches so the instructions will be correctly executed.
  166.      */
  167.     sys_cacheflush(frame, 32*4, BCACHE);
  168. }
  169.  
  170. /*
  171.  * Note that 'init' is a special process: it doesn't get signals it doesn't
  172.  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  173.  * mistake.
  174.  *
  175.  * Note that we go through the signals twice: once to check the signals that
  176.  * the kernel can handle, and then we build all the user-level signal handling
  177.  * stack-frames in one go after that.
  178.  */
  179. asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
  180. {
  181.     unsigned long mask = ~current->blocked;
  182.     unsigned long handler_signal = 0;
  183.     unsigned long *frame = NULL;
  184.     unsigned long pc = 0;
  185.     unsigned long signr;
  186.     struct sigaction * sa;
  187.  
  188.     while ((signr = current->signal & mask)) {
  189.         __asm__(".set\tnoreorder\n\t"
  190.             ".set\tnoat\n\t"
  191.             "li\t%0,31\n"
  192.             "1:\tsllv\t$1,%1,%0\n\t"
  193.             "bgezl\t$1,1b\n\t"
  194.             "subu\t$8,1\n\t"
  195.             "subu\t%0,31\n\t"
  196.             "subu\t%0,$0,%0\n\t"
  197.             "li\t$1,1\n\t"
  198.             "sllv\t$1,$1,%0\n\t"
  199.             "nor\t$1,$0\n\t"
  200.             "xor\t%1,$1\n\t"
  201.             ".set\tat\n\t"
  202.             ".set\treorder"
  203.             :"=r" (signr),"=r" (current->signal)
  204.             :"0"  (signr),"1"  (current->signal)
  205.             :"$1");
  206.         sa = current->sigaction + signr;
  207.         signr++;
  208.         if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
  209.             current->exit_code = signr;
  210.             current->state = TASK_STOPPED;
  211.             notify_parent(current);
  212.             schedule();
  213.             if (!(signr = current->exit_code))
  214.                 continue;
  215.             current->exit_code = 0;
  216.             if (signr == SIGSTOP)
  217.                 continue;
  218.             if (_S(signr) & current->blocked) {
  219.                 current->signal |= _S(signr);
  220.                 continue;
  221.             }
  222.             sa = current->sigaction + signr - 1;
  223.         }
  224.         if (sa->sa_handler == SIG_IGN) {
  225.             if (signr != SIGCHLD)
  226.                 continue;
  227.             /* check for SIGCHLD: it's special */
  228.             while (sys_waitpid(-1,NULL,WNOHANG) > 0)
  229.                 /* nothing */;
  230.             continue;
  231.         }
  232.         if (sa->sa_handler == SIG_DFL) {
  233.             if (current->pid == 1)
  234.                 continue;
  235.             switch (signr) {
  236.             case SIGCONT: case SIGCHLD: case SIGWINCH:
  237.                 continue;
  238.  
  239.             case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
  240.                 if (current->flags & PF_PTRACED)
  241.                     continue;
  242.                 current->state = TASK_STOPPED;
  243.                 current->exit_code = signr;
  244.                 if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
  245.                         SA_NOCLDSTOP))
  246.                     notify_parent(current);
  247.                 schedule();
  248.                 continue;
  249.  
  250.             case SIGQUIT: case SIGILL: case SIGTRAP:
  251.             case SIGIOT: case SIGFPE: case SIGSEGV:
  252.                 if (current->binfmt && current->binfmt->core_dump) {
  253.                     if (current->binfmt->core_dump(signr, regs))
  254.                         signr |= 0x80;
  255.                 }
  256.                 /* fall through */
  257.             default:
  258.                 current->signal |= _S(signr & 0x7f);
  259.                 do_exit(signr);
  260.             }
  261.         }
  262.         /*
  263.          * OK, we're invoking a handler
  264.          */
  265.         if (regs->orig_reg2 >= 0) {
  266.             if (regs->reg2 == -ERESTARTNOHAND ||
  267.                (regs->reg2 == -ERESTARTSYS &&
  268.                 !(sa->sa_flags & SA_RESTART)))
  269.                 regs->reg2 = -EINTR;
  270.         }
  271.         handler_signal |= 1 << (signr-1);
  272.         mask &= ~sa->sa_mask;
  273.     }
  274.     if (regs->orig_reg2 >= 0 &&
  275.         (regs->reg2 == -ERESTARTNOHAND ||
  276.          regs->reg2 == -ERESTARTSYS ||
  277.          regs->reg2 == -ERESTARTNOINTR)) {
  278.         regs->reg2 = regs->orig_reg2;
  279.         regs->cp0_epc -= 4;
  280.     }
  281.     if (!handler_signal)        /* no handler will be called - return 0 */
  282.         return 0;
  283.     pc = regs->cp0_epc;
  284.     frame = (unsigned long *) regs->reg29;
  285.     signr = 1;
  286.     sa = current->sigaction;
  287.     for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
  288.         if (mask > handler_signal)
  289.             break;
  290.         if (!(mask & handler_signal))
  291.             continue;
  292.         setup_frame(sa,&frame,pc,regs,signr,oldmask);
  293.         pc = (unsigned long) sa->sa_handler;
  294.         if (sa->sa_flags & SA_ONESHOT)
  295.             sa->sa_handler = NULL;
  296.         /*
  297.          * force a kernel-mode page-in of the signal
  298.          * handler to reduce races
  299.          */
  300.         __asm__(".set\tnoat\n\t"
  301.             "lwu\t$1,(%0)\n\t"
  302.             ".set\tat\n\t"
  303.             :
  304.             :"r" ((char *) pc)
  305.             :"$1");
  306.         current->blocked |= sa->sa_mask;
  307.         oldmask |= sa->sa_mask;
  308.     }
  309.     regs->reg29 = (unsigned long) frame;
  310.     regs->cp0_epc = pc;        /* "return" to the first handler */
  311.     return 1;
  312. }
  313.