root/arch/i386/kernel/signal.c

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

DEFINITIONS

This source file includes following definitions.
  1. sys_sigsuspend
  2. restore_i387_hard
  3. restore_i387
  4. sys_sigreturn
  5. save_i387_hard
  6. save_i387
  7. setup_frame
  8. handle_signal
  9. do_signal

   1 /*
   2  *  linux/arch/i386/kernel/signal.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/config.h>
   8 
   9 #include <linux/sched.h>
  10 #include <linux/mm.h>
  11 #include <linux/kernel.h>
  12 #include <linux/signal.h>
  13 #include <linux/errno.h>
  14 #include <linux/wait.h>
  15 #include <linux/ptrace.h>
  16 #include <linux/unistd.h>
  17 
  18 #include <asm/segment.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  */
  30 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32         unsigned long mask;
  33         struct pt_regs * regs = (struct pt_regs *) &restart;
  34 
  35         mask = current->blocked;
  36         current->blocked = set & _BLOCKABLE;
  37         regs->eax = -EINTR;
  38         while (1) {
  39                 current->state = TASK_INTERRUPTIBLE;
  40                 schedule();
  41                 if (do_signal(mask,regs))
  42                         return -EINTR;
  43         }
  44 }
  45 
  46 /*
  47  * FIXME. We don't currently restore emulator state
  48  */
  49 #define restore_i387_soft(x) do { } while (0)
  50 
  51 static inline void restore_i387_hard(struct _fpstate *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53 #ifdef __SMP__
  54         if (current->flags & PF_USEDFPU) {
  55                 stts();
  56         }
  57 #else
  58         if (current == last_task_used_math) {
  59                 last_task_used_math = NULL;
  60                 stts();
  61         }
  62 #endif
  63         current->used_math = 1;
  64         current->flags &= ~PF_USEDFPU;
  65         memcpy_fromfs(&current->tss.i387.hard, buf, sizeof(*buf));
  66 }
  67 
  68 static void restore_i387(struct _fpstate *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70 #ifndef CONFIG_MATH_EMULATION
  71         restore_i387_hard(buf);
  72 #else
  73         if (hard_math) {
  74                 restore_i387_hard(buf);
  75                 return;
  76         }
  77         restore_i387_soft(buf);
  78 #endif  
  79 }
  80         
  81 
  82 /*
  83  * This sets regs->esp even though we don't actually use sigstacks yet..
  84  */
  85 asmlinkage int sys_sigreturn(unsigned long __unused)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87 #define COPY(x) regs->x = context.x
  88 #define COPY_SEG(x) \
  89 if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);
  90 #define COPY_SEG_STRICT(x) \
  91 if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
  92         struct sigcontext_struct context;
  93         struct pt_regs * regs;
  94 
  95         regs = (struct pt_regs *) &__unused;
  96         if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))
  97                 goto badframe;
  98         memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
  99         current->blocked = context.oldmask & _BLOCKABLE;
 100         COPY_SEG(ds);
 101         COPY_SEG(es);
 102         COPY_SEG(fs);
 103         COPY_SEG(gs);
 104         COPY_SEG_STRICT(ss);
 105         COPY_SEG_STRICT(cs);
 106         COPY(eip);
 107         COPY(ecx); COPY(edx);
 108         COPY(ebx);
 109         COPY(esp); COPY(ebp);
 110         COPY(edi); COPY(esi);
 111         regs->eflags &= ~0x40DD5;
 112         regs->eflags |= context.eflags & 0x40DD5;
 113         regs->orig_eax = -1;            /* disable syscall checks */
 114         if (context.fpstate) {
 115                 struct _fpstate * buf = context.fpstate;
 116                 if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
 117                         goto badframe;
 118                 restore_i387(buf);
 119         }
 120         return context.eax;
 121 badframe:
 122         do_exit(SIGSEGV);
 123 }
 124 
 125 /*
 126  * FIXME. We currently don't save 387 state if we use emulation
 127  */
 128 #define save_i387_soft(x) NULL
 129 
 130 static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132 #ifdef __SMP__
 133         if (current->flags & PF_USEDFPU) {
 134                 __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard));
 135                 stts();
 136                 current->flags &= ~PF_USEDFPU;
 137         }
 138 #else
 139         if (current == last_task_used_math) {
 140                 __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard));
 141                 last_task_used_math = NULL;
 142                 __asm__ __volatile__("fwait");  /* not needed on 486+ */
 143                 stts();
 144         }
 145 #endif
 146         current->tss.i387.hard.status = current->tss.i387.hard.swd;
 147         memcpy_tofs(buf, &current->tss.i387.hard, sizeof(*buf));
 148         current->used_math = 0;
 149         return buf;
 150 }
 151 
 152 static struct _fpstate * save_i387(struct _fpstate * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154         if (!current->used_math)
 155                 return NULL;
 156 
 157 #ifndef CONFIG_MATH_EMULATION
 158         return save_i387_hard(buf);
 159 #else
 160         if (hard_math)
 161                 return save_i387_hard(buf);
 162         return save_i387_soft(buf);
 163 #endif
 164 }
 165 
 166 /*
 167  * Set up a signal frame... Make the stack look the way iBCS2 expects
 168  * it to look.
 169  */
 170 static void setup_frame(struct sigaction * sa,
     /* [previous][next][first][last][top][bottom][index][help] */
 171         struct pt_regs * regs, int signr,
 172         unsigned long oldmask)
 173 {
 174         unsigned long * frame;
 175 
 176         frame = (unsigned long *) regs->esp;
 177         if (regs->ss != USER_DS && sa->sa_restorer)
 178                 frame = (unsigned long *) sa->sa_restorer;
 179         frame -= 64;
 180         if (verify_area(VERIFY_WRITE,frame,64*4))
 181                 do_exit(SIGSEGV);
 182 
 183 /* set up the "normal" stack seen by the signal handler (iBCS2) */
 184 #define __CODE ((unsigned long)(frame+24))
 185 #define CODE(x) ((unsigned long *) ((x)+__CODE))
 186         put_user(__CODE,frame);
 187         if (current->exec_domain && current->exec_domain->signal_invmap)
 188                 put_user(current->exec_domain->signal_invmap[signr], frame+1);
 189         else
 190                 put_user(signr, frame+1);
 191         put_user(regs->gs, frame+2);
 192         put_user(regs->fs, frame+3);
 193         put_user(regs->es, frame+4);
 194         put_user(regs->ds, frame+5);
 195         put_user(regs->edi, frame+6);
 196         put_user(regs->esi, frame+7);
 197         put_user(regs->ebp, frame+8);
 198         put_user(regs->esp, frame+9);
 199         put_user(regs->ebx, frame+10);
 200         put_user(regs->edx, frame+11);
 201         put_user(regs->ecx, frame+12);
 202         put_user(regs->eax, frame+13);
 203         put_user(current->tss.trap_no, frame+14);
 204         put_user(current->tss.error_code, frame+15);
 205         put_user(regs->eip, frame+16);
 206         put_user(regs->cs, frame+17);
 207         put_user(regs->eflags, frame+18);
 208         put_user(regs->esp, frame+19);
 209         put_user(regs->ss, frame+20);
 210         put_user(save_i387((struct _fpstate *)(frame+32)),frame+21);
 211 /* non-iBCS2 extensions.. */
 212         put_user(oldmask, frame+22);
 213         put_user(current->tss.cr2, frame+23);
 214 /* set up the return code... */
 215         put_user(0x0000b858, CODE(0));  /* popl %eax ; movl $,%eax */
 216         put_user(0x80cd0000, CODE(4));  /* int $0x80 */
 217         put_user(__NR_sigreturn, CODE(2));
 218 #undef __CODE
 219 #undef CODE
 220 
 221         /* Set up registers for signal handler */
 222         regs->esp = (unsigned long) frame;
 223         regs->eip = (unsigned long) sa->sa_handler;
 224         regs->cs = USER_CS; regs->ss = USER_DS;
 225         regs->ds = USER_DS; regs->es = USER_DS;
 226         regs->gs = USER_DS; regs->fs = USER_DS;
 227         regs->eflags &= ~TF_MASK;
 228 }
 229 
 230 /*
 231  * OK, we're invoking a handler
 232  */     
 233 static void handle_signal(unsigned long signr, struct sigaction *sa,
     /* [previous][next][first][last][top][bottom][index][help] */
 234         unsigned long oldmask, struct pt_regs * regs)
 235 {
 236         /* are we from a system call? */
 237         if (regs->orig_eax >= 0) {
 238                 /* If so, check system call restarting.. */
 239                 switch (regs->eax) {
 240                         case -ERESTARTNOHAND:
 241                                 regs->eax = -EINTR;
 242                                 break;
 243 
 244                         case -ERESTARTSYS:
 245                                 if (!(sa->sa_flags & SA_RESTART)) {
 246                                         regs->eax = -EINTR;
 247                                         break;
 248                                 }
 249                         /* fallthrough */
 250                         case -ERESTARTNOINTR:
 251                                 regs->eax = regs->orig_eax;
 252                                 regs->eip -= 2;
 253                 }
 254         }
 255 
 256         /* set up the stack frame */
 257         setup_frame(sa, regs, signr, oldmask);
 258 
 259         if (sa->sa_flags & SA_ONESHOT)
 260                 sa->sa_handler = NULL;
 261         current->blocked |= sa->sa_mask;
 262 }
 263 
 264 /*
 265  * Note that 'init' is a special process: it doesn't get signals it doesn't
 266  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 267  * mistake.
 268  *
 269  * Note that we go through the signals twice: once to check the signals that
 270  * the kernel can handle, and then we build all the user-level signal handling
 271  * stack-frames in one go after that.
 272  */
 273 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275         unsigned long mask = ~current->blocked;
 276         unsigned long signr;
 277         struct sigaction * sa;
 278 
 279         while ((signr = current->signal & mask)) {
 280                 /*
 281                  *      This stops gcc flipping out. Otherwise the assembler
 282                  *      including volatiles for the inline function to get
 283                  *      current combined with this gets it confused.
 284                  */
 285                 struct task_struct *t=current;
 286                 __asm__("bsf %3,%1\n\t"
 287                         "btrl %1,%0"
 288                         :"=m" (t->signal),"=r" (signr)
 289                         :"0" (t->signal), "1" (signr));
 290                 sa = current->sig->action + signr;
 291                 signr++;
 292                 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 293                         current->exit_code = signr;
 294                         current->state = TASK_STOPPED;
 295                         notify_parent(current);
 296                         schedule();
 297                         if (!(signr = current->exit_code))
 298                                 continue;
 299                         current->exit_code = 0;
 300                         if (signr == SIGSTOP)
 301                                 continue;
 302                         if (_S(signr) & current->blocked) {
 303                                 current->signal |= _S(signr);
 304                                 continue;
 305                         }
 306                         sa = current->sig->action + signr - 1;
 307                 }
 308                 if (sa->sa_handler == SIG_IGN) {
 309                         if (signr != SIGCHLD)
 310                                 continue;
 311                         /* check for SIGCHLD: it's special */
 312                         while (sys_waitpid(-1,NULL,WNOHANG) > 0)
 313                                 /* nothing */;
 314                         continue;
 315                 }
 316                 if (sa->sa_handler == SIG_DFL) {
 317                         if (current->pid == 1)
 318                                 continue;
 319                         switch (signr) {
 320                         case SIGCONT: case SIGCHLD: case SIGWINCH:
 321                                 continue;
 322 
 323                         case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
 324                                 if (current->flags & PF_PTRACED)
 325                                         continue;
 326                                 current->state = TASK_STOPPED;
 327                                 current->exit_code = signr;
 328                                 if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 329                                                 SA_NOCLDSTOP))
 330                                         notify_parent(current);
 331                                 schedule();
 332                                 continue;
 333 
 334                         case SIGQUIT: case SIGILL: case SIGTRAP:
 335                         case SIGABRT: case SIGFPE: case SIGSEGV:
 336                                 if (current->binfmt && current->binfmt->core_dump) {
 337                                         if (current->binfmt->core_dump(signr, regs))
 338                                                 signr |= 0x80;
 339                                 }
 340                                 /* fall through */
 341                         default:
 342                                 current->signal |= _S(signr & 0x7f);
 343                                 current->flags |= PF_SIGNALED;
 344                                 do_exit(signr);
 345                         }
 346                 }
 347                 handle_signal(signr, sa, oldmask, regs);
 348                 return 1;
 349         }
 350 
 351         /* Did we come from a system call? */
 352         if (regs->orig_eax >= 0) {
 353                 /* Restart the system call - no handlers present */
 354                 if (regs->eax == -ERESTARTNOHAND ||
 355                     regs->eax == -ERESTARTSYS ||
 356                     regs->eax == -ERESTARTNOINTR) {
 357                         regs->eax = regs->orig_eax;
 358                         regs->eip -= 2;
 359                 }
 360         }
 361         return 0;
 362 }

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