linux/arch/c6x/kernel/signal.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Port on Texas Instruments TMS320C6x architecture
   4 *
   5 *  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
   6 *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
   7 *
   8 *  Updated for 2.6.34: Mark Salter <msalter@redhat.com>
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/uaccess.h>
  13#include <linux/syscalls.h>
  14#include <linux/tracehook.h>
  15
  16#include <asm/ucontext.h>
  17#include <asm/cacheflush.h>
  18
  19
  20/*
  21 * Do a signal return, undo the signal stack.
  22 */
  23
  24#define RETCODE_SIZE (9 << 2)   /* 9 instructions = 36 bytes */
  25
  26struct rt_sigframe {
  27        struct siginfo __user *pinfo;
  28        void __user *puc;
  29        struct siginfo info;
  30        struct ucontext uc;
  31        unsigned long retcode[RETCODE_SIZE >> 2];
  32};
  33
  34static int restore_sigcontext(struct pt_regs *regs,
  35                              struct sigcontext __user *sc)
  36{
  37        int err = 0;
  38
  39        /* The access_ok check was done by caller, so use __get_user here */
  40#define COPY(x)  (err |= __get_user(regs->x, &sc->sc_##x))
  41
  42        COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
  43        COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
  44        COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
  45
  46        COPY(a16); COPY(a17); COPY(a18); COPY(a19);
  47        COPY(a20); COPY(a21); COPY(a22); COPY(a23);
  48        COPY(a24); COPY(a25); COPY(a26); COPY(a27);
  49        COPY(a28); COPY(a29); COPY(a30); COPY(a31);
  50        COPY(b16); COPY(b17); COPY(b18); COPY(b19);
  51        COPY(b20); COPY(b21); COPY(b22); COPY(b23);
  52        COPY(b24); COPY(b25); COPY(b26); COPY(b27);
  53        COPY(b28); COPY(b29); COPY(b30); COPY(b31);
  54
  55        COPY(csr); COPY(pc);
  56
  57#undef COPY
  58
  59        return err;
  60}
  61
  62asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
  63{
  64        struct rt_sigframe __user *frame;
  65        sigset_t set;
  66
  67        /* Always make any pending restarted system calls return -EINTR */
  68        current->restart_block.fn = do_no_restart_syscall;
  69
  70        /*
  71         * Since we stacked the signal on a dword boundary,
  72         * 'sp' should be dword aligned here.  If it's
  73         * not, then the user is trying to mess with us.
  74         */
  75        if (regs->sp & 7)
  76                goto badframe;
  77
  78        frame = (struct rt_sigframe __user *) ((unsigned long) regs->sp + 8);
  79
  80        if (!access_ok(frame, sizeof(*frame)))
  81                goto badframe;
  82        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
  83                goto badframe;
  84
  85        set_current_blocked(&set);
  86
  87        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
  88                goto badframe;
  89
  90        return regs->a4;
  91
  92badframe:
  93        force_sig(SIGSEGV);
  94        return 0;
  95}
  96
  97static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
  98                            unsigned long mask)
  99{
 100        int err = 0;
 101
 102        err |= __put_user(mask, &sc->sc_mask);
 103
 104        /* The access_ok check was done by caller, so use __put_user here */
 105#define COPY(x) (err |= __put_user(regs->x, &sc->sc_##x))
 106
 107        COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
 108        COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
 109        COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
 110
 111        COPY(a16); COPY(a17); COPY(a18); COPY(a19);
 112        COPY(a20); COPY(a21); COPY(a22); COPY(a23);
 113        COPY(a24); COPY(a25); COPY(a26); COPY(a27);
 114        COPY(a28); COPY(a29); COPY(a30); COPY(a31);
 115        COPY(b16); COPY(b17); COPY(b18); COPY(b19);
 116        COPY(b20); COPY(b21); COPY(b22); COPY(b23);
 117        COPY(b24); COPY(b25); COPY(b26); COPY(b27);
 118        COPY(b28); COPY(b29); COPY(b30); COPY(b31);
 119
 120        COPY(csr); COPY(pc);
 121
 122#undef COPY
 123
 124        return err;
 125}
 126
 127static inline void __user *get_sigframe(struct ksignal *ksig,
 128                                        struct pt_regs *regs,
 129                                        unsigned long framesize)
 130{
 131        unsigned long sp = sigsp(regs->sp, ksig);
 132
 133        /*
 134         * No matter what happens, 'sp' must be dword
 135         * aligned. Otherwise, nasty things will happen
 136         */
 137        return (void __user *)((sp - framesize) & ~7);
 138}
 139
 140static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 141                          struct pt_regs *regs)
 142{
 143        struct rt_sigframe __user *frame;
 144        unsigned long __user *retcode;
 145        int err = 0;
 146
 147        frame = get_sigframe(ksig, regs, sizeof(*frame));
 148
 149        if (!access_ok(frame, sizeof(*frame)))
 150                return -EFAULT;
 151
 152        err |= __put_user(&frame->info, &frame->pinfo);
 153        err |= __put_user(&frame->uc, &frame->puc);
 154        err |= copy_siginfo_to_user(&frame->info, &ksig->info);
 155
 156        /* Clear all the bits of the ucontext we don't use.  */
 157        err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
 158
 159        err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
 160        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 161
 162        /* Set up to return from userspace */
 163        retcode = (unsigned long __user *) &frame->retcode;
 164
 165        /* The access_ok check was done above, so use __put_user here */
 166#define COPY(x) (err |= __put_user(x, retcode++))
 167
 168        COPY(0x0000002AUL | (__NR_rt_sigreturn << 7));
 169                                /* MVK __NR_rt_sigreturn,B0 */
 170        COPY(0x10000000UL);     /* SWE */
 171        COPY(0x00006000UL);     /* NOP 4 */
 172        COPY(0x00006000UL);     /* NOP 4 */
 173        COPY(0x00006000UL);     /* NOP 4 */
 174        COPY(0x00006000UL);     /* NOP 4 */
 175        COPY(0x00006000UL);     /* NOP 4 */
 176        COPY(0x00006000UL);     /* NOP 4 */
 177        COPY(0x00006000UL);     /* NOP 4 */
 178
 179#undef COPY
 180
 181        if (err)
 182                return -EFAULT;
 183
 184        flush_icache_range((unsigned long) &frame->retcode,
 185                           (unsigned long) &frame->retcode + RETCODE_SIZE);
 186
 187        retcode = (unsigned long __user *) &frame->retcode;
 188
 189        /* Change user context to branch to signal handler */
 190        regs->sp = (unsigned long) frame - 8;
 191        regs->b3 = (unsigned long) retcode;
 192        regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
 193
 194        /* Give the signal number to the handler */
 195        regs->a4 = ksig->sig;
 196
 197        /*
 198         * For realtime signals we must also set the second and third
 199         * arguments for the signal handler.
 200         *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
 201         */
 202        regs->b4 = (unsigned long)&frame->info;
 203        regs->a6 = (unsigned long)&frame->uc;
 204
 205        return 0;
 206}
 207
 208static inline void
 209handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
 210{
 211        switch (regs->a4) {
 212        case -ERESTARTNOHAND:
 213                if (!has_handler)
 214                        goto do_restart;
 215                regs->a4 = -EINTR;
 216                break;
 217
 218        case -ERESTARTSYS:
 219                if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
 220                        regs->a4 = -EINTR;
 221                        break;
 222                }
 223        /* fallthrough */
 224        case -ERESTARTNOINTR:
 225do_restart:
 226                regs->a4 = regs->orig_a4;
 227                regs->pc -= 4;
 228                break;
 229        }
 230}
 231
 232/*
 233 * handle the actual delivery of a signal to userspace
 234 */
 235static void handle_signal(struct ksignal *ksig, struct pt_regs *regs,
 236                          int syscall)
 237{
 238        int ret;
 239
 240        /* Are we from a system call? */
 241        if (syscall) {
 242                /* If so, check system call restarting.. */
 243                switch (regs->a4) {
 244                case -ERESTART_RESTARTBLOCK:
 245                case -ERESTARTNOHAND:
 246                        regs->a4 = -EINTR;
 247                        break;
 248
 249                case -ERESTARTSYS:
 250                        if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
 251                                regs->a4 = -EINTR;
 252                                break;
 253                        }
 254
 255                        /* fallthrough */
 256                case -ERESTARTNOINTR:
 257                        regs->a4 = regs->orig_a4;
 258                        regs->pc -= 4;
 259                }
 260        }
 261
 262        /* Set up the stack frame */
 263        ret = setup_rt_frame(ksig, sigmask_to_save(), regs);
 264        signal_setup_done(ret, ksig, 0);
 265}
 266
 267/*
 268 * handle a potential signal
 269 */
 270static void do_signal(struct pt_regs *regs, int syscall)
 271{
 272        struct ksignal ksig;
 273
 274        /* we want the common case to go fast, which is why we may in certain
 275         * cases get here from kernel mode */
 276        if (!user_mode(regs))
 277                return;
 278
 279        if (get_signal(&ksig)) {
 280                handle_signal(&ksig, regs, syscall);
 281                return;
 282        }
 283
 284        /* did we come from a system call? */
 285        if (syscall) {
 286                /* restart the system call - no handlers present */
 287                switch (regs->a4) {
 288                case -ERESTARTNOHAND:
 289                case -ERESTARTSYS:
 290                case -ERESTARTNOINTR:
 291                        regs->a4 = regs->orig_a4;
 292                        regs->pc -= 4;
 293                        break;
 294
 295                case -ERESTART_RESTARTBLOCK:
 296                        regs->a4 = regs->orig_a4;
 297                        regs->b0 = __NR_restart_syscall;
 298                        regs->pc -= 4;
 299                        break;
 300                }
 301        }
 302
 303        /* if there's no signal to deliver, we just put the saved sigmask
 304         * back */
 305        restore_saved_sigmask();
 306}
 307
 308/*
 309 * notification of userspace execution resumption
 310 * - triggered by current->work.notify_resume
 311 */
 312asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags,
 313                                 int syscall)
 314{
 315        /* deal with pending signal delivery */
 316        if (thread_info_flags & (1 << TIF_SIGPENDING))
 317                do_signal(regs, syscall);
 318
 319        if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) {
 320                clear_thread_flag(TIF_NOTIFY_RESUME);
 321                tracehook_notify_resume(regs);
 322        }
 323}
 324