linux/arch/metag/kernel/signal.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 1991,1992  Linus Torvalds
   3 *  Copyright (C) 2005-2012  Imagination Technologies Ltd.
   4 *
   5 *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
   6 *
   7 */
   8
   9#include <linux/sched.h>
  10#include <linux/mm.h>
  11#include <linux/smp.h>
  12#include <linux/kernel.h>
  13#include <linux/signal.h>
  14#include <linux/errno.h>
  15#include <linux/wait.h>
  16#include <linux/ptrace.h>
  17#include <linux/unistd.h>
  18#include <linux/stddef.h>
  19#include <linux/personality.h>
  20#include <linux/uaccess.h>
  21#include <linux/tracehook.h>
  22
  23#include <asm/ucontext.h>
  24#include <asm/cacheflush.h>
  25#include <asm/switch.h>
  26#include <asm/syscall.h>
  27#include <asm/syscalls.h>
  28
  29#define REG_FLAGS       ctx.SaveMask
  30#define REG_RETVAL      ctx.DX[0].U0
  31#define REG_SYSCALL     ctx.DX[0].U1
  32#define REG_SP          ctx.AX[0].U0
  33#define REG_ARG1        ctx.DX[3].U1
  34#define REG_ARG2        ctx.DX[3].U0
  35#define REG_ARG3        ctx.DX[2].U1
  36#define REG_PC          ctx.CurrPC
  37#define REG_RTP         ctx.DX[4].U1
  38
  39struct rt_sigframe {
  40        struct siginfo info;
  41        struct ucontext uc;
  42        unsigned long retcode[2];
  43};
  44
  45static int restore_sigcontext(struct pt_regs *regs,
  46                              struct sigcontext __user *sc)
  47{
  48        int err;
  49
  50        /* Always make any pending restarted system calls return -EINTR */
  51        current->restart_block.fn = do_no_restart_syscall;
  52
  53        err = metag_gp_regs_copyin(regs, 0, sizeof(struct user_gp_regs), NULL,
  54                                   &sc->regs);
  55        if (!err)
  56                err = metag_cb_regs_copyin(regs, 0,
  57                                           sizeof(struct user_cb_regs), NULL,
  58                                           &sc->cb);
  59        if (!err)
  60                err = metag_rp_state_copyin(regs, 0,
  61                                            sizeof(struct user_rp_state), NULL,
  62                                            &sc->rp);
  63
  64        /* This is a user-mode context. */
  65        regs->REG_FLAGS |= TBICTX_PRIV_BIT;
  66
  67        return err;
  68}
  69
  70long sys_rt_sigreturn(void)
  71{
  72        /* NOTE - Meta stack goes UPWARDS - so we wind the stack back */
  73        struct pt_regs *regs = current_pt_regs();
  74        struct rt_sigframe __user *frame;
  75        sigset_t set;
  76
  77        frame = (__force struct rt_sigframe __user *)(regs->REG_SP -
  78                                                      sizeof(*frame));
  79
  80        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  81                goto badframe;
  82
  83        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
  84                goto badframe;
  85
  86        set_current_blocked(&set);
  87
  88        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
  89                goto badframe;
  90
  91        if (restore_altstack(&frame->uc.uc_stack))
  92                goto badframe;
  93
  94        return regs->REG_RETVAL;
  95
  96badframe:
  97        force_sig(SIGSEGV, current);
  98
  99        return 0;
 100}
 101
 102static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
 103                            unsigned long mask)
 104{
 105        int err;
 106
 107        err = metag_gp_regs_copyout(regs, 0, sizeof(struct user_gp_regs), NULL,
 108                                    &sc->regs);
 109
 110        if (!err)
 111                err = metag_cb_regs_copyout(regs, 0,
 112                                            sizeof(struct user_cb_regs), NULL,
 113                                            &sc->cb);
 114        if (!err)
 115                err = metag_rp_state_copyout(regs, 0,
 116                                             sizeof(struct user_rp_state), NULL,
 117                                             &sc->rp);
 118
 119        /* OK, clear that cbuf flag in the old context, or our stored
 120         * catch buffer will be restored when we go to call the signal
 121         * handler. Also clear out the CBRP RA/RD pipe bit incase
 122         * that is pending as well!
 123         * Note that as we have already stored this context, these
 124         * flags will get restored on sigreturn to their original
 125         * state.
 126         */
 127        regs->REG_FLAGS &= ~(TBICTX_XCBF_BIT | TBICTX_CBUF_BIT |
 128                             TBICTX_CBRP_BIT);
 129
 130        /* Clear out the LSM_STEP bits in case we are in the middle of
 131         * and MSET/MGET.
 132         */
 133        regs->ctx.Flags &= ~TXSTATUS_LSM_STEP_BITS;
 134
 135        err |= __put_user(mask, &sc->oldmask);
 136
 137        return err;
 138}
 139
 140/*
 141 * Determine which stack to use..
 142 */
 143static void __user *get_sigframe(struct ksignal *ksig, unsigned long sp)
 144{
 145        sp = sigsp(sp, ksig);
 146        sp = (sp + 7) & ~7;                     /* 8byte align stack */
 147
 148        return (void __user *)sp;
 149}
 150
 151static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 152                          struct pt_regs *regs)
 153{
 154        struct rt_sigframe __user *frame;
 155        int err;
 156        unsigned long code;
 157
 158        frame = get_sigframe(ksig, regs->REG_SP);
 159        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 160                return -EFAULT;
 161
 162        err = copy_siginfo_to_user(&frame->info, &ksig->info);
 163
 164        /* Create the ucontext.  */
 165        err |= __put_user(0, &frame->uc.uc_flags);
 166        err |= __put_user(0, (unsigned long __user *)&frame->uc.uc_link);
 167        err |= __save_altstack(&frame->uc.uc_stack, regs->REG_SP);
 168        err |= setup_sigcontext(&frame->uc.uc_mcontext,
 169                                regs, set->sig[0]);
 170        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 171
 172        if (err)
 173                return -EFAULT;
 174
 175        /* Set up to return from userspace.  */
 176
 177        /* MOV D1Re0 (D1.0), #__NR_rt_sigreturn */
 178        code = 0x03000004 | (__NR_rt_sigreturn << 3);
 179        err |= __put_user(code, (unsigned long __user *)(&frame->retcode[0]));
 180
 181        /* SWITCH #__METAG_SW_SYS */
 182        code = __METAG_SW_ENCODING(SYS);
 183        err |= __put_user(code, (unsigned long __user *)(&frame->retcode[1]));
 184
 185        if (err)
 186                return -EFAULT;
 187
 188        /* Set up registers for signal handler */
 189        regs->REG_RTP = (unsigned long) frame->retcode;
 190        regs->REG_SP = (unsigned long) frame + sizeof(*frame);
 191        regs->REG_ARG1 = ksig->sig;
 192        regs->REG_ARG2 = (unsigned long) &frame->info;
 193        regs->REG_ARG3 = (unsigned long) &frame->uc;
 194        regs->REG_PC = (unsigned long) ksig->ka.sa.sa_handler;
 195
 196        pr_debug("SIG deliver (%s:%d): sp=%p pc=%08x pr=%08x\n",
 197                 current->comm, current->pid, frame, regs->REG_PC,
 198                 regs->REG_RTP);
 199
 200        /* Now pass size of 'new code' into sigtramp so we can do a more
 201         * effective cache flush - directed rather than 'full flush'.
 202         */
 203        flush_cache_sigtramp(regs->REG_RTP, sizeof(frame->retcode));
 204
 205        return 0;
 206}
 207
 208static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 209{
 210        sigset_t *oldset = sigmask_to_save();
 211        int ret;
 212
 213        /* Set up the stack frame */
 214        ret = setup_rt_frame(ksig, oldset, regs);
 215
 216        signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
 217}
 218
 219 /*
 220  * Notes for Meta.
 221  * We have moved from the old 2.4.9 SH way of using syscall_nr (in the stored
 222  * context) to passing in the syscall flag on the stack.
 223  * This is because having syscall_nr in our context does not fit with TBX, and
 224  * corrupted the stack.
 225  */
 226static int do_signal(struct pt_regs *regs, int syscall)
 227{
 228        unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
 229        int restart = 0;
 230        struct ksignal ksig;
 231
 232        /*
 233         * By the end of rt_sigreturn the context describes the point that the
 234         * signal was taken (which may happen to be just before a syscall if
 235         * it's already been restarted). This should *never* be mistaken for a
 236         * system call in need of restarting.
 237         */
 238        if (syscall == __NR_rt_sigreturn)
 239                syscall = -1;
 240
 241        /* Did we come from a system call? */
 242        if (syscall >= 0) {
 243                continue_addr = regs->REG_PC;
 244                restart_addr = continue_addr - 4;
 245                retval = regs->REG_RETVAL;
 246
 247                /*
 248                 * Prepare for system call restart. We do this here so that a
 249                 * debugger will see the already changed PC.
 250                 */
 251                switch (retval) {
 252                case -ERESTART_RESTARTBLOCK:
 253                        restart = -2;
 254                case -ERESTARTNOHAND:
 255                case -ERESTARTSYS:
 256                case -ERESTARTNOINTR:
 257                        ++restart;
 258                        regs->REG_PC = restart_addr;
 259                        break;
 260                }
 261        }
 262
 263        /*
 264         * Get the signal to deliver. When running under ptrace, at this point
 265         * the debugger may change all our registers ...
 266         */
 267        get_signal(&ksig);
 268
 269        /*
 270         * Depending on the signal settings we may need to revert the decision
 271         * to restart the system call. But skip this if a debugger has chosen to
 272         * restart at a different PC.
 273         */
 274        if (regs->REG_PC != restart_addr)
 275                restart = 0;
 276        if (ksig.sig > 0) {
 277                if (unlikely(restart)) {
 278                        if (retval == -ERESTARTNOHAND
 279                            || retval == -ERESTART_RESTARTBLOCK
 280                            || (retval == -ERESTARTSYS
 281                                && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
 282                                regs->REG_RETVAL = -EINTR;
 283                                regs->REG_PC = continue_addr;
 284                        }
 285                }
 286
 287                /* Whee! Actually deliver the signal.  */
 288                handle_signal(&ksig, regs);
 289                return 0;
 290        }
 291
 292        /* Handlerless -ERESTART_RESTARTBLOCK re-enters via restart_syscall */
 293        if (unlikely(restart < 0))
 294                regs->REG_SYSCALL = __NR_restart_syscall;
 295
 296        /*
 297         * If there's no signal to deliver, we just put the saved sigmask back.
 298         */
 299        restore_saved_sigmask();
 300
 301        return restart;
 302}
 303
 304int do_work_pending(struct pt_regs *regs, unsigned int thread_flags,
 305                    int syscall)
 306{
 307        do {
 308                if (likely(thread_flags & _TIF_NEED_RESCHED)) {
 309                        schedule();
 310                } else {
 311                        if (unlikely(!user_mode(regs)))
 312                                return 0;
 313                        local_irq_enable();
 314                        if (thread_flags & _TIF_SIGPENDING) {
 315                                int restart = do_signal(regs, syscall);
 316                                if (unlikely(restart)) {
 317                                        /*
 318                                         * Restart without handlers.
 319                                         * Deal with it without leaving
 320                                         * the kernel space.
 321                                         */
 322                                        return restart;
 323                                }
 324                                syscall = -1;
 325                        } else {
 326                                clear_thread_flag(TIF_NOTIFY_RESUME);
 327                                tracehook_notify_resume(regs);
 328                        }
 329                }
 330                local_irq_disable();
 331                thread_flags = current_thread_info()->flags;
 332        } while (thread_flags & _TIF_WORK_MASK);
 333        return 0;
 334}
 335