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_thread_info()->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 k_sigaction *ka, unsigned long sp,
 144                                 size_t frame_size)
 145{
 146        /* Meta stacks grows upwards */
 147        if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
 148                sp = current->sas_ss_sp;
 149
 150        sp = (sp + 7) & ~7;                     /* 8byte align stack */
 151
 152        return (void __user *)sp;
 153}
 154
 155static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 156                          sigset_t *set, struct pt_regs *regs)
 157{
 158        struct rt_sigframe __user *frame;
 159        int err = -EFAULT;
 160        unsigned long code;
 161
 162        frame = get_sigframe(ka, regs->REG_SP, sizeof(*frame));
 163        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 164                goto out;
 165
 166        err = copy_siginfo_to_user(&frame->info, info);
 167
 168        /* Create the ucontext.  */
 169        err |= __put_user(0, &frame->uc.uc_flags);
 170        err |= __put_user(0, (unsigned long __user *)&frame->uc.uc_link);
 171        err |= __save_altstack(&frame->uc.uc_stack, regs->REG_SP);
 172        err |= setup_sigcontext(&frame->uc.uc_mcontext,
 173                                regs, set->sig[0]);
 174        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 175
 176        if (err)
 177                goto out;
 178
 179        /* Set up to return from userspace.  */
 180
 181        /* MOV D1Re0 (D1.0), #__NR_rt_sigreturn */
 182        code = 0x03000004 | (__NR_rt_sigreturn << 3);
 183        err |= __put_user(code, (unsigned long __user *)(&frame->retcode[0]));
 184
 185        /* SWITCH #__METAG_SW_SYS */
 186        code = __METAG_SW_ENCODING(SYS);
 187        err |= __put_user(code, (unsigned long __user *)(&frame->retcode[1]));
 188
 189        if (err)
 190                goto out;
 191
 192        /* Set up registers for signal handler */
 193        regs->REG_RTP = (unsigned long) frame->retcode;
 194        regs->REG_SP = (unsigned long) frame + sizeof(*frame);
 195        regs->REG_ARG1 = sig;
 196        regs->REG_ARG2 = (unsigned long) &frame->info;
 197        regs->REG_ARG3 = (unsigned long) &frame->uc;
 198        regs->REG_PC = (unsigned long) ka->sa.sa_handler;
 199
 200        pr_debug("SIG deliver (%s:%d): sp=%p pc=%08x pr=%08x\n",
 201                 current->comm, current->pid, frame, regs->REG_PC,
 202                 regs->REG_RTP);
 203
 204        /* Now pass size of 'new code' into sigtramp so we can do a more
 205         * effective cache flush - directed rather than 'full flush'.
 206         */
 207        flush_cache_sigtramp(regs->REG_RTP, sizeof(frame->retcode));
 208out:
 209        if (err) {
 210                force_sigsegv(sig, current);
 211                return -EFAULT;
 212        }
 213        return 0;
 214}
 215
 216static void handle_signal(unsigned long sig, siginfo_t *info,
 217                          struct k_sigaction *ka, struct pt_regs *regs)
 218{
 219        sigset_t *oldset = sigmask_to_save();
 220
 221        /* Set up the stack frame */
 222        if (setup_rt_frame(sig, ka, info, oldset, regs))
 223                return;
 224
 225        signal_delivered(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP));
 226}
 227
 228 /*
 229  * Notes for Meta.
 230  * We have moved from the old 2.4.9 SH way of using syscall_nr (in the stored
 231  * context) to passing in the syscall flag on the stack.
 232  * This is because having syscall_nr in our context does not fit with TBX, and
 233  * corrupted the stack.
 234  */
 235static int do_signal(struct pt_regs *regs, int syscall)
 236{
 237        unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
 238        struct k_sigaction ka;
 239        siginfo_t info;
 240        int signr;
 241        int restart = 0;
 242
 243        /*
 244         * By the end of rt_sigreturn the context describes the point that the
 245         * signal was taken (which may happen to be just before a syscall if
 246         * it's already been restarted). This should *never* be mistaken for a
 247         * system call in need of restarting.
 248         */
 249        if (syscall == __NR_rt_sigreturn)
 250                syscall = -1;
 251
 252        /* Did we come from a system call? */
 253        if (syscall >= 0) {
 254                continue_addr = regs->REG_PC;
 255                restart_addr = continue_addr - 4;
 256                retval = regs->REG_RETVAL;
 257
 258                /*
 259                 * Prepare for system call restart. We do this here so that a
 260                 * debugger will see the already changed PC.
 261                 */
 262                switch (retval) {
 263                case -ERESTART_RESTARTBLOCK:
 264                        restart = -2;
 265                case -ERESTARTNOHAND:
 266                case -ERESTARTSYS:
 267                case -ERESTARTNOINTR:
 268                        ++restart;
 269                        regs->REG_PC = restart_addr;
 270                        break;
 271                }
 272        }
 273
 274        /*
 275         * Get the signal to deliver. When running under ptrace, at this point
 276         * the debugger may change all our registers ...
 277         */
 278        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 279        /*
 280         * Depending on the signal settings we may need to revert the decision
 281         * to restart the system call. But skip this if a debugger has chosen to
 282         * restart at a different PC.
 283         */
 284        if (regs->REG_PC != restart_addr)
 285                restart = 0;
 286        if (signr > 0) {
 287                if (unlikely(restart)) {
 288                        if (retval == -ERESTARTNOHAND
 289                            || retval == -ERESTART_RESTARTBLOCK
 290                            || (retval == -ERESTARTSYS
 291                                && !(ka.sa.sa_flags & SA_RESTART))) {
 292                                regs->REG_RETVAL = -EINTR;
 293                                regs->REG_PC = continue_addr;
 294                        }
 295                }
 296
 297                /* Whee! Actually deliver the signal.  */
 298                handle_signal(signr, &info, &ka, regs);
 299                return 0;
 300        }
 301
 302        /* Handlerless -ERESTART_RESTARTBLOCK re-enters via restart_syscall */
 303        if (unlikely(restart < 0))
 304                regs->REG_SYSCALL = __NR_restart_syscall;
 305
 306        /*
 307         * If there's no signal to deliver, we just put the saved sigmask back.
 308         */
 309        restore_saved_sigmask();
 310
 311        return restart;
 312}
 313
 314int do_work_pending(struct pt_regs *regs, unsigned int thread_flags,
 315                    int syscall)
 316{
 317        do {
 318                if (likely(thread_flags & _TIF_NEED_RESCHED)) {
 319                        schedule();
 320                } else {
 321                        if (unlikely(!user_mode(regs)))
 322                                return 0;
 323                        local_irq_enable();
 324                        if (thread_flags & _TIF_SIGPENDING) {
 325                                int restart = do_signal(regs, syscall);
 326                                if (unlikely(restart)) {
 327                                        /*
 328                                         * Restart without handlers.
 329                                         * Deal with it without leaving
 330                                         * the kernel space.
 331                                         */
 332                                        return restart;
 333                                }
 334                                syscall = -1;
 335                        } else {
 336                                clear_thread_flag(TIF_NOTIFY_RESUME);
 337                                tracehook_notify_resume(regs);
 338                        }
 339                }
 340                local_irq_disable();
 341                thread_flags = current_thread_info()->flags;
 342        } while (thread_flags & _TIF_WORK_MASK);
 343        return 0;
 344}
 345