linux/arch/m68k/kernel/signal.c
<<
>>
Prefs
   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 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/personality.h>
  43#include <linux/tty.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
  54asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
  55
  56const int frame_extra_sizes[16] = {
  57  [1]   = -1, /* sizeof(((struct frame *)0)->un.fmt1), */
  58  [2]   = sizeof(((struct frame *)0)->un.fmt2),
  59  [3]   = sizeof(((struct frame *)0)->un.fmt3),
  60  [4]   = sizeof(((struct frame *)0)->un.fmt4),
  61  [5]   = -1, /* sizeof(((struct frame *)0)->un.fmt5), */
  62  [6]   = -1, /* sizeof(((struct frame *)0)->un.fmt6), */
  63  [7]   = sizeof(((struct frame *)0)->un.fmt7),
  64  [8]   = -1, /* sizeof(((struct frame *)0)->un.fmt8), */
  65  [9]   = sizeof(((struct frame *)0)->un.fmt9),
  66  [10]  = sizeof(((struct frame *)0)->un.fmta),
  67  [11]  = sizeof(((struct frame *)0)->un.fmtb),
  68  [12]  = -1, /* sizeof(((struct frame *)0)->un.fmtc), */
  69  [13]  = -1, /* sizeof(((struct frame *)0)->un.fmtd), */
  70  [14]  = -1, /* sizeof(((struct frame *)0)->un.fmte), */
  71  [15]  = -1, /* sizeof(((struct frame *)0)->un.fmtf), */
  72};
  73
  74/*
  75 * Atomically swap in the new signal mask, and wait for a signal.
  76 */
  77asmlinkage int do_sigsuspend(struct pt_regs *regs)
  78{
  79        old_sigset_t mask = regs->d3;
  80        sigset_t saveset;
  81
  82        mask &= _BLOCKABLE;
  83        saveset = current->blocked;
  84        siginitset(&current->blocked, mask);
  85        recalc_sigpending();
  86
  87        regs->d0 = -EINTR;
  88        while (1) {
  89                current->state = TASK_INTERRUPTIBLE;
  90                schedule();
  91                if (do_signal(&saveset, regs))
  92                        return -EINTR;
  93        }
  94}
  95
  96asmlinkage int
  97do_rt_sigsuspend(struct pt_regs *regs)
  98{
  99        sigset_t __user *unewset = (sigset_t __user *)regs->d1;
 100        size_t sigsetsize = (size_t)regs->d2;
 101        sigset_t saveset, newset;
 102
 103        /* XXX: Don't preclude handling different sized sigset_t's.  */
 104        if (sigsetsize != sizeof(sigset_t))
 105                return -EINVAL;
 106
 107        if (copy_from_user(&newset, unewset, sizeof(newset)))
 108                return -EFAULT;
 109        sigdelsetmask(&newset, ~_BLOCKABLE);
 110
 111        saveset = current->blocked;
 112        current->blocked = newset;
 113        recalc_sigpending();
 114
 115        regs->d0 = -EINTR;
 116        while (1) {
 117                current->state = TASK_INTERRUPTIBLE;
 118                schedule();
 119                if (do_signal(&saveset, regs))
 120                        return -EINTR;
 121        }
 122}
 123
 124asmlinkage int
 125sys_sigaction(int sig, const struct old_sigaction __user *act,
 126              struct old_sigaction __user *oact)
 127{
 128        struct k_sigaction new_ka, old_ka;
 129        int ret;
 130
 131        if (act) {
 132                old_sigset_t mask;
 133                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 134                    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 135                    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 136                        return -EFAULT;
 137                __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 138                __get_user(mask, &act->sa_mask);
 139                siginitset(&new_ka.sa.sa_mask, mask);
 140        }
 141
 142        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 143
 144        if (!ret && oact) {
 145                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 146                    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 147                    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 148                        return -EFAULT;
 149                __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 150                __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 151        }
 152
 153        return ret;
 154}
 155
 156asmlinkage int
 157sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
 158{
 159        return do_sigaltstack(uss, uoss, rdusp());
 160}
 161
 162
 163/*
 164 * Do a signal return; undo the signal stack.
 165 *
 166 * Keep the return code on the stack quadword aligned!
 167 * That makes the cache flush below easier.
 168 */
 169
 170struct sigframe
 171{
 172        char __user *pretcode;
 173        int sig;
 174        int code;
 175        struct sigcontext __user *psc;
 176        char retcode[8];
 177        unsigned long extramask[_NSIG_WORDS-1];
 178        struct sigcontext sc;
 179};
 180
 181struct rt_sigframe
 182{
 183        char __user *pretcode;
 184        int sig;
 185        struct siginfo __user *pinfo;
 186        void __user *puc;
 187        char retcode[8];
 188        struct siginfo info;
 189        struct ucontext uc;
 190};
 191
 192
 193static unsigned char fpu_version;       /* version number of fpu, set by setup_frame */
 194
 195static inline int restore_fpu_state(struct sigcontext *sc)
 196{
 197        int err = 1;
 198
 199        if (FPU_IS_EMU) {
 200            /* restore registers */
 201            memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
 202            memcpy(current->thread.fp, sc->sc_fpregs, 24);
 203            return 0;
 204        }
 205
 206        if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
 207            /* Verify the frame format.  */
 208            if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
 209                goto out;
 210            if (CPU_IS_020_OR_030) {
 211                if (m68k_fputype & FPU_68881 &&
 212                    !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
 213                    goto out;
 214                if (m68k_fputype & FPU_68882 &&
 215                    !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
 216                    goto out;
 217            } else if (CPU_IS_040) {
 218                if (!(sc->sc_fpstate[1] == 0x00 ||
 219                      sc->sc_fpstate[1] == 0x28 ||
 220                      sc->sc_fpstate[1] == 0x60))
 221                    goto out;
 222            } else if (CPU_IS_060) {
 223                if (!(sc->sc_fpstate[3] == 0x00 ||
 224                      sc->sc_fpstate[3] == 0x60 ||
 225                      sc->sc_fpstate[3] == 0xe0))
 226                    goto out;
 227            } else
 228                goto out;
 229
 230            __asm__ volatile (".chip 68k/68881\n\t"
 231                              "fmovemx %0,%%fp0-%%fp1\n\t"
 232                              "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
 233                              ".chip 68k"
 234                              : /* no outputs */
 235                              : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
 236        }
 237        __asm__ volatile (".chip 68k/68881\n\t"
 238                          "frestore %0\n\t"
 239                          ".chip 68k" : : "m" (*sc->sc_fpstate));
 240        err = 0;
 241
 242out:
 243        return err;
 244}
 245
 246#define FPCONTEXT_SIZE  216
 247#define uc_fpstate      uc_filler[0]
 248#define uc_formatvec    uc_filler[FPCONTEXT_SIZE/4]
 249#define uc_extra        uc_filler[FPCONTEXT_SIZE/4+1]
 250
 251static inline int rt_restore_fpu_state(struct ucontext __user *uc)
 252{
 253        unsigned char fpstate[FPCONTEXT_SIZE];
 254        int context_size = CPU_IS_060 ? 8 : 0;
 255        fpregset_t fpregs;
 256        int err = 1;
 257
 258        if (FPU_IS_EMU) {
 259                /* restore fpu control register */
 260                if (__copy_from_user(current->thread.fpcntl,
 261                                uc->uc_mcontext.fpregs.f_fpcntl, 12))
 262                        goto out;
 263                /* restore all other fpu register */
 264                if (__copy_from_user(current->thread.fp,
 265                                uc->uc_mcontext.fpregs.f_fpregs, 96))
 266                        goto out;
 267                return 0;
 268        }
 269
 270        if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
 271                goto out;
 272        if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
 273                if (!CPU_IS_060)
 274                        context_size = fpstate[1];
 275                /* Verify the frame format.  */
 276                if (!CPU_IS_060 && (fpstate[0] != fpu_version))
 277                        goto out;
 278                if (CPU_IS_020_OR_030) {
 279                        if (m68k_fputype & FPU_68881 &&
 280                            !(context_size == 0x18 || context_size == 0xb4))
 281                                goto out;
 282                        if (m68k_fputype & FPU_68882 &&
 283                            !(context_size == 0x38 || context_size == 0xd4))
 284                                goto out;
 285                } else if (CPU_IS_040) {
 286                        if (!(context_size == 0x00 ||
 287                              context_size == 0x28 ||
 288                              context_size == 0x60))
 289                                goto out;
 290                } else if (CPU_IS_060) {
 291                        if (!(fpstate[3] == 0x00 ||
 292                              fpstate[3] == 0x60 ||
 293                              fpstate[3] == 0xe0))
 294                                goto out;
 295                } else
 296                        goto out;
 297                if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
 298                                     sizeof(fpregs)))
 299                        goto out;
 300                __asm__ volatile (".chip 68k/68881\n\t"
 301                                  "fmovemx %0,%%fp0-%%fp7\n\t"
 302                                  "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
 303                                  ".chip 68k"
 304                                  : /* no outputs */
 305                                  : "m" (*fpregs.f_fpregs),
 306                                    "m" (*fpregs.f_fpcntl));
 307        }
 308        if (context_size &&
 309            __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
 310                             context_size))
 311                goto out;
 312        __asm__ volatile (".chip 68k/68881\n\t"
 313                          "frestore %0\n\t"
 314                          ".chip 68k" : : "m" (*fpstate));
 315        err = 0;
 316
 317out:
 318        return err;
 319}
 320
 321static inline int
 322restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp,
 323                   int *pd0)
 324{
 325        int fsize, formatvec;
 326        struct sigcontext context;
 327        int err;
 328
 329        /* get previous context */
 330        if (copy_from_user(&context, usc, sizeof(context)))
 331                goto badframe;
 332
 333        /* restore passed registers */
 334        regs->d1 = context.sc_d1;
 335        regs->a0 = context.sc_a0;
 336        regs->a1 = context.sc_a1;
 337        regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
 338        regs->pc = context.sc_pc;
 339        regs->orig_d0 = -1;             /* disable syscall checks */
 340        wrusp(context.sc_usp);
 341        formatvec = context.sc_formatvec;
 342        regs->format = formatvec >> 12;
 343        regs->vector = formatvec & 0xfff;
 344
 345        err = restore_fpu_state(&context);
 346
 347        fsize = frame_extra_sizes[regs->format];
 348        if (fsize < 0) {
 349                /*
 350                 * user process trying to return with weird frame format
 351                 */
 352#ifdef DEBUG
 353                printk("user process returning with weird frame format\n");
 354#endif
 355                goto badframe;
 356        }
 357
 358        /* OK.  Make room on the supervisor stack for the extra junk,
 359         * if necessary.
 360         */
 361
 362        if (fsize) {
 363                struct switch_stack *sw = (struct switch_stack *)regs - 1;
 364                regs->d0 = context.sc_d0;
 365#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
 366                __asm__ __volatile__
 367                        ("   movel %0,%/a0\n\t"
 368                         "   subl %1,%/a0\n\t"     /* make room on stack */
 369                         "   movel %/a0,%/sp\n\t"  /* set stack pointer */
 370                         /* move switch_stack and pt_regs */
 371                         "1: movel %0@+,%/a0@+\n\t"
 372                         "   dbra %2,1b\n\t"
 373                         "   lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
 374                         "   lsrl  #2,%1\n\t"
 375                         "   subql #1,%1\n\t"
 376                         "2: movesl %4@+,%2\n\t"
 377                         "3: movel %2,%/a0@+\n\t"
 378                         "   dbra %1,2b\n\t"
 379                         "   bral ret_from_signal\n"
 380                         "4:\n"
 381                         ".section __ex_table,\"a\"\n"
 382                         "   .align 4\n"
 383                         "   .long 2b,4b\n"
 384                         "   .long 3b,4b\n"
 385                         ".previous"
 386                         : /* no outputs, it doesn't ever return */
 387                         : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
 388                           "n" (frame_offset), "a" (fp)
 389                         : "a0");
 390#undef frame_offset
 391                /*
 392                 * If we ever get here an exception occurred while
 393                 * building the above stack-frame.
 394                 */
 395                goto badframe;
 396        }
 397
 398        *pd0 = context.sc_d0;
 399        return err;
 400
 401badframe:
 402        return 1;
 403}
 404
 405static inline int
 406rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
 407                    struct ucontext __user *uc, int *pd0)
 408{
 409        int fsize, temp;
 410        greg_t __user *gregs = uc->uc_mcontext.gregs;
 411        unsigned long usp;
 412        int err;
 413
 414        err = __get_user(temp, &uc->uc_mcontext.version);
 415        if (temp != MCONTEXT_VERSION)
 416                goto badframe;
 417        /* restore passed registers */
 418        err |= __get_user(regs->d0, &gregs[0]);
 419        err |= __get_user(regs->d1, &gregs[1]);
 420        err |= __get_user(regs->d2, &gregs[2]);
 421        err |= __get_user(regs->d3, &gregs[3]);
 422        err |= __get_user(regs->d4, &gregs[4]);
 423        err |= __get_user(regs->d5, &gregs[5]);
 424        err |= __get_user(sw->d6, &gregs[6]);
 425        err |= __get_user(sw->d7, &gregs[7]);
 426        err |= __get_user(regs->a0, &gregs[8]);
 427        err |= __get_user(regs->a1, &gregs[9]);
 428        err |= __get_user(regs->a2, &gregs[10]);
 429        err |= __get_user(sw->a3, &gregs[11]);
 430        err |= __get_user(sw->a4, &gregs[12]);
 431        err |= __get_user(sw->a5, &gregs[13]);
 432        err |= __get_user(sw->a6, &gregs[14]);
 433        err |= __get_user(usp, &gregs[15]);
 434        wrusp(usp);
 435        err |= __get_user(regs->pc, &gregs[16]);
 436        err |= __get_user(temp, &gregs[17]);
 437        regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
 438        regs->orig_d0 = -1;             /* disable syscall checks */
 439        err |= __get_user(temp, &uc->uc_formatvec);
 440        regs->format = temp >> 12;
 441        regs->vector = temp & 0xfff;
 442
 443        err |= rt_restore_fpu_state(uc);
 444
 445        if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
 446                goto badframe;
 447
 448        fsize = frame_extra_sizes[regs->format];
 449        if (fsize < 0) {
 450                /*
 451                 * user process trying to return with weird frame format
 452                 */
 453#ifdef DEBUG
 454                printk("user process returning with weird frame format\n");
 455#endif
 456                goto badframe;
 457        }
 458
 459        /* OK.  Make room on the supervisor stack for the extra junk,
 460         * if necessary.
 461         */
 462
 463        if (fsize) {
 464#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
 465                __asm__ __volatile__
 466                        ("   movel %0,%/a0\n\t"
 467                         "   subl %1,%/a0\n\t"     /* make room on stack */
 468                         "   movel %/a0,%/sp\n\t"  /* set stack pointer */
 469                         /* move switch_stack and pt_regs */
 470                         "1: movel %0@+,%/a0@+\n\t"
 471                         "   dbra %2,1b\n\t"
 472                         "   lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
 473                         "   lsrl  #2,%1\n\t"
 474                         "   subql #1,%1\n\t"
 475                         "2: movesl %4@+,%2\n\t"
 476                         "3: movel %2,%/a0@+\n\t"
 477                         "   dbra %1,2b\n\t"
 478                         "   bral ret_from_signal\n"
 479                         "4:\n"
 480                         ".section __ex_table,\"a\"\n"
 481                         "   .align 4\n"
 482                         "   .long 2b,4b\n"
 483                         "   .long 3b,4b\n"
 484                         ".previous"
 485                         : /* no outputs, it doesn't ever return */
 486                         : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
 487                           "n" (frame_offset), "a" (&uc->uc_extra)
 488                         : "a0");
 489#undef frame_offset
 490                /*
 491                 * If we ever get here an exception occurred while
 492                 * building the above stack-frame.
 493                 */
 494                goto badframe;
 495        }
 496
 497        *pd0 = regs->d0;
 498        return err;
 499
 500badframe:
 501        return 1;
 502}
 503
 504asmlinkage int do_sigreturn(unsigned long __unused)
 505{
 506        struct switch_stack *sw = (struct switch_stack *) &__unused;
 507        struct pt_regs *regs = (struct pt_regs *) (sw + 1);
 508        unsigned long usp = rdusp();
 509        struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
 510        sigset_t set;
 511        int d0;
 512
 513        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 514                goto badframe;
 515        if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
 516            (_NSIG_WORDS > 1 &&
 517             __copy_from_user(&set.sig[1], &frame->extramask,
 518                              sizeof(frame->extramask))))
 519                goto badframe;
 520
 521        sigdelsetmask(&set, ~_BLOCKABLE);
 522        current->blocked = set;
 523        recalc_sigpending();
 524
 525        if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
 526                goto badframe;
 527        return d0;
 528
 529badframe:
 530        force_sig(SIGSEGV, current);
 531        return 0;
 532}
 533
 534asmlinkage int do_rt_sigreturn(unsigned long __unused)
 535{
 536        struct switch_stack *sw = (struct switch_stack *) &__unused;
 537        struct pt_regs *regs = (struct pt_regs *) (sw + 1);
 538        unsigned long usp = rdusp();
 539        struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
 540        sigset_t set;
 541        int d0;
 542
 543        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 544                goto badframe;
 545        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 546                goto badframe;
 547
 548        sigdelsetmask(&set, ~_BLOCKABLE);
 549        current->blocked = set;
 550        recalc_sigpending();
 551
 552        if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
 553                goto badframe;
 554        return d0;
 555
 556badframe:
 557        force_sig(SIGSEGV, current);
 558        return 0;
 559}
 560
 561/*
 562 * Set up a signal frame.
 563 */
 564
 565static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
 566{
 567        if (FPU_IS_EMU) {
 568                /* save registers */
 569                memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
 570                memcpy(sc->sc_fpregs, current->thread.fp, 24);
 571                return;
 572        }
 573
 574        __asm__ volatile (".chip 68k/68881\n\t"
 575                          "fsave %0\n\t"
 576                          ".chip 68k"
 577                          : : "m" (*sc->sc_fpstate) : "memory");
 578
 579        if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
 580                fpu_version = sc->sc_fpstate[0];
 581                if (CPU_IS_020_OR_030 &&
 582                    regs->vector >= (VEC_FPBRUC * 4) &&
 583                    regs->vector <= (VEC_FPNAN * 4)) {
 584                        /* Clear pending exception in 68882 idle frame */
 585                        if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
 586                                sc->sc_fpstate[0x38] |= 1 << 3;
 587                }
 588                __asm__ volatile (".chip 68k/68881\n\t"
 589                                  "fmovemx %%fp0-%%fp1,%0\n\t"
 590                                  "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
 591                                  ".chip 68k"
 592                                  : "=m" (*sc->sc_fpregs),
 593                                    "=m" (*sc->sc_fpcntl)
 594                                  : /* no inputs */
 595                                  : "memory");
 596        }
 597}
 598
 599static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
 600{
 601        unsigned char fpstate[FPCONTEXT_SIZE];
 602        int context_size = CPU_IS_060 ? 8 : 0;
 603        int err = 0;
 604
 605        if (FPU_IS_EMU) {
 606                /* save fpu control register */
 607                err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl,
 608                                current->thread.fpcntl, 12);
 609                /* save all other fpu register */
 610                err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
 611                                current->thread.fp, 96);
 612                return err;
 613        }
 614
 615        __asm__ volatile (".chip 68k/68881\n\t"
 616                          "fsave %0\n\t"
 617                          ".chip 68k"
 618                          : : "m" (*fpstate) : "memory");
 619
 620        err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
 621        if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
 622                fpregset_t fpregs;
 623                if (!CPU_IS_060)
 624                        context_size = fpstate[1];
 625                fpu_version = fpstate[0];
 626                if (CPU_IS_020_OR_030 &&
 627                    regs->vector >= (VEC_FPBRUC * 4) &&
 628                    regs->vector <= (VEC_FPNAN * 4)) {
 629                        /* Clear pending exception in 68882 idle frame */
 630                        if (*(unsigned short *) fpstate == 0x1f38)
 631                                fpstate[0x38] |= 1 << 3;
 632                }
 633                __asm__ volatile (".chip 68k/68881\n\t"
 634                                  "fmovemx %%fp0-%%fp7,%0\n\t"
 635                                  "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
 636                                  ".chip 68k"
 637                                  : "=m" (*fpregs.f_fpregs),
 638                                    "=m" (*fpregs.f_fpcntl)
 639                                  : /* no inputs */
 640                                  : "memory");
 641                err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
 642                                    sizeof(fpregs));
 643        }
 644        if (context_size)
 645                err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
 646                                    context_size);
 647        return err;
 648}
 649
 650static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 651                             unsigned long mask)
 652{
 653        sc->sc_mask = mask;
 654        sc->sc_usp = rdusp();
 655        sc->sc_d0 = regs->d0;
 656        sc->sc_d1 = regs->d1;
 657        sc->sc_a0 = regs->a0;
 658        sc->sc_a1 = regs->a1;
 659        sc->sc_sr = regs->sr;
 660        sc->sc_pc = regs->pc;
 661        sc->sc_formatvec = regs->format << 12 | regs->vector;
 662        save_fpu_state(sc, regs);
 663}
 664
 665static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
 666{
 667        struct switch_stack *sw = (struct switch_stack *)regs - 1;
 668        greg_t __user *gregs = uc->uc_mcontext.gregs;
 669        int err = 0;
 670
 671        err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
 672        err |= __put_user(regs->d0, &gregs[0]);
 673        err |= __put_user(regs->d1, &gregs[1]);
 674        err |= __put_user(regs->d2, &gregs[2]);
 675        err |= __put_user(regs->d3, &gregs[3]);
 676        err |= __put_user(regs->d4, &gregs[4]);
 677        err |= __put_user(regs->d5, &gregs[5]);
 678        err |= __put_user(sw->d6, &gregs[6]);
 679        err |= __put_user(sw->d7, &gregs[7]);
 680        err |= __put_user(regs->a0, &gregs[8]);
 681        err |= __put_user(regs->a1, &gregs[9]);
 682        err |= __put_user(regs->a2, &gregs[10]);
 683        err |= __put_user(sw->a3, &gregs[11]);
 684        err |= __put_user(sw->a4, &gregs[12]);
 685        err |= __put_user(sw->a5, &gregs[13]);
 686        err |= __put_user(sw->a6, &gregs[14]);
 687        err |= __put_user(rdusp(), &gregs[15]);
 688        err |= __put_user(regs->pc, &gregs[16]);
 689        err |= __put_user(regs->sr, &gregs[17]);
 690        err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
 691        err |= rt_save_fpu_state(uc, regs);
 692        return err;
 693}
 694
 695static inline void push_cache (unsigned long vaddr)
 696{
 697        /*
 698         * Using the old cache_push_v() was really a big waste.
 699         *
 700         * What we are trying to do is to flush 8 bytes to ram.
 701         * Flushing 2 cache lines of 16 bytes is much cheaper than
 702         * flushing 1 or 2 pages, as previously done in
 703         * cache_push_v().
 704         *                                                     Jes
 705         */
 706        if (CPU_IS_040) {
 707                unsigned long temp;
 708
 709                __asm__ __volatile__ (".chip 68040\n\t"
 710                                      "nop\n\t"
 711                                      "ptestr (%1)\n\t"
 712                                      "movec %%mmusr,%0\n\t"
 713                                      ".chip 68k"
 714                                      : "=r" (temp)
 715                                      : "a" (vaddr));
 716
 717                temp &= PAGE_MASK;
 718                temp |= vaddr & ~PAGE_MASK;
 719
 720                __asm__ __volatile__ (".chip 68040\n\t"
 721                                      "nop\n\t"
 722                                      "cpushl %%bc,(%0)\n\t"
 723                                      ".chip 68k"
 724                                      : : "a" (temp));
 725        }
 726        else if (CPU_IS_060) {
 727                unsigned long temp;
 728                __asm__ __volatile__ (".chip 68060\n\t"
 729                                      "plpar (%0)\n\t"
 730                                      ".chip 68k"
 731                                      : "=a" (temp)
 732                                      : "0" (vaddr));
 733                __asm__ __volatile__ (".chip 68060\n\t"
 734                                      "cpushl %%bc,(%0)\n\t"
 735                                      ".chip 68k"
 736                                      : : "a" (temp));
 737        }
 738        else {
 739                /*
 740                 * 68030/68020 have no writeback cache;
 741                 * still need to clear icache.
 742                 * Note that vaddr is guaranteed to be long word aligned.
 743                 */
 744                unsigned long temp;
 745                asm volatile ("movec %%cacr,%0" : "=r" (temp));
 746                temp += 4;
 747                asm volatile ("movec %0,%%caar\n\t"
 748                              "movec %1,%%cacr"
 749                              : : "r" (vaddr), "r" (temp));
 750                asm volatile ("movec %0,%%caar\n\t"
 751                              "movec %1,%%cacr"
 752                              : : "r" (vaddr + 4), "r" (temp));
 753        }
 754}
 755
 756static inline void __user *
 757get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 758{
 759        unsigned long usp;
 760
 761        /* Default to using normal stack.  */
 762        usp = rdusp();
 763
 764        /* This is the X/Open sanctioned signal stack switching.  */
 765        if (ka->sa.sa_flags & SA_ONSTACK) {
 766                if (!sas_ss_flags(usp))
 767                        usp = current->sas_ss_sp + current->sas_ss_size;
 768        }
 769        return (void __user *)((usp - frame_size) & -8UL);
 770}
 771
 772static void setup_frame (int sig, struct k_sigaction *ka,
 773                         sigset_t *set, struct pt_regs *regs)
 774{
 775        struct sigframe __user *frame;
 776        int fsize = frame_extra_sizes[regs->format];
 777        struct sigcontext context;
 778        int err = 0;
 779
 780        if (fsize < 0) {
 781#ifdef DEBUG
 782                printk ("setup_frame: Unknown frame format %#x\n",
 783                        regs->format);
 784#endif
 785                goto give_sigsegv;
 786        }
 787
 788        frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
 789
 790        if (fsize) {
 791                err |= copy_to_user (frame + 1, regs + 1, fsize);
 792                regs->stkadj = fsize;
 793        }
 794
 795        err |= __put_user((current_thread_info()->exec_domain
 796                           && current_thread_info()->exec_domain->signal_invmap
 797                           && sig < 32
 798                           ? current_thread_info()->exec_domain->signal_invmap[sig]
 799                           : sig),
 800                          &frame->sig);
 801
 802        err |= __put_user(regs->vector, &frame->code);
 803        err |= __put_user(&frame->sc, &frame->psc);
 804
 805        if (_NSIG_WORDS > 1)
 806                err |= copy_to_user(frame->extramask, &set->sig[1],
 807                                    sizeof(frame->extramask));
 808
 809        setup_sigcontext(&context, regs, set->sig[0]);
 810        err |= copy_to_user (&frame->sc, &context, sizeof(context));
 811
 812        /* Set up to return from userspace.  */
 813        err |= __put_user(frame->retcode, &frame->pretcode);
 814        /* moveq #,d0; trap #0 */
 815        err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
 816                          (long __user *)(frame->retcode));
 817
 818        if (err)
 819                goto give_sigsegv;
 820
 821        push_cache ((unsigned long) &frame->retcode);
 822
 823        /* Set up registers for signal handler */
 824        wrusp ((unsigned long) frame);
 825        regs->pc = (unsigned long) ka->sa.sa_handler;
 826
 827adjust_stack:
 828        /* Prepare to skip over the extra stuff in the exception frame.  */
 829        if (regs->stkadj) {
 830                struct pt_regs *tregs =
 831                        (struct pt_regs *)((ulong)regs + regs->stkadj);
 832#ifdef DEBUG
 833                printk("Performing stackadjust=%04x\n", regs->stkadj);
 834#endif
 835                /* This must be copied with decreasing addresses to
 836                   handle overlaps.  */
 837                tregs->vector = 0;
 838                tregs->format = 0;
 839                tregs->pc = regs->pc;
 840                tregs->sr = regs->sr;
 841        }
 842        return;
 843
 844give_sigsegv:
 845        force_sigsegv(sig, current);
 846        goto adjust_stack;
 847}
 848
 849static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
 850                            sigset_t *set, struct pt_regs *regs)
 851{
 852        struct rt_sigframe __user *frame;
 853        int fsize = frame_extra_sizes[regs->format];
 854        int err = 0;
 855
 856        if (fsize < 0) {
 857#ifdef DEBUG
 858                printk ("setup_frame: Unknown frame format %#x\n",
 859                        regs->format);
 860#endif
 861                goto give_sigsegv;
 862        }
 863
 864        frame = get_sigframe(ka, regs, sizeof(*frame));
 865
 866        if (fsize) {
 867                err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
 868                regs->stkadj = fsize;
 869        }
 870
 871        err |= __put_user((current_thread_info()->exec_domain
 872                           && current_thread_info()->exec_domain->signal_invmap
 873                           && sig < 32
 874                           ? current_thread_info()->exec_domain->signal_invmap[sig]
 875                           : sig),
 876                          &frame->sig);
 877        err |= __put_user(&frame->info, &frame->pinfo);
 878        err |= __put_user(&frame->uc, &frame->puc);
 879        err |= copy_siginfo_to_user(&frame->info, info);
 880
 881        /* Create the ucontext.  */
 882        err |= __put_user(0, &frame->uc.uc_flags);
 883        err |= __put_user(NULL, &frame->uc.uc_link);
 884        err |= __put_user((void __user *)current->sas_ss_sp,
 885                          &frame->uc.uc_stack.ss_sp);
 886        err |= __put_user(sas_ss_flags(rdusp()),
 887                          &frame->uc.uc_stack.ss_flags);
 888        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 889        err |= rt_setup_ucontext(&frame->uc, regs);
 890        err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
 891
 892        /* Set up to return from userspace.  */
 893        err |= __put_user(frame->retcode, &frame->pretcode);
 894        /* moveq #,d0; notb d0; trap #0 */
 895        err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
 896                          (long __user *)(frame->retcode + 0));
 897        err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4));
 898
 899        if (err)
 900                goto give_sigsegv;
 901
 902        push_cache ((unsigned long) &frame->retcode);
 903
 904        /* Set up registers for signal handler */
 905        wrusp ((unsigned long) frame);
 906        regs->pc = (unsigned long) ka->sa.sa_handler;
 907
 908adjust_stack:
 909        /* Prepare to skip over the extra stuff in the exception frame.  */
 910        if (regs->stkadj) {
 911                struct pt_regs *tregs =
 912                        (struct pt_regs *)((ulong)regs + regs->stkadj);
 913#ifdef DEBUG
 914                printk("Performing stackadjust=%04x\n", regs->stkadj);
 915#endif
 916                /* This must be copied with decreasing addresses to
 917                   handle overlaps.  */
 918                tregs->vector = 0;
 919                tregs->format = 0;
 920                tregs->pc = regs->pc;
 921                tregs->sr = regs->sr;
 922        }
 923        return;
 924
 925give_sigsegv:
 926        force_sigsegv(sig, current);
 927        goto adjust_stack;
 928}
 929
 930static inline void
 931handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
 932{
 933        switch (regs->d0) {
 934        case -ERESTARTNOHAND:
 935                if (!has_handler)
 936                        goto do_restart;
 937                regs->d0 = -EINTR;
 938                break;
 939
 940        case -ERESTARTSYS:
 941                if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
 942                        regs->d0 = -EINTR;
 943                        break;
 944                }
 945        /* fallthrough */
 946        case -ERESTARTNOINTR:
 947        do_restart:
 948                regs->d0 = regs->orig_d0;
 949                regs->pc -= 2;
 950                break;
 951        }
 952}
 953
 954void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
 955{
 956        if (regs->orig_d0 < 0)
 957                return;
 958        switch (regs->d0) {
 959        case -ERESTARTNOHAND:
 960        case -ERESTARTSYS:
 961        case -ERESTARTNOINTR:
 962                regs->d0 = regs->orig_d0;
 963                regs->orig_d0 = -1;
 964                regs->pc -= 2;
 965                break;
 966        }
 967}
 968
 969/*
 970 * OK, we're invoking a handler
 971 */
 972static void
 973handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
 974              sigset_t *oldset, struct pt_regs *regs)
 975{
 976        /* are we from a system call? */
 977        if (regs->orig_d0 >= 0)
 978                /* If so, check system call restarting.. */
 979                handle_restart(regs, ka, 1);
 980
 981        /* set up the stack frame */
 982        if (ka->sa.sa_flags & SA_SIGINFO)
 983                setup_rt_frame(sig, ka, info, oldset, regs);
 984        else
 985                setup_frame(sig, ka, oldset, regs);
 986
 987        if (ka->sa.sa_flags & SA_ONESHOT)
 988                ka->sa.sa_handler = SIG_DFL;
 989
 990        sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 991        if (!(ka->sa.sa_flags & SA_NODEFER))
 992                sigaddset(&current->blocked,sig);
 993        recalc_sigpending();
 994}
 995
 996/*
 997 * Note that 'init' is a special process: it doesn't get signals it doesn't
 998 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 999 * mistake.
1000 */
1001asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
1002{
1003        siginfo_t info;
1004        struct k_sigaction ka;
1005        int signr;
1006
1007        current->thread.esp0 = (unsigned long) regs;
1008
1009        if (!oldset)
1010                oldset = &current->blocked;
1011
1012        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
1013        if (signr > 0) {
1014                /* Whee!  Actually deliver the signal.  */
1015                handle_signal(signr, &ka, &info, oldset, regs);
1016                return 1;
1017        }
1018
1019        /* Did we come from a system call? */
1020        if (regs->orig_d0 >= 0)
1021                /* Restart the system call - no handlers present */
1022                handle_restart(regs, NULL, 0);
1023
1024        return 0;
1025}
1026