linux/arch/m68knommu/kernel/signal.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/m68knommu/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 COPYING in the main directory of this archive
   8 * for more details.
   9 */
  10
  11/*
  12 * Linux/m68k support by Hamish Macdonald
  13 *
  14 * 68060 fixes by Jesper Skov
  15 *
  16 * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
  17 *
  18 * mathemu support by Roman Zippel
  19 *  (Note: fpstate in the signal context is completely ignored for the emulator
  20 *         and the internal floating point format is put on stack)
  21 */
  22
  23/*
  24 * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
  25 * Atari :-) Current limitation: Only one sigstack can be active at one time.
  26 * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
  27 * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
  28 * signal handlers!
  29 */
  30
  31#include <linux/sched.h>
  32#include <linux/mm.h>
  33#include <linux/kernel.h>
  34#include <linux/signal.h>
  35#include <linux/syscalls.h>
  36#include <linux/errno.h>
  37#include <linux/wait.h>
  38#include <linux/ptrace.h>
  39#include <linux/unistd.h>
  40#include <linux/stddef.h>
  41#include <linux/highuid.h>
  42#include <linux/tty.h>
  43#include <linux/personality.h>
  44#include <linux/binfmts.h>
  45
  46#include <asm/setup.h>
  47#include <asm/uaccess.h>
  48#include <asm/pgtable.h>
  49#include <asm/traps.h>
  50#include <asm/ucontext.h>
  51
  52#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
  53
  54void ret_from_user_signal(void);
  55void ret_from_user_rt_signal(void);
  56asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
  57
  58/*
  59 * Atomically swap in the new signal mask, and wait for a signal.
  60 */
  61asmlinkage int do_sigsuspend(struct pt_regs *regs)
  62{
  63        old_sigset_t mask = regs->d3;
  64        sigset_t saveset;
  65
  66        mask &= _BLOCKABLE;
  67        spin_lock_irq(&current->sighand->siglock);
  68        saveset = current->blocked;
  69        siginitset(&current->blocked, mask);
  70        recalc_sigpending();
  71        spin_unlock_irq(&current->sighand->siglock);
  72
  73        regs->d0 = -EINTR;
  74        while (1) {
  75                current->state = TASK_INTERRUPTIBLE;
  76                schedule();
  77                if (do_signal(&saveset, regs))
  78                        return -EINTR;
  79        }
  80}
  81
  82asmlinkage int
  83do_rt_sigsuspend(struct pt_regs *regs)
  84{
  85        sigset_t *unewset = (sigset_t *)regs->d1;
  86        size_t sigsetsize = (size_t)regs->d2;
  87        sigset_t saveset, newset;
  88
  89        /* XXX: Don't preclude handling different sized sigset_t's.  */
  90        if (sigsetsize != sizeof(sigset_t))
  91                return -EINVAL;
  92
  93        if (copy_from_user(&newset, unewset, sizeof(newset)))
  94                return -EFAULT;
  95        sigdelsetmask(&newset, ~_BLOCKABLE);
  96
  97        spin_lock_irq(&current->sighand->siglock);
  98        saveset = current->blocked;
  99        current->blocked = newset;
 100        recalc_sigpending();
 101        spin_unlock_irq(&current->sighand->siglock);
 102
 103        regs->d0 = -EINTR;
 104        while (1) {
 105                current->state = TASK_INTERRUPTIBLE;
 106                schedule();
 107                if (do_signal(&saveset, regs))
 108                        return -EINTR;
 109        }
 110}
 111
 112asmlinkage int 
 113sys_sigaction(int sig, const struct old_sigaction *act,
 114              struct old_sigaction *oact)
 115{
 116        struct k_sigaction new_ka, old_ka;
 117        int ret;
 118
 119        if (act) {
 120                old_sigset_t mask;
 121                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 122                    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 123                    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 124                        return -EFAULT;
 125                __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 126                __get_user(mask, &act->sa_mask);
 127                siginitset(&new_ka.sa.sa_mask, mask);
 128        }
 129
 130        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 131
 132        if (!ret && oact) {
 133                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 134                    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 135                    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 136                        return -EFAULT;
 137                __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 138                __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 139        }
 140
 141        return ret;
 142}
 143
 144asmlinkage int
 145sys_sigaltstack(const stack_t *uss, stack_t *uoss)
 146{
 147        return do_sigaltstack(uss, uoss, rdusp());
 148}
 149
 150
 151/*
 152 * Do a signal return; undo the signal stack.
 153 *
 154 * Keep the return code on the stack quadword aligned!
 155 * That makes the cache flush below easier.
 156 */
 157
 158struct sigframe
 159{
 160        char *pretcode;
 161        int sig;
 162        int code;
 163        struct sigcontext *psc;
 164        char retcode[8];
 165        unsigned long extramask[_NSIG_WORDS-1];
 166        struct sigcontext sc;
 167};
 168
 169struct rt_sigframe
 170{
 171        char *pretcode;
 172        int sig;
 173        struct siginfo *pinfo;
 174        void *puc;
 175        char retcode[8];
 176        struct siginfo info;
 177        struct ucontext uc;
 178};
 179
 180#ifdef CONFIG_FPU
 181
 182static unsigned char fpu_version = 0;   /* version number of fpu, set by setup_frame */
 183
 184static inline int restore_fpu_state(struct sigcontext *sc)
 185{
 186        int err = 1;
 187
 188        if (FPU_IS_EMU) {
 189            /* restore registers */
 190            memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
 191            memcpy(current->thread.fp, sc->sc_fpregs, 24);
 192            return 0;
 193        }
 194
 195        if (sc->sc_fpstate[0]) {
 196            /* Verify the frame format.  */
 197            if (sc->sc_fpstate[0] != fpu_version)
 198                goto out;
 199
 200            __asm__ volatile (".chip 68k/68881\n\t"
 201                              "fmovemx %0,%/fp0-%/fp1\n\t"
 202                              "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
 203                              ".chip 68k"
 204                              : /* no outputs */
 205                              : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
 206        }
 207        __asm__ volatile (".chip 68k/68881\n\t"
 208                          "frestore %0\n\t"
 209                          ".chip 68k" : : "m" (*sc->sc_fpstate));
 210        err = 0;
 211
 212out:
 213        return err;
 214}
 215
 216#define FPCONTEXT_SIZE  216
 217#define uc_fpstate      uc_filler[0]
 218#define uc_formatvec    uc_filler[FPCONTEXT_SIZE/4]
 219#define uc_extra        uc_filler[FPCONTEXT_SIZE/4+1]
 220
 221static inline int rt_restore_fpu_state(struct ucontext *uc)
 222{
 223        unsigned char fpstate[FPCONTEXT_SIZE];
 224        int context_size = 0;
 225        fpregset_t fpregs;
 226        int err = 1;
 227
 228        if (FPU_IS_EMU) {
 229                /* restore fpu control register */
 230                if (__copy_from_user(current->thread.fpcntl,
 231                                &uc->uc_mcontext.fpregs.f_pcr, 12))
 232                        goto out;
 233                /* restore all other fpu register */
 234                if (__copy_from_user(current->thread.fp,
 235                                uc->uc_mcontext.fpregs.f_fpregs, 96))
 236                        goto out;
 237                return 0;
 238        }
 239
 240        if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
 241                goto out;
 242        if (fpstate[0]) {
 243                context_size = fpstate[1];
 244
 245                /* Verify the frame format.  */
 246                if (fpstate[0] != fpu_version)
 247                        goto out;
 248                if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
 249                     sizeof(fpregs)))
 250                        goto out;
 251                __asm__ volatile (".chip 68k/68881\n\t"
 252                                  "fmovemx %0,%/fp0-%/fp7\n\t"
 253                                  "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
 254                                  ".chip 68k"
 255                                  : /* no outputs */
 256                                  : "m" (*fpregs.f_fpregs),
 257                                    "m" (fpregs.f_pcr));
 258        }
 259        if (context_size &&
 260            __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1,
 261                             context_size))
 262                goto out;
 263        __asm__ volatile (".chip 68k/68881\n\t"
 264                          "frestore %0\n\t"
 265                          ".chip 68k" : : "m" (*fpstate));
 266        err = 0;
 267
 268out:
 269        return err;
 270}
 271
 272#endif
 273
 274static inline int
 275restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
 276                   int *pd0)
 277{
 278        int formatvec;
 279        struct sigcontext context;
 280        int err = 0;
 281
 282        /* get previous context */
 283        if (copy_from_user(&context, usc, sizeof(context)))
 284                goto badframe;
 285        
 286        /* restore passed registers */
 287        regs->d1 = context.sc_d1;
 288        regs->a0 = context.sc_a0;
 289        regs->a1 = context.sc_a1;
 290        ((struct switch_stack *)regs - 1)->a5 = context.sc_a5;
 291        regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
 292        regs->pc = context.sc_pc;
 293        regs->orig_d0 = -1;             /* disable syscall checks */
 294        wrusp(context.sc_usp);
 295        formatvec = context.sc_formatvec;
 296        regs->format = formatvec >> 12;
 297        regs->vector = formatvec & 0xfff;
 298
 299#ifdef CONFIG_FPU
 300        err = restore_fpu_state(&context);
 301#endif
 302
 303        *pd0 = context.sc_d0;
 304        return err;
 305
 306badframe:
 307        return 1;
 308}
 309
 310static inline int
 311rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
 312                    struct ucontext *uc, int *pd0)
 313{
 314        int temp;
 315        greg_t *gregs = uc->uc_mcontext.gregs;
 316        unsigned long usp;
 317        int err;
 318
 319        err = __get_user(temp, &uc->uc_mcontext.version);
 320        if (temp != MCONTEXT_VERSION)
 321                goto badframe;
 322        /* restore passed registers */
 323        err |= __get_user(regs->d0, &gregs[0]);
 324        err |= __get_user(regs->d1, &gregs[1]);
 325        err |= __get_user(regs->d2, &gregs[2]);
 326        err |= __get_user(regs->d3, &gregs[3]);
 327        err |= __get_user(regs->d4, &gregs[4]);
 328        err |= __get_user(regs->d5, &gregs[5]);
 329        err |= __get_user(sw->d6, &gregs[6]);
 330        err |= __get_user(sw->d7, &gregs[7]);
 331        err |= __get_user(regs->a0, &gregs[8]);
 332        err |= __get_user(regs->a1, &gregs[9]);
 333        err |= __get_user(regs->a2, &gregs[10]);
 334        err |= __get_user(sw->a3, &gregs[11]);
 335        err |= __get_user(sw->a4, &gregs[12]);
 336        err |= __get_user(sw->a5, &gregs[13]);
 337        err |= __get_user(sw->a6, &gregs[14]);
 338        err |= __get_user(usp, &gregs[15]);
 339        wrusp(usp);
 340        err |= __get_user(regs->pc, &gregs[16]);
 341        err |= __get_user(temp, &gregs[17]);
 342        regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
 343        regs->orig_d0 = -1;             /* disable syscall checks */
 344        regs->format = temp >> 12;
 345        regs->vector = temp & 0xfff;
 346
 347        if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
 348                goto badframe;
 349
 350        *pd0 = regs->d0;
 351        return err;
 352
 353badframe:
 354        return 1;
 355}
 356
 357asmlinkage int do_sigreturn(unsigned long __unused)
 358{
 359        struct switch_stack *sw = (struct switch_stack *) &__unused;
 360        struct pt_regs *regs = (struct pt_regs *) (sw + 1);
 361        unsigned long usp = rdusp();
 362        struct sigframe *frame = (struct sigframe *)(usp - 4);
 363        sigset_t set;
 364        int d0;
 365
 366        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 367                goto badframe;
 368        if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
 369            (_NSIG_WORDS > 1 &&
 370             __copy_from_user(&set.sig[1], &frame->extramask,
 371                              sizeof(frame->extramask))))
 372                goto badframe;
 373
 374        sigdelsetmask(&set, ~_BLOCKABLE);
 375        spin_lock_irq(&current->sighand->siglock);
 376        current->blocked = set;
 377        recalc_sigpending();
 378        spin_unlock_irq(&current->sighand->siglock);
 379        
 380        if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
 381                goto badframe;
 382        return d0;
 383
 384badframe:
 385        force_sig(SIGSEGV, current);
 386        return 0;
 387}
 388
 389asmlinkage int do_rt_sigreturn(unsigned long __unused)
 390{
 391        struct switch_stack *sw = (struct switch_stack *) &__unused;
 392        struct pt_regs *regs = (struct pt_regs *) (sw + 1);
 393        unsigned long usp = rdusp();
 394        struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
 395        sigset_t set;
 396        int d0;
 397
 398        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 399                goto badframe;
 400        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 401                goto badframe;
 402
 403        sigdelsetmask(&set, ~_BLOCKABLE);
 404        spin_lock_irq(&current->sighand->siglock);
 405        current->blocked = set;
 406        recalc_sigpending();
 407        spin_unlock_irq(&current->sighand->siglock);
 408        
 409        if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
 410                goto badframe;
 411        return d0;
 412
 413badframe:
 414        force_sig(SIGSEGV, current);
 415        return 0;
 416}
 417
 418#ifdef CONFIG_FPU
 419/*
 420 * Set up a signal frame.
 421 */
 422
 423static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
 424{
 425        if (FPU_IS_EMU) {
 426                /* save registers */
 427                memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
 428                memcpy(sc->sc_fpregs, current->thread.fp, 24);
 429                return;
 430        }
 431
 432        __asm__ volatile (".chip 68k/68881\n\t"
 433                          "fsave %0\n\t"
 434                          ".chip 68k"
 435                          : : "m" (*sc->sc_fpstate) : "memory");
 436
 437        if (sc->sc_fpstate[0]) {
 438                fpu_version = sc->sc_fpstate[0];
 439                __asm__ volatile (".chip 68k/68881\n\t"
 440                                  "fmovemx %/fp0-%/fp1,%0\n\t"
 441                                  "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
 442                                  ".chip 68k"
 443                                  : /* no outputs */
 444                                  : "m" (*sc->sc_fpregs),
 445                                    "m" (*sc->sc_fpcntl)
 446                                  : "memory");
 447        }
 448}
 449
 450static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
 451{
 452        unsigned char fpstate[FPCONTEXT_SIZE];
 453        int context_size = 0;
 454        int err = 0;
 455
 456        if (FPU_IS_EMU) {
 457                /* save fpu control register */
 458                err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr,
 459                                current->thread.fpcntl, 12);
 460                /* save all other fpu register */
 461                err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
 462                                current->thread.fp, 96);
 463                return err;
 464        }
 465
 466        __asm__ volatile (".chip 68k/68881\n\t"
 467                          "fsave %0\n\t"
 468                          ".chip 68k"
 469                          : : "m" (*fpstate) : "memory");
 470
 471        err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
 472        if (fpstate[0]) {
 473                fpregset_t fpregs;
 474                context_size = fpstate[1];
 475                fpu_version = fpstate[0];
 476                __asm__ volatile (".chip 68k/68881\n\t"
 477                                  "fmovemx %/fp0-%/fp7,%0\n\t"
 478                                  "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
 479                                  ".chip 68k"
 480                                  : /* no outputs */
 481                                  : "m" (*fpregs.f_fpregs),
 482                                    "m" (fpregs.f_pcr)
 483                                  : "memory");
 484                err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
 485                                    sizeof(fpregs));
 486        }
 487        if (context_size)
 488                err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
 489                                    context_size);
 490        return err;
 491}
 492
 493#endif
 494
 495static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 496                             unsigned long mask)
 497{
 498        sc->sc_mask = mask;
 499        sc->sc_usp = rdusp();
 500        sc->sc_d0 = regs->d0;
 501        sc->sc_d1 = regs->d1;
 502        sc->sc_a0 = regs->a0;
 503        sc->sc_a1 = regs->a1;
 504        sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5;
 505        sc->sc_sr = regs->sr;
 506        sc->sc_pc = regs->pc;
 507        sc->sc_formatvec = regs->format << 12 | regs->vector;
 508#ifdef CONFIG_FPU
 509        save_fpu_state(sc, regs);
 510#endif
 511}
 512
 513static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
 514{
 515        struct switch_stack *sw = (struct switch_stack *)regs - 1;
 516        greg_t *gregs = uc->uc_mcontext.gregs;
 517        int err = 0;
 518
 519        err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
 520        err |= __put_user(regs->d0, &gregs[0]);
 521        err |= __put_user(regs->d1, &gregs[1]);
 522        err |= __put_user(regs->d2, &gregs[2]);
 523        err |= __put_user(regs->d3, &gregs[3]);
 524        err |= __put_user(regs->d4, &gregs[4]);
 525        err |= __put_user(regs->d5, &gregs[5]);
 526        err |= __put_user(sw->d6, &gregs[6]);
 527        err |= __put_user(sw->d7, &gregs[7]);
 528        err |= __put_user(regs->a0, &gregs[8]);
 529        err |= __put_user(regs->a1, &gregs[9]);
 530        err |= __put_user(regs->a2, &gregs[10]);
 531        err |= __put_user(sw->a3, &gregs[11]);
 532        err |= __put_user(sw->a4, &gregs[12]);
 533        err |= __put_user(sw->a5, &gregs[13]);
 534        err |= __put_user(sw->a6, &gregs[14]);
 535        err |= __put_user(rdusp(), &gregs[15]);
 536        err |= __put_user(regs->pc, &gregs[16]);
 537        err |= __put_user(regs->sr, &gregs[17]);
 538#ifdef CONFIG_FPU
 539        err |= rt_save_fpu_state(uc, regs);
 540#endif
 541        return err;
 542}
 543
 544static inline void *
 545get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 546{
 547        unsigned long usp;
 548
 549        /* Default to using normal stack.  */
 550        usp = rdusp();
 551
 552        /* This is the X/Open sanctioned signal stack switching.  */
 553        if (ka->sa.sa_flags & SA_ONSTACK) {
 554                if (!sas_ss_flags(usp))
 555                        usp = current->sas_ss_sp + current->sas_ss_size;
 556        }
 557        return (void *)((usp - frame_size) & -8UL);
 558}
 559
 560static void setup_frame (int sig, struct k_sigaction *ka,
 561                         sigset_t *set, struct pt_regs *regs)
 562{
 563        struct sigframe *frame;
 564        struct sigcontext context;
 565        int err = 0;
 566
 567        frame = get_sigframe(ka, regs, sizeof(*frame));
 568
 569        err |= __put_user((current_thread_info()->exec_domain
 570                           && current_thread_info()->exec_domain->signal_invmap
 571                           && sig < 32
 572                           ? current_thread_info()->exec_domain->signal_invmap[sig]
 573                           : sig),
 574                          &frame->sig);
 575
 576        err |= __put_user(regs->vector, &frame->code);
 577        err |= __put_user(&frame->sc, &frame->psc);
 578
 579        if (_NSIG_WORDS > 1)
 580                err |= copy_to_user(frame->extramask, &set->sig[1],
 581                                    sizeof(frame->extramask));
 582
 583        setup_sigcontext(&context, regs, set->sig[0]);
 584        err |= copy_to_user (&frame->sc, &context, sizeof(context));
 585
 586        /* Set up to return from userspace.  */
 587        err |= __put_user((void *) ret_from_user_signal, &frame->pretcode);
 588
 589        if (err)
 590                goto give_sigsegv;
 591
 592        /* Set up registers for signal handler */
 593        wrusp ((unsigned long) frame);
 594        regs->pc = (unsigned long) ka->sa.sa_handler;
 595        ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
 596        regs->format = 0x4; /*set format byte to make stack appear modulo 4 
 597                                                which it will be when doing the rte */
 598
 599adjust_stack:
 600        /* Prepare to skip over the extra stuff in the exception frame.  */
 601        if (regs->stkadj) {
 602                struct pt_regs *tregs =
 603                        (struct pt_regs *)((ulong)regs + regs->stkadj);
 604#if defined(DEBUG)
 605                printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
 606#endif
 607                /* This must be copied with decreasing addresses to
 608                   handle overlaps.  */
 609                tregs->vector = 0;
 610                tregs->format = 0;
 611                tregs->pc = regs->pc;
 612                tregs->sr = regs->sr;
 613        }
 614        return;
 615
 616give_sigsegv:
 617        force_sigsegv(sig, current);
 618        goto adjust_stack;
 619}
 620
 621static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
 622                            sigset_t *set, struct pt_regs *regs)
 623{
 624        struct rt_sigframe *frame;
 625        int err = 0;
 626
 627        frame = get_sigframe(ka, regs, sizeof(*frame));
 628
 629        err |= __put_user((current_thread_info()->exec_domain
 630                           && current_thread_info()->exec_domain->signal_invmap
 631                           && sig < 32
 632                           ? current_thread_info()->exec_domain->signal_invmap[sig]
 633                           : sig),
 634                          &frame->sig);
 635        err |= __put_user(&frame->info, &frame->pinfo);
 636        err |= __put_user(&frame->uc, &frame->puc);
 637        err |= copy_siginfo_to_user(&frame->info, info);
 638
 639        /* Create the ucontext.  */
 640        err |= __put_user(0, &frame->uc.uc_flags);
 641        err |= __put_user(0, &frame->uc.uc_link);
 642        err |= __put_user((void *)current->sas_ss_sp,
 643                          &frame->uc.uc_stack.ss_sp);
 644        err |= __put_user(sas_ss_flags(rdusp()),
 645                          &frame->uc.uc_stack.ss_flags);
 646        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 647        err |= rt_setup_ucontext(&frame->uc, regs);
 648        err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
 649
 650        /* Set up to return from userspace.  */
 651        err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode);
 652
 653        if (err)
 654                goto give_sigsegv;
 655
 656        /* Set up registers for signal handler */
 657        wrusp ((unsigned long) frame);
 658        regs->pc = (unsigned long) ka->sa.sa_handler;
 659        ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
 660        regs->format = 0x4; /*set format byte to make stack appear modulo 4 
 661                                                which it will be when doing the rte */
 662
 663adjust_stack:
 664        /* Prepare to skip over the extra stuff in the exception frame.  */
 665        if (regs->stkadj) {
 666                struct pt_regs *tregs =
 667                        (struct pt_regs *)((ulong)regs + regs->stkadj);
 668#if defined(DEBUG)
 669                printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
 670#endif
 671                /* This must be copied with decreasing addresses to
 672                   handle overlaps.  */
 673                tregs->vector = 0;
 674                tregs->format = 0;
 675                tregs->pc = regs->pc;
 676                tregs->sr = regs->sr;
 677        }
 678        return;
 679
 680give_sigsegv:
 681        force_sigsegv(sig, current);
 682        goto adjust_stack;
 683}
 684
 685static inline void
 686handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
 687{
 688        switch (regs->d0) {
 689        case -ERESTARTNOHAND:
 690                if (!has_handler)
 691                        goto do_restart;
 692                regs->d0 = -EINTR;
 693                break;
 694
 695        case -ERESTARTSYS:
 696                if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
 697                        regs->d0 = -EINTR;
 698                        break;
 699                }
 700        /* fallthrough */
 701        case -ERESTARTNOINTR:
 702        do_restart:
 703                regs->d0 = regs->orig_d0;
 704                regs->pc -= 2;
 705                break;
 706        }
 707}
 708
 709/*
 710 * OK, we're invoking a handler
 711 */
 712static void
 713handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
 714              sigset_t *oldset, struct pt_regs *regs)
 715{
 716        /* are we from a system call? */
 717        if (regs->orig_d0 >= 0)
 718                /* If so, check system call restarting.. */
 719                handle_restart(regs, ka, 1);
 720
 721        /* set up the stack frame */
 722        if (ka->sa.sa_flags & SA_SIGINFO)
 723                setup_rt_frame(sig, ka, info, oldset, regs);
 724        else
 725                setup_frame(sig, ka, oldset, regs);
 726
 727        if (ka->sa.sa_flags & SA_ONESHOT)
 728                ka->sa.sa_handler = SIG_DFL;
 729
 730        spin_lock_irq(&current->sighand->siglock);
 731        sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 732        if (!(ka->sa.sa_flags & SA_NODEFER))
 733                sigaddset(&current->blocked,sig);
 734        recalc_sigpending();
 735        spin_unlock_irq(&current->sighand->siglock);
 736}
 737
 738/*
 739 * Note that 'init' is a special process: it doesn't get signals it doesn't
 740 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 741 * mistake.
 742 */
 743asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 744{
 745        struct k_sigaction ka;
 746        siginfo_t info;
 747        int signr;
 748
 749        /*
 750         * We want the common case to go fast, which
 751         * is why we may in certain cases get here from
 752         * kernel mode. Just return without doing anything
 753         * if so.
 754         */
 755        if (!user_mode(regs))
 756                return 1;
 757
 758        if (!oldset)
 759                oldset = &current->blocked;
 760
 761        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 762        if (signr > 0) {
 763                /* Whee!  Actually deliver the signal.  */
 764                handle_signal(signr, &ka, &info, oldset, regs);
 765                return 1;
 766        }
 767
 768        /* Did we come from a system call? */
 769        if (regs->orig_d0 >= 0) {
 770                /* Restart the system call - no handlers present */
 771                handle_restart(regs, NULL, 0);
 772        }
 773        return 0;
 774}
 775
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.