linux/arch/mn10300/kernel/signal.c
<<
>>
Prefs
   1/* MN10300 Signal handling
   2 *
   3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11
  12#include <linux/sched.h>
  13#include <linux/mm.h>
  14#include <linux/smp.h>
  15#include <linux/kernel.h>
  16#include <linux/signal.h>
  17#include <linux/errno.h>
  18#include <linux/wait.h>
  19#include <linux/ptrace.h>
  20#include <linux/unistd.h>
  21#include <linux/stddef.h>
  22#include <linux/tty.h>
  23#include <linux/personality.h>
  24#include <linux/suspend.h>
  25#include <linux/tracehook.h>
  26#include <asm/cacheflush.h>
  27#include <asm/ucontext.h>
  28#include <asm/uaccess.h>
  29#include <asm/fpu.h>
  30#include "sigframe.h"
  31
  32#define DEBUG_SIG 0
  33
  34/*
  35 * do a signal return; undo the signal stack.
  36 */
  37static int restore_sigcontext(struct pt_regs *regs,
  38                              struct sigcontext __user *sc, long *_d0)
  39{
  40        unsigned int err = 0;
  41
  42        /* Always make any pending restarted system calls return -EINTR */
  43        current->restart_block.fn = do_no_restart_syscall;
  44
  45        if (is_using_fpu(current))
  46                fpu_kill_state(current);
  47
  48#define COPY(x) err |= __get_user(regs->x, &sc->x)
  49        COPY(d1); COPY(d2); COPY(d3);
  50        COPY(a0); COPY(a1); COPY(a2); COPY(a3);
  51        COPY(e0); COPY(e1); COPY(e2); COPY(e3);
  52        COPY(e4); COPY(e5); COPY(e6); COPY(e7);
  53        COPY(lar); COPY(lir);
  54        COPY(mdr); COPY(mdrq);
  55        COPY(mcvf); COPY(mcrl); COPY(mcrh);
  56        COPY(sp); COPY(pc);
  57#undef COPY
  58
  59        {
  60                unsigned int tmpflags;
  61#ifndef CONFIG_MN10300_USING_JTAG
  62#define USER_EPSW (EPSW_FLAG_Z | EPSW_FLAG_N | EPSW_FLAG_C | EPSW_FLAG_V | \
  63                   EPSW_T | EPSW_nAR)
  64#else
  65#define USER_EPSW (EPSW_FLAG_Z | EPSW_FLAG_N | EPSW_FLAG_C | EPSW_FLAG_V | \
  66                   EPSW_nAR)
  67#endif
  68                err |= __get_user(tmpflags, &sc->epsw);
  69                regs->epsw = (regs->epsw & ~USER_EPSW) |
  70                  (tmpflags & USER_EPSW);
  71                regs->orig_d0 = -1;             /* disable syscall checks */
  72        }
  73
  74        {
  75                struct fpucontext *buf;
  76                err |= __get_user(buf, &sc->fpucontext);
  77                if (buf) {
  78                        if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
  79                                goto badframe;
  80                        err |= fpu_restore_sigcontext(buf);
  81                }
  82        }
  83
  84        err |= __get_user(*_d0, &sc->d0);
  85        return err;
  86
  87badframe:
  88        return 1;
  89}
  90
  91/*
  92 * standard signal return syscall
  93 */
  94asmlinkage long sys_sigreturn(void)
  95{
  96        struct sigframe __user *frame;
  97        sigset_t set;
  98        long d0;
  99
 100        frame = (struct sigframe __user *) current_frame()->sp;
 101        if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 102                goto badframe;
 103        if (__get_user(set.sig[0], &frame->sc.oldmask))
 104                goto badframe;
 105
 106        if (_NSIG_WORDS > 1 &&
 107            __copy_from_user(&set.sig[1], &frame->extramask,
 108                             sizeof(frame->extramask)))
 109                goto badframe;
 110
 111        set_current_blocked(&set);
 112
 113        if (restore_sigcontext(current_frame(), &frame->sc, &d0))
 114                goto badframe;
 115
 116        return d0;
 117
 118badframe:
 119        force_sig(SIGSEGV, current);
 120        return 0;
 121}
 122
 123/*
 124 * realtime signal return syscall
 125 */
 126asmlinkage long sys_rt_sigreturn(void)
 127{
 128        struct rt_sigframe __user *frame;
 129        sigset_t set;
 130        long d0;
 131
 132        frame = (struct rt_sigframe __user *) current_frame()->sp;
 133        if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 134                goto badframe;
 135        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 136                goto badframe;
 137
 138        set_current_blocked(&set);
 139
 140        if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0))
 141                goto badframe;
 142
 143        if (restore_altstack(&frame->uc.uc_stack))
 144                goto badframe;
 145
 146        return d0;
 147
 148badframe:
 149        force_sig(SIGSEGV, current);
 150        return 0;
 151}
 152
 153/*
 154 * store the userspace context into a signal frame
 155 */
 156static int setup_sigcontext(struct sigcontext __user *sc,
 157                            struct fpucontext *fpuctx,
 158                            struct pt_regs *regs,
 159                            unsigned long mask)
 160{
 161        int tmp, err = 0;
 162
 163#define COPY(x) err |= __put_user(regs->x, &sc->x)
 164        COPY(d0); COPY(d1); COPY(d2); COPY(d3);
 165        COPY(a0); COPY(a1); COPY(a2); COPY(a3);
 166        COPY(e0); COPY(e1); COPY(e2); COPY(e3);
 167        COPY(e4); COPY(e5); COPY(e6); COPY(e7);
 168        COPY(lar); COPY(lir);
 169        COPY(mdr); COPY(mdrq);
 170        COPY(mcvf); COPY(mcrl); COPY(mcrh);
 171        COPY(sp); COPY(epsw); COPY(pc);
 172#undef COPY
 173
 174        tmp = fpu_setup_sigcontext(fpuctx);
 175        if (tmp < 0)
 176                err = 1;
 177        else
 178                err |= __put_user(tmp ? fpuctx : NULL, &sc->fpucontext);
 179
 180        /* non-iBCS2 extensions.. */
 181        err |= __put_user(mask, &sc->oldmask);
 182
 183        return err;
 184}
 185
 186/*
 187 * determine which stack to use..
 188 */
 189static inline void __user *get_sigframe(struct ksignal *ksig,
 190                                        struct pt_regs *regs,
 191                                        size_t frame_size)
 192{
 193        unsigned long sp = sigsp(regs->sp, ksig);
 194
 195        return (void __user *) ((sp - frame_size) & ~7UL);
 196}
 197
 198/*
 199 * set up a normal signal frame
 200 */
 201static int setup_frame(struct ksignal *ksig, sigset_t *set,
 202                       struct pt_regs *regs)
 203{
 204        struct sigframe __user *frame;
 205        int sig = ksig->sig;
 206
 207        frame = get_sigframe(ksig, regs, sizeof(*frame));
 208
 209        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 210                return -EFAULT;
 211
 212        if (__put_user(sig, &frame->sig) < 0 ||
 213            __put_user(&frame->sc, &frame->psc) < 0)
 214                return -EFAULT;
 215
 216        if (setup_sigcontext(&frame->sc, &frame->fpuctx, regs, set->sig[0]))
 217                return -EFAULT;
 218
 219        if (_NSIG_WORDS > 1) {
 220                if (__copy_to_user(frame->extramask, &set->sig[1],
 221                                   sizeof(frame->extramask)))
 222                        return -EFAULT;
 223        }
 224
 225        /* set up to return from userspace.  If provided, use a stub already in
 226         * userspace */
 227        if (ksig->ka.sa.sa_flags & SA_RESTORER) {
 228                if (__put_user(ksig->ka.sa.sa_restorer, &frame->pretcode))
 229                        return -EFAULT;
 230        } else {
 231                if (__put_user((void (*)(void))frame->retcode,
 232                               &frame->pretcode))
 233                        return -EFAULT;
 234                /* this is mov $,d0; syscall 0 */
 235                if (__put_user(0x2c, (char *)(frame->retcode + 0)) ||
 236                    __put_user(__NR_sigreturn, (char *)(frame->retcode + 1)) ||
 237                    __put_user(0x00, (char *)(frame->retcode + 2)) ||
 238                    __put_user(0xf0, (char *)(frame->retcode + 3)) ||
 239                    __put_user(0xe0, (char *)(frame->retcode + 4)))
 240                        return -EFAULT;
 241                flush_icache_range((unsigned long) frame->retcode,
 242                                   (unsigned long) frame->retcode + 5);
 243        }
 244
 245        /* set up registers for signal handler */
 246        regs->sp = (unsigned long) frame;
 247        regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
 248        regs->d0 = sig;
 249        regs->d1 = (unsigned long) &frame->sc;
 250
 251#if DEBUG_SIG
 252        printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
 253               sig, current->comm, current->pid, frame, regs->pc,
 254               frame->pretcode);
 255#endif
 256
 257        return 0;
 258}
 259
 260/*
 261 * set up a realtime signal frame
 262 */
 263static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 264                          struct pt_regs *regs)
 265{
 266        struct rt_sigframe __user *frame;
 267        int sig = ksig->sig;
 268
 269        frame = get_sigframe(ksig, regs, sizeof(*frame));
 270
 271        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 272                return -EFAULT;
 273
 274        if (__put_user(sig, &frame->sig) ||
 275            __put_user(&frame->info, &frame->pinfo) ||
 276            __put_user(&frame->uc, &frame->puc) ||
 277            copy_siginfo_to_user(&frame->info, &ksig->info))
 278                return -EFAULT;
 279
 280        /* create the ucontext.  */
 281        if (__put_user(0, &frame->uc.uc_flags) ||
 282            __put_user(0, &frame->uc.uc_link) ||
 283            __save_altstack(&frame->uc.uc_stack, regs->sp) ||
 284            setup_sigcontext(&frame->uc.uc_mcontext,
 285                             &frame->fpuctx, regs, set->sig[0]) ||
 286            __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)))
 287                return -EFAULT;
 288
 289        /* set up to return from userspace.  If provided, use a stub already in
 290         * userspace */
 291        if (ksig->ka.sa.sa_flags & SA_RESTORER) {
 292                if (__put_user(ksig->ka.sa.sa_restorer, &frame->pretcode))
 293                        return -EFAULT;
 294
 295        } else {
 296                if (__put_user((void(*)(void))frame->retcode,
 297                               &frame->pretcode) ||
 298                    /* This is mov $,d0; syscall 0 */
 299                    __put_user(0x2c, (char *)(frame->retcode + 0)) ||
 300                    __put_user(__NR_rt_sigreturn,
 301                               (char *)(frame->retcode + 1)) ||
 302                    __put_user(0x00, (char *)(frame->retcode + 2)) ||
 303                    __put_user(0xf0, (char *)(frame->retcode + 3)) ||
 304                    __put_user(0xe0, (char *)(frame->retcode + 4)))
 305                        return -EFAULT;
 306
 307                flush_icache_range((u_long) frame->retcode,
 308                                   (u_long) frame->retcode + 5);
 309        }
 310
 311        /* Set up registers for signal handler */
 312        regs->sp = (unsigned long) frame;
 313        regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
 314        regs->d0 = sig;
 315        regs->d1 = (long) &frame->info;
 316
 317#if DEBUG_SIG
 318        printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
 319               sig, current->comm, current->pid, frame, regs->pc,
 320               frame->pretcode);
 321#endif
 322
 323        return 0;
 324}
 325
 326static inline void stepback(struct pt_regs *regs)
 327{
 328        regs->pc -= 2;
 329        regs->orig_d0 = -1;
 330}
 331
 332/*
 333 * handle the actual delivery of a signal to userspace
 334 */
 335static int handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 336{
 337        sigset_t *oldset = sigmask_to_save();
 338        int ret;
 339
 340        /* Are we from a system call? */
 341        if (regs->orig_d0 >= 0) {
 342                /* If so, check system call restarting.. */
 343                switch (regs->d0) {
 344                case -ERESTART_RESTARTBLOCK:
 345                case -ERESTARTNOHAND:
 346                        regs->d0 = -EINTR;
 347                        break;
 348
 349                case -ERESTARTSYS:
 350                        if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
 351                                regs->d0 = -EINTR;
 352                                break;
 353                        }
 354
 355                        /* fallthrough */
 356                case -ERESTARTNOINTR:
 357                        regs->d0 = regs->orig_d0;
 358                        stepback(regs);
 359                }
 360        }
 361
 362        /* Set up the stack frame */
 363        if (ksig->ka.sa.sa_flags & SA_SIGINFO)
 364                ret = setup_rt_frame(ksig, oldset, regs);
 365        else
 366                ret = setup_frame(ksig, oldset, regs);
 367
 368        signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
 369        return 0;
 370}
 371
 372/*
 373 * handle a potential signal
 374 */
 375static void do_signal(struct pt_regs *regs)
 376{
 377        struct ksignal ksig;
 378
 379        if (get_signal(&ksig)) {
 380                handle_signal(&ksig, regs);
 381                return;
 382        }
 383
 384        /* did we come from a system call? */
 385        if (regs->orig_d0 >= 0) {
 386                /* restart the system call - no handlers present */
 387                switch (regs->d0) {
 388                case -ERESTARTNOHAND:
 389                case -ERESTARTSYS:
 390                case -ERESTARTNOINTR:
 391                        regs->d0 = regs->orig_d0;
 392                        stepback(regs);
 393                        break;
 394
 395                case -ERESTART_RESTARTBLOCK:
 396                        regs->d0 = __NR_restart_syscall;
 397                        stepback(regs);
 398                        break;
 399                }
 400        }
 401
 402        /* if there's no signal to deliver, we just put the saved sigmask
 403         * back */
 404        restore_saved_sigmask();
 405}
 406
 407/*
 408 * notification of userspace execution resumption
 409 * - triggered by current->work.notify_resume
 410 */
 411asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
 412{
 413        /* Pending single-step? */
 414        if (thread_info_flags & _TIF_SINGLESTEP) {
 415#ifndef CONFIG_MN10300_USING_JTAG
 416                regs->epsw |= EPSW_T;
 417                clear_thread_flag(TIF_SINGLESTEP);
 418#else
 419                BUG(); /* no h/w single-step if using JTAG unit */
 420#endif
 421        }
 422
 423        /* deal with pending signal delivery */
 424        if (thread_info_flags & _TIF_SIGPENDING)
 425                do_signal(regs);
 426
 427        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 428                clear_thread_flag(TIF_NOTIFY_RESUME);
 429                tracehook_notify_resume(current_frame());
 430        }
 431}
 432