linux/arch/microblaze/kernel/signal.c
<<
>>
Prefs
   1/*
   2 * Signal handling
   3 *
   4 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
   5 * Copyright (C) 2008-2009 PetaLogix
   6 * Copyright (C) 2003,2004 John Williams <jwilliams@itee.uq.edu.au>
   7 * Copyright (C) 2001 NEC Corporation
   8 * Copyright (C) 2001 Miles Bader <miles@gnu.org>
   9 * Copyright (C) 1999,2000 Niibe Yutaka & Kaz Kojima
  10 * Copyright (C) 1991,1992 Linus Torvalds
  11 *
  12 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
  13 *
  14 * This file was was derived from the sh version, arch/sh/kernel/signal.c
  15 *
  16 * This file is subject to the terms and conditions of the GNU General
  17 * Public License. See the file COPYING in the main directory of this
  18 * archive for more details.
  19 */
  20
  21#include <linux/sched.h>
  22#include <linux/mm.h>
  23#include <linux/smp.h>
  24#include <linux/smp_lock.h>
  25#include <linux/kernel.h>
  26#include <linux/signal.h>
  27#include <linux/errno.h>
  28#include <linux/wait.h>
  29#include <linux/ptrace.h>
  30#include <linux/unistd.h>
  31#include <linux/stddef.h>
  32#include <linux/personality.h>
  33#include <linux/percpu.h>
  34#include <linux/linkage.h>
  35#include <asm/entry.h>
  36#include <asm/ucontext.h>
  37#include <linux/uaccess.h>
  38#include <asm/pgtable.h>
  39#include <asm/pgalloc.h>
  40#include <linux/syscalls.h>
  41#include <asm/cacheflush.h>
  42#include <asm/syscalls.h>
  43
  44#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
  45
  46asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
  47
  48/*
  49 * Atomically swap in the new signal mask, and wait for a signal.
  50 */
  51asmlinkage int
  52sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs)
  53{
  54        sigset_t saveset;
  55
  56        mask &= _BLOCKABLE;
  57        spin_lock_irq(&current->sighand->siglock);
  58        saveset = current->blocked;
  59        siginitset(&current->blocked, mask);
  60        recalc_sigpending();
  61        spin_unlock_irq(&current->sighand->siglock);
  62
  63        regs->r3 = -EINTR;
  64        while (1) {
  65                current->state = TASK_INTERRUPTIBLE;
  66                schedule();
  67                if (do_signal(regs, &saveset, 1))
  68                        return -EINTR;
  69        }
  70}
  71
  72asmlinkage int
  73sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
  74                struct pt_regs *regs)
  75{
  76        sigset_t saveset, newset;
  77
  78        /* XXX: Don't preclude handling different sized sigset_t's. */
  79        if (sigsetsize != sizeof(sigset_t))
  80                return -EINVAL;
  81
  82        if (copy_from_user(&newset, unewset, sizeof(newset)))
  83                return -EFAULT;
  84        sigdelsetmask(&newset, ~_BLOCKABLE);
  85        spin_lock_irq(&current->sighand->siglock);
  86        saveset = current->blocked;
  87        current->blocked = newset;
  88        recalc_sigpending();
  89        spin_unlock_irq(&current->sighand->siglock);
  90
  91        regs->r3 = -EINTR;
  92        while (1) {
  93                current->state = TASK_INTERRUPTIBLE;
  94                schedule();
  95                if (do_signal(regs, &saveset, 1))
  96                        return -EINTR;
  97        }
  98}
  99
 100asmlinkage int
 101sys_sigaction(int sig, const struct old_sigaction *act,
 102                struct old_sigaction *oact)
 103{
 104        struct k_sigaction new_ka, old_ka;
 105        int ret;
 106
 107        if (act) {
 108                old_sigset_t mask;
 109                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 110                        __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 111                        __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 112                        return -EFAULT;
 113                __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 114                __get_user(mask, &act->sa_mask);
 115                siginitset(&new_ka.sa.sa_mask, mask);
 116        }
 117
 118        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 119
 120        if (!ret && oact) {
 121                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 122                        __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 123                        __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 124                        return -EFAULT;
 125                __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 126                __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 127        }
 128
 129        return ret;
 130}
 131
 132asmlinkage int
 133sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
 134                struct pt_regs *regs)
 135{
 136        return do_sigaltstack(uss, uoss, regs->r1);
 137}
 138
 139/*
 140 * Do a signal return; undo the signal stack.
 141 */
 142
 143struct sigframe {
 144        struct sigcontext sc;
 145        unsigned long extramask[_NSIG_WORDS-1];
 146        unsigned long tramp[2]; /* signal trampoline */
 147};
 148
 149struct rt_sigframe {
 150        struct siginfo info;
 151        struct ucontext uc;
 152        unsigned long tramp[2]; /* signal trampoline */
 153};
 154
 155static int
 156restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p)
 157{
 158        unsigned int err = 0;
 159
 160#define COPY(x)         {err |= __get_user(regs->x, &sc->regs.x); }
 161        COPY(r0);
 162        COPY(r1);
 163        COPY(r2);       COPY(r3);       COPY(r4);       COPY(r5);
 164        COPY(r6);       COPY(r7);       COPY(r8);       COPY(r9);
 165        COPY(r10);      COPY(r11);      COPY(r12);      COPY(r13);
 166        COPY(r14);      COPY(r15);      COPY(r16);      COPY(r17);
 167        COPY(r18);      COPY(r19);      COPY(r20);      COPY(r21);
 168        COPY(r22);      COPY(r23);      COPY(r24);      COPY(r25);
 169        COPY(r26);      COPY(r27);      COPY(r28);      COPY(r29);
 170        COPY(r30);      COPY(r31);
 171        COPY(pc);       COPY(ear);      COPY(esr);      COPY(fsr);
 172#undef COPY
 173
 174        *rval_p = regs->r3;
 175
 176        return err;
 177}
 178
 179asmlinkage int sys_sigreturn(struct pt_regs *regs)
 180{
 181        struct sigframe *frame =
 182                        (struct sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE);
 183
 184        sigset_t set;
 185        int rval;
 186
 187        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 188                goto badframe;
 189
 190        if (__get_user(set.sig[0], &frame->sc.oldmask)
 191                || (_NSIG_WORDS > 1
 192                && __copy_from_user(&set.sig[1], &frame->extramask,
 193                                        sizeof(frame->extramask))))
 194                goto badframe;
 195
 196        sigdelsetmask(&set, ~_BLOCKABLE);
 197
 198        spin_lock_irq(&current->sighand->siglock);
 199        current->blocked = set;
 200        recalc_sigpending();
 201        spin_unlock_irq(&current->sighand->siglock);
 202
 203        if (restore_sigcontext(regs, &frame->sc, &rval))
 204                goto badframe;
 205        return rval;
 206
 207badframe:
 208        force_sig(SIGSEGV, current);
 209        return 0;
 210}
 211
 212asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
 213{
 214        struct rt_sigframe *frame =
 215                        (struct rt_sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE);
 216
 217        sigset_t set;
 218        stack_t st;
 219        int rval;
 220
 221        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 222                goto badframe;
 223
 224        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
 225                goto badframe;
 226
 227        sigdelsetmask(&set, ~_BLOCKABLE);
 228        spin_lock_irq(&current->sighand->siglock);
 229        current->blocked = set;
 230        recalc_sigpending();
 231        spin_unlock_irq(&current->sighand->siglock);
 232
 233        if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
 234                goto badframe;
 235
 236        if (__copy_from_user((void *)&st, &frame->uc.uc_stack, sizeof(st)))
 237                goto badframe;
 238        /* It is more difficult to avoid calling this function than to
 239         call it and ignore errors. */
 240        do_sigaltstack(&st, NULL, regs->r1);
 241
 242        return rval;
 243
 244badframe:
 245        force_sig(SIGSEGV, current);
 246        return 0;
 247}
 248
 249/*
 250 * Set up a signal frame.
 251 */
 252
 253static int
 254setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
 255                unsigned long mask)
 256{
 257        int err = 0;
 258
 259#define COPY(x)         {err |= __put_user(regs->x, &sc->regs.x); }
 260        COPY(r0);
 261        COPY(r1);
 262        COPY(r2);       COPY(r3);       COPY(r4);       COPY(r5);
 263        COPY(r6);       COPY(r7);       COPY(r8);       COPY(r9);
 264        COPY(r10);      COPY(r11);      COPY(r12);      COPY(r13);
 265        COPY(r14);      COPY(r15);      COPY(r16);      COPY(r17);
 266        COPY(r18);      COPY(r19);      COPY(r20);      COPY(r21);
 267        COPY(r22);      COPY(r23);      COPY(r24);      COPY(r25);
 268        COPY(r26);      COPY(r27);      COPY(r28);      COPY(r29);
 269        COPY(r30);      COPY(r31);
 270        COPY(pc);       COPY(ear);      COPY(esr);      COPY(fsr);
 271#undef COPY
 272
 273        err |= __put_user(mask, &sc->oldmask);
 274
 275        return err;
 276}
 277
 278/*
 279 * Determine which stack to use..
 280 */
 281static inline void *
 282get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 283{
 284        /* Default to using normal stack */
 285        unsigned long sp = regs->r1;
 286
 287        if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
 288                sp = current->sas_ss_sp + current->sas_ss_size;
 289
 290        return (void *)((sp - frame_size) & -8UL);
 291}
 292
 293static void setup_frame(int sig, struct k_sigaction *ka,
 294                        sigset_t *set, struct pt_regs *regs)
 295{
 296        struct sigframe *frame;
 297        int err = 0;
 298        int signal;
 299
 300        frame = get_sigframe(ka, regs, sizeof(*frame));
 301
 302        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 303                goto give_sigsegv;
 304
 305        signal = current_thread_info()->exec_domain
 306                && current_thread_info()->exec_domain->signal_invmap
 307                && sig < 32
 308                ? current_thread_info()->exec_domain->signal_invmap[sig]
 309                : sig;
 310
 311        err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
 312
 313        if (_NSIG_WORDS > 1) {
 314                err |= __copy_to_user(frame->extramask, &set->sig[1],
 315                                        sizeof(frame->extramask));
 316        }
 317
 318        /* Set up to return from userspace. If provided, use a stub
 319         already in userspace. */
 320        /* minus 8 is offset to cater for "rtsd r15,8" offset */
 321        if (ka->sa.sa_flags & SA_RESTORER) {
 322                regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8;
 323        } else {
 324                /* Note, these encodings are _big endian_! */
 325
 326                /* addi r12, r0, __NR_sigreturn */
 327                err |= __put_user(0x31800000 | __NR_sigreturn ,
 328                                frame->tramp + 0);
 329                /* brki r14, 0x8 */
 330                err |= __put_user(0xb9cc0008, frame->tramp + 1);
 331
 332                /* Return from sighandler will jump to the tramp.
 333                 Negative 8 offset because return is rtsd r15, 8 */
 334                regs->r15 = ((unsigned long)frame->tramp)-8;
 335
 336                __invalidate_cache_sigtramp((unsigned long)frame->tramp);
 337        }
 338
 339        if (err)
 340                goto give_sigsegv;
 341
 342        /* Set up registers for signal handler */
 343        regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE;
 344
 345        /* Signal handler args: */
 346        regs->r5 = signal; /* Arg 0: signum */
 347        regs->r6 = (unsigned long) &frame->sc; /* arg 1: sigcontext */
 348
 349        /* Offset of 4 to handle microblaze rtid r14, 0 */
 350        regs->pc = (unsigned long)ka->sa.sa_handler;
 351
 352        set_fs(USER_DS);
 353
 354#ifdef DEBUG_SIG
 355        printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
 356                current->comm, current->pid, frame, regs->pc);
 357#endif
 358
 359        return;
 360
 361give_sigsegv:
 362        if (sig == SIGSEGV)
 363                ka->sa.sa_handler = SIG_DFL;
 364        force_sig(SIGSEGV, current);
 365}
 366
 367static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 368                        sigset_t *set, struct pt_regs *regs)
 369{
 370        struct rt_sigframe *frame;
 371        int err = 0;
 372        int signal;
 373
 374        frame = get_sigframe(ka, regs, sizeof(*frame));
 375
 376        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 377                goto give_sigsegv;
 378
 379        signal = current_thread_info()->exec_domain
 380                && current_thread_info()->exec_domain->signal_invmap
 381                && sig < 32
 382                ? current_thread_info()->exec_domain->signal_invmap[sig]
 383                : sig;
 384
 385        err |= copy_siginfo_to_user(&frame->info, info);
 386
 387        /* Create the ucontext. */
 388        err |= __put_user(0, &frame->uc.uc_flags);
 389        err |= __put_user(0, &frame->uc.uc_link);
 390        err |= __put_user((void *)current->sas_ss_sp,
 391                        &frame->uc.uc_stack.ss_sp);
 392        err |= __put_user(sas_ss_flags(regs->r1),
 393                        &frame->uc.uc_stack.ss_flags);
 394        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 395        err |= setup_sigcontext(&frame->uc.uc_mcontext,
 396                        regs, set->sig[0]);
 397        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 398
 399        /* Set up to return from userspace. If provided, use a stub
 400         already in userspace. */
 401        /* minus 8 is offset to cater for "rtsd r15,8" */
 402        if (ka->sa.sa_flags & SA_RESTORER) {
 403                regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8;
 404        } else {
 405                /* addi r12, r0, __NR_sigreturn */
 406                err |= __put_user(0x31800000 | __NR_rt_sigreturn ,
 407                                frame->tramp + 0);
 408                /* brki r14, 0x8 */
 409                err |= __put_user(0xb9cc0008, frame->tramp + 1);
 410
 411                /* Return from sighandler will jump to the tramp.
 412                 Negative 8 offset because return is rtsd r15, 8 */
 413                regs->r15 = ((unsigned long)frame->tramp)-8;
 414
 415                __invalidate_cache_sigtramp((unsigned long)frame->tramp);
 416        }
 417
 418        if (err)
 419                goto give_sigsegv;
 420
 421        /* Set up registers for signal handler */
 422        regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE;
 423
 424        /* Signal handler args: */
 425        regs->r5 = signal; /* arg 0: signum */
 426        regs->r6 = (unsigned long) &frame->info; /* arg 1: siginfo */
 427        regs->r7 = (unsigned long) &frame->uc; /* arg2: ucontext */
 428        /* Offset to handle microblaze rtid r14, 0 */
 429        regs->pc = (unsigned long)ka->sa.sa_handler;
 430
 431        set_fs(USER_DS);
 432
 433#ifdef DEBUG_SIG
 434        printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
 435                current->comm, current->pid, frame, regs->pc);
 436#endif
 437
 438        return;
 439
 440give_sigsegv:
 441        if (sig == SIGSEGV)
 442                ka->sa.sa_handler = SIG_DFL;
 443        force_sig(SIGSEGV, current);
 444}
 445
 446/* Handle restarting system calls */
 447static inline void
 448handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
 449{
 450        switch (regs->r3) {
 451        case -ERESTART_RESTARTBLOCK:
 452        case -ERESTARTNOHAND:
 453                if (!has_handler)
 454                        goto do_restart;
 455                regs->r3 = -EINTR;
 456                break;
 457        case -ERESTARTSYS:
 458                if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
 459                        regs->r3 = -EINTR;
 460                        break;
 461        }
 462        /* fallthrough */
 463        case -ERESTARTNOINTR:
 464do_restart:
 465                /* offset of 4 bytes to re-execute trap (brki) instruction */
 466                regs->pc -= 4;
 467                break;
 468        }
 469}
 470
 471/*
 472 * OK, we're invoking a handler
 473 */
 474
 475static void
 476handle_signal(unsigned long sig, struct k_sigaction *ka,
 477                siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 478{
 479        /* Set up the stack frame */
 480        if (ka->sa.sa_flags & SA_SIGINFO)
 481                setup_rt_frame(sig, ka, info, oldset, regs);
 482        else
 483                setup_frame(sig, ka, oldset, regs);
 484
 485        if (ka->sa.sa_flags & SA_ONESHOT)
 486                ka->sa.sa_handler = SIG_DFL;
 487
 488        if (!(ka->sa.sa_flags & SA_NODEFER)) {
 489                spin_lock_irq(&current->sighand->siglock);
 490                sigorsets(&current->blocked,
 491                                &current->blocked, &ka->sa.sa_mask);
 492                sigaddset(&current->blocked, sig);
 493                recalc_sigpending();
 494                spin_unlock_irq(&current->sighand->siglock);
 495        }
 496}
 497
 498/*
 499 * Note that 'init' is a special process: it doesn't get signals it doesn't
 500 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 501 * mistake.
 502 *
 503 * Note that we go through the signals twice: once to check the signals that
 504 * the kernel can handle, and then we build all the user-level signal handling
 505 * stack-frames in one go after that.
 506 */
 507int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
 508{
 509        siginfo_t info;
 510        int signr;
 511        struct k_sigaction ka;
 512#ifdef DEBUG_SIG
 513        printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall);
 514        printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1,
 515                        regs->r12, current_thread_info()->flags);
 516#endif
 517        /*
 518         * We want the common case to go fast, which
 519         * is why we may in certain cases get here from
 520         * kernel mode. Just return without doing anything
 521         * if so.
 522         */
 523        if (kernel_mode(regs))
 524                return 1;
 525
 526        if (!oldset)
 527                oldset = &current->blocked;
 528
 529        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 530        if (signr > 0) {
 531                /* Whee! Actually deliver the signal. */
 532                if (in_syscall)
 533                        handle_restart(regs, &ka, 1);
 534                handle_signal(signr, &ka, &info, oldset, regs);
 535                return 1;
 536        }
 537
 538        if (in_syscall)
 539                handle_restart(regs, NULL, 0);
 540
 541        /* Did we come from a system call? */
 542        return 0;
 543}
 544
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.