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        /* Always make any pending restarted system calls return -EINTR */
 330        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 331
 332        /* get previous context */
 333        if (copy_from_user(&context, usc, sizeof(context)))
 334                goto badframe;
 335
 336        /* restore passed registers */
 337        regs->d1 = context.sc_d1;
 338        regs->a0 = context.sc_a0;
 339        regs->a1 = context.sc_a1;
 340        regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
 341        regs->pc = context.sc_pc;
 342        regs->orig_d0 = -1;             /* disable syscall checks */
 343        wrusp(context.sc_usp);
 344        formatvec = context.sc_formatvec;
 345        regs->format = formatvec >> 12;
 346        regs->vector = formatvec & 0xfff;
 347
 348        err = restore_fpu_state(&context);
 349
 350        fsize = frame_extra_sizes[regs->format];
 351        if (fsize < 0) {
 352                /*
 353                 * user process trying to return with weird frame format
 354                 */
 355#ifdef DEBUG
 356                printk("user process returning with weird frame format\n");
 357#endif
 358                goto badframe;
 359        }
 360
 361        /* OK.  Make room on the supervisor stack for the extra junk,
 362         * if necessary.
 363         */
 364
 365        if (fsize) {
 366                struct switch_stack *sw = (struct switch_stack *)regs - 1;
 367                regs->d0 = context.sc_d0;
 368#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
 369                __asm__ __volatile__
 370                        ("   movel %0,%/a0\n\t"
 371                         "   subl %1,%/a0\n\t"     /* make room on stack */
 372                         "   movel %/a0,%/sp\n\t"  /* set stack pointer */
 373                         /* move switch_stack and pt_regs */
 374                         "1: movel %0@+,%/a0@+\n\t"
 375                         "   dbra %2,1b\n\t"
 376                         "   lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
 377                         "   lsrl  #2,%1\n\t"
 378                         "   subql #1,%1\n\t"
 379                         "2: movesl %4@+,%2\n\t"
 380                         "3: movel %2,%/a0@+\n\t"
 381                         "   dbra %1,2b\n\t"
 382                         "   bral ret_from_signal\n"
 383                         "4:\n"
 384                         ".section __ex_table,\"a\"\n"
 385                         "   .align 4\n"
 386                         "   .long 2b,4b\n"
 387                         "   .long 3b,4b\n"
 388                         ".previous"
 389                         : /* no outputs, it doesn't ever return */
 390                         : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
 391                           "n" (frame_offset), "a" (fp)
 392                         : "a0");
 393#undef frame_offset
 394                /*
 395                 * If we ever get here an exception occurred while
 396                 * building the above stack-frame.
 397                 */
 398                goto badframe;
 399        }
 400
 401        *pd0 = context.sc_d0;
 402        return err;
 403
 404badframe:
 405        return 1;
 406}
 407
 408static inline int
 409rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
 410                    struct ucontext __user *uc, int *pd0)
 411{
 412        int fsize, temp;
 413        greg_t __user *gregs = uc->uc_mcontext.gregs;
 414        unsigned long usp;
 415        int err;
 416
 417        /* Always make any pending restarted system calls return -EINTR */
 418        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 419
 420        err = __get_user(temp, &uc->uc_mcontext.version);
 421        if (temp != MCONTEXT_VERSION)
 422                goto badframe;
 423        /* restore passed registers */
 424        err |= __get_user(regs->d0, &gregs[0]);
 425        err |= __get_user(regs->d1, &gregs[1]);
 426        err |= __get_user(regs->d2, &gregs[2]);
 427        err |= __get_user(regs->d3, &gregs[3]);
 428        err |= __get_user(regs->d4, &gregs[4]);
 429        err |= __get_user(regs->d5, &gregs[5]);
 430        err |= __get_user(sw->d6, &gregs[6]);
 431        err |= __get_user(sw->d7, &gregs[7]);
 432        err |= __get_user(regs->a0, &gregs[8]);
 433        err |= __get_user(regs->a1, &gregs[9]);
 434        err |= __get_user(regs->a2, &gregs[10]);
 435        err |= __get_user(sw->a3, &gregs[11]);
 436        err |= __get_user(sw->a4, &gregs[12]);
 437        err |= __get_user(sw->a5, &gregs[13]);
 438        err |= __get_user(sw->a6, &gregs[14]);
 439        err |= __get_user(usp, &gregs[15]);
 440        wrusp(usp);
 441        err |= __get_user(regs->pc, &gregs[16]);
 442        err |= __get_user(temp, &gregs[17]);
 443        regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
 444        regs->orig_d0 = -1;             /* disable syscall checks */
 445        err |= __get_user(temp, &uc->uc_formatvec);
 446        regs->format = temp >> 12;
 447        regs->vector = temp & 0xfff;
 448
 449        err |= rt_restore_fpu_state(uc);
 450
 451        if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
 452                goto badframe;
 453
 454        fsize = frame_extra_sizes[regs->format];
 455        if (fsize < 0) {
 456                /*
 457                 * user process trying to return with weird frame format
 458                 */
 459#ifdef DEBUG
 460                printk("user process returning with weird frame format\n");
 461#endif
 462                goto badframe;
 463        }
 464
 465        /* OK.  Make room on the supervisor stack for the extra junk,
 466         * if necessary.
 467         */
 468
 469        if (fsize) {
 470#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
 471                __asm__ __volatile__
 472                        ("   movel %0,%/a0\n\t"
 473                         "   subl %1,%/a0\n\t"     /* make room on stack */
 474                         "   movel %/a0,%/sp\n\t"  /* set stack pointer */
 475                         /* move switch_stack and pt_regs */
 476                         "1: movel %0@+,%/a0@+\n\t"
 477                         "   dbra %2,1b\n\t"
 478                         "   lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
 479                         "   lsrl  #2,%1\n\t"
 480                         "   subql #1,%1\n\t"
 481                         "2: movesl %4@+,%2\n\t"
 482                         "3: movel %2,%/a0@+\n\t"
 483                         "   dbra %1,2b\n\t"
 484                         "   bral ret_from_signal\n"
 485                         "4:\n"
 486                         ".section __ex_table,\"a\"\n"
 487                         "   .align 4\n"
 488                         "   .long 2b,4b\n"
 489                         "   .long 3b,4b\n"
 490                         ".previous"
 491                         : /* no outputs, it doesn't ever return */
 492                         : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
 493                           "n" (frame_offset), "a" (&uc->uc_extra)
 494                         : "a0");
 495#undef frame_offset
 496                /*
 497                 * If we ever get here an exception occurred while
 498                 * building the above stack-frame.
 499                 */
 500                goto badframe;
 501        }
 502
 503        *pd0 = regs->d0;
 504        return err;
 505
 506badframe:
 507        return 1;
 508}
 509
 510asmlinkage int do_sigreturn(unsigned long __unused)
 511{
 512        struct switch_stack *sw = (struct switch_stack *) &__unused;
 513        struct pt_regs *regs = (struct pt_regs *) (sw + 1);
 514        unsigned long usp = rdusp();
 515        struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
 516        sigset_t set;
 517        int d0;
 518
 519        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 520                goto badframe;
 521        if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
 522            (_NSIG_WORDS > 1 &&
 523             __copy_from_user(&set.sig[1], &frame->extramask,
 524                              sizeof(frame->extramask))))
 525                goto badframe;
 526
 527        sigdelsetmask(&set, ~_BLOCKABLE);
 528        current->blocked = set;
 529        recalc_sigpending();
 530
 531        if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
 532                goto badframe;
 533        return d0;
 534
 535badframe:
 536        force_sig(SIGSEGV, current);
 537        return 0;
 538}
 539
 540asmlinkage int do_rt_sigreturn(unsigned long __unused)
 541{
 542        struct switch_stack *sw = (struct switch_stack *) &__unused;
 543        struct pt_regs *regs = (struct pt_regs *) (sw + 1);
 544        unsigned long usp = rdusp();
 545        struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
 546        sigset_t set;
 547        int d0;
 548
 549        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 550                goto badframe;
 551        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 552                goto badframe;
 553
 554        sigdelsetmask(&set, ~_BLOCKABLE);
 555        current->blocked = set;
 556        recalc_sigpending();
 557
 558        if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
 559                goto badframe;
 560        return d0;
 561
 562badframe:
 563        force_sig(SIGSEGV, current);
 564        return 0;
 565}
 566
 567/*
 568 * Set up a signal frame.
 569 */
 570
 571static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
 572{
 573        if (FPU_IS_EMU) {
 574                /* save registers */
 575                memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
 576                memcpy(sc->sc_fpregs, current->thread.fp, 24);
 577                return;
 578        }
 579
 580        __asm__ volatile (".chip 68k/68881\n\t"
 581                          "fsave %0\n\t"
 582                          ".chip 68k"
 583                          : : "m" (*sc->sc_fpstate) : "memory");
 584
 585        if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
 586                fpu_version = sc->sc_fpstate[0];
 587                if (CPU_IS_020_OR_030 &&
 588                    regs->vector >= (VEC_FPBRUC * 4) &&
 589                    regs->vector <= (VEC_FPNAN * 4)) {
 590                        /* Clear pending exception in 68882 idle frame */
 591                        if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
 592                                sc->sc_fpstate[0x38] |= 1 << 3;
 593                }
 594                __asm__ volatile (".chip 68k/68881\n\t"
 595                                  "fmovemx %%fp0-%%fp1,%0\n\t"
 596                                  "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
 597                                  ".chip 68k"
 598                                  : "=m" (*sc->sc_fpregs),
 599                                    "=m" (*sc->sc_fpcntl)
 600                                  : /* no inputs */
 601                                  : "memory");
 602        }
 603}
 604
 605static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
 606{
 607        unsigned char fpstate[FPCONTEXT_SIZE];
 608        int context_size = CPU_IS_060 ? 8 : 0;
 609        int err = 0;
 610
 611        if (FPU_IS_EMU) {
 612                /* save fpu control register */
 613                err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl,
 614                                current->thread.fpcntl, 12);
 615                /* save all other fpu register */
 616                err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
 617                                current->thread.fp, 96);
 618                return err;
 619        }
 620
 621        __asm__ volatile (".chip 68k/68881\n\t"
 622                          "fsave %0\n\t"
 623                          ".chip 68k"
 624                          : : "m" (*fpstate) : "memory");
 625
 626        err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
 627        if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
 628                fpregset_t fpregs;
 629                if (!CPU_IS_060)
 630                        context_size = fpstate[1];
 631                fpu_version = fpstate[0];
 632                if (CPU_IS_020_OR_030 &&
 633                    regs->vector >= (VEC_FPBRUC * 4) &&
 634                    regs->vector <= (VEC_FPNAN * 4)) {
 635                        /* Clear pending exception in 68882 idle frame */
 636                        if (*(unsigned short *) fpstate == 0x1f38)
 637                                fpstate[0x38] |= 1 << 3;
 638                }
 639                __asm__ volatile (".chip 68k/68881\n\t"
 640                                  "fmovemx %%fp0-%%fp7,%0\n\t"
 641                                  "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
 642                                  ".chip 68k"
 643                                  : "=m" (*fpregs.f_fpregs),
 644                                    "=m" (*fpregs.f_fpcntl)
 645                                  : /* no inputs */
 646                                  : "memory");
 647                err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
 648                                    sizeof(fpregs));
 649        }
 650        if (context_size)
 651                err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
 652                                    context_size);
 653        return err;
 654}
 655
 656static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 657                             unsigned long mask)
 658{
 659        sc->sc_mask = mask;
 660        sc->sc_usp = rdusp();
 661        sc->sc_d0 = regs->d0;
 662        sc->sc_d1 = regs->d1;
 663        sc->sc_a0 = regs->a0;
 664        sc->sc_a1 = regs->a1;
 665        sc->sc_sr = regs->sr;
 666        sc->sc_pc = regs->pc;
 667        sc->sc_formatvec = regs->format << 12 | regs->vector;
 668        save_fpu_state(sc, regs);
 669}
 670
 671static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
 672{
 673        struct switch_stack *sw = (struct switch_stack *)regs - 1;
 674        greg_t __user *gregs = uc->uc_mcontext.gregs;
 675        int err = 0;
 676
 677        err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
 678        err |= __put_user(regs->d0, &gregs[0]);
 679        err |= __put_user(regs->d1, &gregs[1]);
 680        err |= __put_user(regs->d2, &gregs[2]);
 681        err |= __put_user(regs->d3, &gregs[3]);
 682        err |= __put_user(regs->d4, &gregs[4]);
 683        err |= __put_user(regs->d5, &gregs[5]);
 684        err |= __put_user(sw->d6, &gregs[6]);
 685        err |= __put_user(sw->d7, &gregs[7]);
 686        err |= __put_user(regs->a0, &gregs[8]);
 687        err |= __put_user(regs->a1, &gregs[9]);
 688        err |= __put_user(regs->a2, &gregs[10]);
 689        err |= __put_user(sw->a3, &gregs[11]);
 690        err |= __put_user(sw->a4, &gregs[12]);
 691        err |= __put_user(sw->a5, &gregs[13]);
 692        err |= __put_user(sw->a6, &gregs[14]);
 693        err |= __put_user(rdusp(), &gregs[15]);
 694        err |= __put_user(regs->pc, &gregs[16]);
 695        err |= __put_user(regs->sr, &gregs[17]);
 696        err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
 697        err |= rt_save_fpu_state(uc, regs);
 698        return err;
 699}
 700
 701static inline void push_cache (unsigned long vaddr)
 702{
 703        /*
 704         * Using the old cache_push_v() was really a big waste.
 705         *
 706         * What we are trying to do is to flush 8 bytes to ram.
 707         * Flushing 2 cache lines of 16 bytes is much cheaper than
 708         * flushing 1 or 2 pages, as previously done in
 709         * cache_push_v().
 710         *                                                     Jes
 711         */
 712        if (CPU_IS_040) {
 713                unsigned long temp;
 714
 715                __asm__ __volatile__ (".chip 68040\n\t"
 716                                      "nop\n\t"
 717                                      "ptestr (%1)\n\t"
 718                                      "movec %%mmusr,%0\n\t"
 719                                      ".chip 68k"
 720                                      : "=r" (temp)
 721                                      : "a" (vaddr));
 722
 723                temp &= PAGE_MASK;
 724                temp |= vaddr & ~PAGE_MASK;
 725
 726                __asm__ __volatile__ (".chip 68040\n\t"
 727                                      "nop\n\t"
 728                                      "cpushl %%bc,(%0)\n\t"
 729                                      ".chip 68k"
 730                                      : : "a" (temp));
 731        }
 732        else if (CPU_IS_060) {
 733                unsigned long temp;
 734                __asm__ __volatile__ (".chip 68060\n\t"
 735                                      "plpar (%0)\n\t"
 736                                      ".chip 68k"
 737                                      : "=a" (temp)
 738                                      : "0" (vaddr));
 739                __asm__ __volatile__ (".chip 68060\n\t"
 740                                      "cpushl %%bc,(%0)\n\t"
 741                                      ".chip 68k"
 742                                      : : "a" (temp));
 743        }
 744        else {
 745                /*
 746                 * 68030/68020 have no writeback cache;
 747                 * still need to clear icache.
 748                 * Note that vaddr is guaranteed to be long word aligned.
 749                 */
 750                unsigned long temp;
 751                asm volatile ("movec %%cacr,%0" : "=r" (temp));
 752                temp += 4;
 753                asm volatile ("movec %0,%%caar\n\t"
 754                              "movec %1,%%cacr"
 755                              : : "r" (vaddr), "r" (temp));
 756                asm volatile ("movec %0,%%caar\n\t"
 757                              "movec %1,%%cacr"
 758                              : : "r" (vaddr + 4), "r" (temp));
 759        }
 760}
 761
 762static inline void __user *
 763get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 764{
 765        unsigned long usp;
 766
 767        /* Default to using normal stack.  */
 768        usp = rdusp();
 769
 770        /* This is the X/Open sanctioned signal stack switching.  */
 771        if (ka->sa.sa_flags & SA_ONSTACK) {
 772                if (!sas_ss_flags(usp))
 773                        usp = current->sas_ss_sp + current->sas_ss_size;
 774        }
 775        return (void __user *)((usp - frame_size) & -8UL);
 776}
 777
 778static void setup_frame (int sig, struct k_sigaction *ka,
 779                         sigset_t *set, struct pt_regs *regs)
 780{
 781        struct sigframe __user *frame;
 782        int fsize = frame_extra_sizes[regs->format];
 783        struct sigcontext context;
 784        int err = 0;
 785
 786        if (fsize < 0) {
 787#ifdef DEBUG
 788                printk ("setup_frame: Unknown frame format %#x\n",
 789                        regs->format);
 790#endif
 791                goto give_sigsegv;
 792        }
 793
 794        frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
 795
 796        if (fsize) {
 797                err |= copy_to_user (frame + 1, regs + 1, fsize);
 798                regs->stkadj = fsize;
 799        }
 800
 801        err |= __put_user((current_thread_info()->exec_domain
 802                           && current_thread_info()->exec_domain->signal_invmap
 803                           && sig < 32
 804                           ? current_thread_info()->exec_domain->signal_invmap[sig]
 805                           : sig),
 806                          &frame->sig);
 807
 808        err |= __put_user(regs->vector, &frame->code);
 809        err |= __put_user(&frame->sc, &frame->psc);
 810
 811        if (_NSIG_WORDS > 1)
 812                err |= copy_to_user(frame->extramask, &set->sig[1],
 813                                    sizeof(frame->extramask));
 814
 815        setup_sigcontext(&context, regs, set->sig[0]);
 816        err |= copy_to_user (&frame->sc, &context, sizeof(context));
 817
 818        /* Set up to return from userspace.  */
 819        err |= __put_user(frame->retcode, &frame->pretcode);
 820        /* moveq #,d0; trap #0 */
 821        err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
 822                          (long __user *)(frame->retcode));
 823
 824        if (err)
 825                goto give_sigsegv;
 826
 827        push_cache ((unsigned long) &frame->retcode);
 828
 829        /* Set up registers for signal handler */
 830        wrusp ((unsigned long) frame);
 831        regs->pc = (unsigned long) ka->sa.sa_handler;
 832
 833adjust_stack:
 834        /* Prepare to skip over the extra stuff in the exception frame.  */
 835        if (regs->stkadj) {
 836                struct pt_regs *tregs =
 837                        (struct pt_regs *)((ulong)regs + regs->stkadj);
 838#ifdef DEBUG
 839                printk("Performing stackadjust=%04x\n", regs->stkadj);
 840#endif
 841                /* This must be copied with decreasing addresses to
 842                   handle overlaps.  */
 843                tregs->vector = 0;
 844                tregs->format = 0;
 845                tregs->pc = regs->pc;
 846                tregs->sr = regs->sr;
 847        }
 848        return;
 849
 850give_sigsegv:
 851        force_sigsegv(sig, current);
 852        goto adjust_stack;
 853}
 854
 855static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
 856                            sigset_t *set, struct pt_regs *regs)
 857{
 858        struct rt_sigframe __user *frame;
 859        int fsize = frame_extra_sizes[regs->format];
 860        int err = 0;
 861
 862        if (fsize < 0) {
 863#ifdef DEBUG
 864                printk ("setup_frame: Unknown frame format %#x\n",
 865                        regs->format);
 866#endif
 867                goto give_sigsegv;
 868        }
 869
 870        frame = get_sigframe(ka, regs, sizeof(*frame));
 871
 872        if (fsize) {
 873                err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
 874                regs->stkadj = fsize;
 875        }
 876
 877        err |= __put_user((current_thread_info()->exec_domain
 878                           && current_thread_info()->exec_domain->signal_invmap
 879                           && sig < 32
 880                           ? current_thread_info()->exec_domain->signal_invmap[sig]
 881                           : sig),
 882                          &frame->sig);
 883        err |= __put_user(&frame->info, &frame->pinfo);
 884        err |= __put_user(&frame->uc, &frame->puc);
 885        err |= copy_siginfo_to_user(&frame->info, info);
 886
 887        /* Create the ucontext.  */
 888        err |= __put_user(0, &frame->uc.uc_flags);
 889        err |= __put_user(NULL, &frame->uc.uc_link);
 890        err |= __put_user((void __user *)current->sas_ss_sp,
 891                          &frame->uc.uc_stack.ss_sp);
 892        err |= __put_user(sas_ss_flags(rdusp()),
 893                          &frame->uc.uc_stack.ss_flags);
 894        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 895        err |= rt_setup_ucontext(&frame->uc, regs);
 896        err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
 897
 898        /* Set up to return from userspace.  */
 899        err |= __put_user(frame->retcode, &frame->pretcode);
 900        /* moveq #,d0; notb d0; trap #0 */
 901        err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
 902                          (long __user *)(frame->retcode + 0));
 903        err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4));
 904
 905        if (err)
 906                goto give_sigsegv;
 907
 908        push_cache ((unsigned long) &frame->retcode);
 909
 910        /* Set up registers for signal handler */
 911        wrusp ((unsigned long) frame);
 912        regs->pc = (unsigned long) ka->sa.sa_handler;
 913
 914adjust_stack:
 915        /* Prepare to skip over the extra stuff in the exception frame.  */
 916        if (regs->stkadj) {
 917                struct pt_regs *tregs =
 918                        (struct pt_regs *)((ulong)regs + regs->stkadj);
 919#ifdef DEBUG
 920                printk("Performing stackadjust=%04x\n", regs->stkadj);
 921#endif
 922                /* This must be copied with decreasing addresses to
 923                   handle overlaps.  */
 924                tregs->vector = 0;
 925                tregs->format = 0;
 926                tregs->pc = regs->pc;
 927                tregs->sr = regs->sr;
 928        }
 929        return;
 930
 931give_sigsegv:
 932        force_sigsegv(sig, current);
 933        goto adjust_stack;
 934}
 935
 936static inline void
 937handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
 938{
 939        switch (regs->d0) {
 940        case -ERESTARTNOHAND:
 941                if (!has_handler)
 942                        goto do_restart;
 943                regs->d0 = -EINTR;
 944                break;
 945
 946        case -ERESTART_RESTARTBLOCK:
 947                if (!has_handler) {
 948                        regs->d0 = __NR_restart_syscall;
 949                        regs->pc -= 2;
 950                        break;
 951                }
 952                regs->d0 = -EINTR;
 953                break;
 954
 955        case -ERESTARTSYS:
 956                if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
 957                        regs->d0 = -EINTR;
 958                        break;
 959                }
 960        /* fallthrough */
 961        case -ERESTARTNOINTR:
 962        do_restart:
 963                regs->d0 = regs->orig_d0;
 964                regs->pc -= 2;
 965                break;
 966        }
 967}
 968
 969void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
 970{
 971        if (regs->orig_d0 < 0)
 972                return;
 973        switch (regs->d0) {
 974        case -ERESTARTNOHAND:
 975        case -ERESTARTSYS:
 976        case -ERESTARTNOINTR:
 977                regs->d0 = regs->orig_d0;
 978                regs->orig_d0 = -1;
 979                regs->pc -= 2;
 980                break;
 981        }
 982}
 983
 984/*
 985 * OK, we're invoking a handler
 986 */
 987static void
 988handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
 989              sigset_t *oldset, struct pt_regs *regs)
 990{
 991        /* are we from a system call? */
 992        if (regs->orig_d0 >= 0)
 993                /* If so, check system call restarting.. */
 994                handle_restart(regs, ka, 1);
 995
 996        /* set up the stack frame */
 997        if (ka->sa.sa_flags & SA_SIGINFO)
 998                setup_rt_frame(sig, ka, info, oldset, regs);
 999        else
1000                setup_frame(sig, ka, oldset, regs);
1001
1002        if (ka->sa.sa_flags & SA_ONESHOT)
1003                ka->sa.sa_handler = SIG_DFL;
1004
1005        sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
1006        if (!(ka->sa.sa_flags & SA_NODEFER))
1007                sigaddset(&current->blocked,sig);
1008        recalc_sigpending();
1009}
1010
1011/*
1012 * Note that 'init' is a special process: it doesn't get signals it doesn't
1013 * want to handle. Thus you cannot kill init even with a SIGKILL even by
1014 * mistake.
1015 */
1016asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
1017{
1018        siginfo_t info;
1019        struct k_sigaction ka;
1020        int signr;
1021
1022        current->thread.esp0 = (unsigned long) regs;
1023
1024        if (!oldset)
1025                oldset = &current->blocked;
1026
1027        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
1028        if (signr > 0) {
1029                /* Whee!  Actually deliver the signal.  */
1030                handle_signal(signr, &ka, &info, oldset, regs);
1031                return 1;
1032        }
1033
1034        /* Did we come from a system call? */
1035        if (regs->orig_d0 >= 0)
1036                /* Restart the system call - no handlers present */
1037                handle_restart(regs, NULL, 0);
1038
1039        return 0;
1040}
1041