linux/arch/csky/kernel/signal.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <linux/signal.h>
   4#include <linux/uaccess.h>
   5#include <linux/syscalls.h>
   6#include <linux/tracehook.h>
   7
   8#include <asm/traps.h>
   9#include <asm/ucontext.h>
  10#include <asm/vdso.h>
  11
  12#include <abi/regdef.h>
  13
  14#ifdef CONFIG_CPU_HAS_FPU
  15#include <abi/fpu.h>
  16static int restore_fpu_state(struct sigcontext __user *sc)
  17{
  18        int err = 0;
  19        struct user_fp user_fp;
  20
  21        err = __copy_from_user(&user_fp, &sc->sc_user_fp, sizeof(user_fp));
  22
  23        restore_from_user_fp(&user_fp);
  24
  25        return err;
  26}
  27
  28static int save_fpu_state(struct sigcontext __user *sc)
  29{
  30        struct user_fp user_fp;
  31
  32        save_to_user_fp(&user_fp);
  33
  34        return __copy_to_user(&sc->sc_user_fp, &user_fp, sizeof(user_fp));
  35}
  36#else
  37#define restore_fpu_state(sigcontext)   (0)
  38#define save_fpu_state(sigcontext)      (0)
  39#endif
  40
  41struct rt_sigframe {
  42        /*
  43         * pad[3] is compatible with the same struct defined in
  44         * gcc/libgcc/config/csky/linux-unwind.h
  45         */
  46        int pad[3];
  47        struct siginfo info;
  48        struct ucontext uc;
  49};
  50
  51static long restore_sigcontext(struct pt_regs *regs,
  52        struct sigcontext __user *sc)
  53{
  54        int err = 0;
  55
  56        /* sc_pt_regs is structured the same as the start of pt_regs */
  57        err |= __copy_from_user(regs, &sc->sc_pt_regs, sizeof(struct pt_regs));
  58
  59        /* Restore the floating-point state. */
  60        err |= restore_fpu_state(sc);
  61
  62        return err;
  63}
  64
  65SYSCALL_DEFINE0(rt_sigreturn)
  66{
  67        struct pt_regs *regs = current_pt_regs();
  68        struct rt_sigframe __user *frame;
  69        sigset_t set;
  70
  71        /* Always make any pending restarted system calls return -EINTR */
  72        current->restart_block.fn = do_no_restart_syscall;
  73
  74        frame = (struct rt_sigframe __user *)regs->usp;
  75
  76        if (!access_ok(frame, sizeof(*frame)))
  77                goto badframe;
  78
  79        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
  80                goto badframe;
  81
  82        set_current_blocked(&set);
  83
  84        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
  85                goto badframe;
  86
  87        if (restore_altstack(&frame->uc.uc_stack))
  88                goto badframe;
  89
  90        return regs->a0;
  91
  92badframe:
  93        force_sig(SIGSEGV);
  94        return 0;
  95}
  96
  97static int setup_sigcontext(struct rt_sigframe __user *frame,
  98        struct pt_regs *regs)
  99{
 100        struct sigcontext __user *sc = &frame->uc.uc_mcontext;
 101        int err = 0;
 102
 103        err |= __copy_to_user(&sc->sc_pt_regs, regs, sizeof(struct pt_regs));
 104        err |= save_fpu_state(sc);
 105
 106        return err;
 107}
 108
 109static inline void __user *get_sigframe(struct ksignal *ksig,
 110        struct pt_regs *regs, size_t framesize)
 111{
 112        unsigned long sp;
 113        /* Default to using normal stack */
 114        sp = regs->usp;
 115
 116        /*
 117         * If we are on the alternate signal stack and would overflow it, don't.
 118         * Return an always-bogus address instead so we will die with SIGSEGV.
 119         */
 120        if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
 121                return (void __user __force *)(-1UL);
 122
 123        /* This is the X/Open sanctioned signal stack switching. */
 124        sp = sigsp(sp, ksig) - framesize;
 125
 126        /* Align the stack frame. */
 127        sp &= -8UL;
 128
 129        return (void __user *)sp;
 130}
 131
 132static int
 133setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
 134{
 135        struct rt_sigframe *frame;
 136        int err = 0;
 137        struct csky_vdso *vdso = current->mm->context.vdso;
 138
 139        frame = get_sigframe(ksig, regs, sizeof(*frame));
 140        if (!access_ok(frame, sizeof(*frame)))
 141                return -EFAULT;
 142
 143        err |= copy_siginfo_to_user(&frame->info, &ksig->info);
 144
 145        /* Create the ucontext. */
 146        err |= __put_user(0, &frame->uc.uc_flags);
 147        err |= __put_user(NULL, &frame->uc.uc_link);
 148        err |= __save_altstack(&frame->uc.uc_stack, regs->usp);
 149        err |= setup_sigcontext(frame, regs);
 150        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 151        if (err)
 152                return -EFAULT;
 153
 154        /* Set up to return from userspace. */
 155        regs->lr = (unsigned long)(vdso->rt_signal_retcode);
 156
 157        /*
 158         * Set up registers for signal handler.
 159         * Registers that we don't modify keep the value they had from
 160         * user-space at the time we took the signal.
 161         * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
 162         * since some things rely on this (e.g. glibc's debug/segfault.c).
 163         */
 164        regs->pc  = (unsigned long)ksig->ka.sa.sa_handler;
 165        regs->usp = (unsigned long)frame;
 166        regs->a0  = ksig->sig;                          /* a0: signal number */
 167        regs->a1  = (unsigned long)(&(frame->info));    /* a1: siginfo pointer */
 168        regs->a2  = (unsigned long)(&(frame->uc));      /* a2: ucontext pointer */
 169
 170        return 0;
 171}
 172
 173static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 174{
 175        sigset_t *oldset = sigmask_to_save();
 176        int ret;
 177
 178        /* Are we from a system call? */
 179        if (in_syscall(regs)) {
 180                /* Avoid additional syscall restarting via ret_from_exception */
 181                forget_syscall(regs);
 182
 183                /* If so, check system call restarting.. */
 184                switch (regs->a0) {
 185                case -ERESTART_RESTARTBLOCK:
 186                case -ERESTARTNOHAND:
 187                        regs->a0 = -EINTR;
 188                        break;
 189
 190                case -ERESTARTSYS:
 191                        if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
 192                                regs->a0 = -EINTR;
 193                                break;
 194                        }
 195                        /* fallthrough */
 196                case -ERESTARTNOINTR:
 197                        regs->a0 = regs->orig_a0;
 198                        regs->pc -= TRAP0_SIZE;
 199                        break;
 200                }
 201        }
 202
 203        /* Set up the stack frame */
 204        ret = setup_rt_frame(ksig, oldset, regs);
 205
 206        signal_setup_done(ret, ksig, 0);
 207}
 208
 209static void do_signal(struct pt_regs *regs)
 210{
 211        struct ksignal ksig;
 212
 213        if (get_signal(&ksig)) {
 214                /* Actually deliver the signal */
 215                handle_signal(&ksig, regs);
 216                return;
 217        }
 218
 219        /* Did we come from a system call? */
 220        if (in_syscall(regs)) {
 221                /* Avoid additional syscall restarting via ret_from_exception */
 222                forget_syscall(regs);
 223
 224                /* Restart the system call - no handlers present */
 225                switch (regs->a0) {
 226                case -ERESTARTNOHAND:
 227                case -ERESTARTSYS:
 228                case -ERESTARTNOINTR:
 229                        regs->a0 = regs->orig_a0;
 230                        regs->pc -= TRAP0_SIZE;
 231                        break;
 232                case -ERESTART_RESTARTBLOCK:
 233                        regs->a0 = regs->orig_a0;
 234                        regs_syscallid(regs) = __NR_restart_syscall;
 235                        regs->pc -= TRAP0_SIZE;
 236                        break;
 237                }
 238        }
 239
 240        /*
 241         * If there is no signal to deliver, we just put the saved
 242         * sigmask back.
 243         */
 244        restore_saved_sigmask();
 245}
 246
 247/*
 248 * notification of userspace execution resumption
 249 * - triggered by the _TIF_WORK_MASK flags
 250 */
 251asmlinkage void do_notify_resume(struct pt_regs *regs,
 252        unsigned long thread_info_flags)
 253{
 254        /* Handle pending signal delivery */
 255        if (thread_info_flags & _TIF_SIGPENDING)
 256                do_signal(regs);
 257
 258        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 259                clear_thread_flag(TIF_NOTIFY_RESUME);
 260                tracehook_notify_resume(regs);
 261        }
 262}
 263