linux/arch/riscv/kernel/signal.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
   3 *  Chen Liqin <liqin.chen@sunplusct.com>
   4 *  Lennox Wu <lennox.wu@sunplusct.com>
   5 * Copyright (C) 2012 Regents of the University of California
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, see the file COPYING, or write
  19 * to the Free Software Foundation, Inc.,
  20 */
  21
  22#include <linux/signal.h>
  23#include <linux/uaccess.h>
  24#include <linux/syscalls.h>
  25#include <linux/tracehook.h>
  26#include <linux/linkage.h>
  27
  28#include <asm/ucontext.h>
  29#include <asm/vdso.h>
  30#include <asm/switch_to.h>
  31#include <asm/csr.h>
  32
  33#define DEBUG_SIG 0
  34
  35struct rt_sigframe {
  36        struct siginfo info;
  37        struct ucontext uc;
  38};
  39
  40static long restore_d_state(struct pt_regs *regs,
  41        struct __riscv_d_ext_state __user *state)
  42{
  43        long err;
  44        err = __copy_from_user(&current->thread.fstate, state, sizeof(*state));
  45        if (likely(!err))
  46                fstate_restore(current, regs);
  47        return err;
  48}
  49
  50static long save_d_state(struct pt_regs *regs,
  51        struct __riscv_d_ext_state __user *state)
  52{
  53        fstate_save(current, regs);
  54        return __copy_to_user(state, &current->thread.fstate, sizeof(*state));
  55}
  56
  57static long restore_sigcontext(struct pt_regs *regs,
  58        struct sigcontext __user *sc)
  59{
  60        long err;
  61        size_t i;
  62        /* sc_regs is structured the same as the start of pt_regs */
  63        err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
  64        if (unlikely(err))
  65                return err;
  66        /* Restore the floating-point state. */
  67        err = restore_d_state(regs, &sc->sc_fpregs.d);
  68        if (unlikely(err))
  69                return err;
  70        /* We support no other extension state at this time. */
  71        for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) {
  72                u32 value;
  73                err = __get_user(value, &sc->sc_fpregs.q.reserved[i]);
  74                if (unlikely(err))
  75                        break;
  76                if (value != 0)
  77                        return -EINVAL;
  78        }
  79        return err;
  80}
  81
  82SYSCALL_DEFINE0(rt_sigreturn)
  83{
  84        struct pt_regs *regs = current_pt_regs();
  85        struct rt_sigframe __user *frame;
  86        struct task_struct *task;
  87        sigset_t set;
  88
  89        /* Always make any pending restarted system calls return -EINTR */
  90        current->restart_block.fn = do_no_restart_syscall;
  91
  92        frame = (struct rt_sigframe __user *)regs->sp;
  93
  94        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  95                goto badframe;
  96
  97        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
  98                goto badframe;
  99
 100        set_current_blocked(&set);
 101
 102        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 103                goto badframe;
 104
 105        if (restore_altstack(&frame->uc.uc_stack))
 106                goto badframe;
 107
 108        return regs->a0;
 109
 110badframe:
 111        task = current;
 112        if (show_unhandled_signals) {
 113                pr_info_ratelimited(
 114                        "%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
 115                        task->comm, task_pid_nr(task), __func__,
 116                        frame, (void *)regs->sepc, (void *)regs->sp);
 117        }
 118        force_sig(SIGSEGV, task);
 119        return 0;
 120}
 121
 122static long setup_sigcontext(struct rt_sigframe __user *frame,
 123        struct pt_regs *regs)
 124{
 125        struct sigcontext __user *sc = &frame->uc.uc_mcontext;
 126        long err;
 127        size_t i;
 128        /* sc_regs is structured the same as the start of pt_regs */
 129        err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
 130        /* Save the floating-point state. */
 131        err |= save_d_state(regs, &sc->sc_fpregs.d);
 132        /* We support no other extension state at this time. */
 133        for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++)
 134                err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]);
 135        return err;
 136}
 137
 138static inline void __user *get_sigframe(struct ksignal *ksig,
 139        struct pt_regs *regs, size_t framesize)
 140{
 141        unsigned long sp;
 142        /* Default to using normal stack */
 143        sp = regs->sp;
 144
 145        /*
 146         * If we are on the alternate signal stack and would overflow it, don't.
 147         * Return an always-bogus address instead so we will die with SIGSEGV.
 148         */
 149        if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
 150                return (void __user __force *)(-1UL);
 151
 152        /* This is the X/Open sanctioned signal stack switching. */
 153        sp = sigsp(sp, ksig) - framesize;
 154
 155        /* Align the stack frame. */
 156        sp &= ~0xfUL;
 157
 158        return (void __user *)sp;
 159}
 160
 161
 162static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 163        struct pt_regs *regs)
 164{
 165        struct rt_sigframe __user *frame;
 166        long err = 0;
 167
 168        frame = get_sigframe(ksig, regs, sizeof(*frame));
 169        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 170                return -EFAULT;
 171
 172        err |= copy_siginfo_to_user(&frame->info, &ksig->info);
 173
 174        /* Create the ucontext. */
 175        err |= __put_user(0, &frame->uc.uc_flags);
 176        err |= __put_user(NULL, &frame->uc.uc_link);
 177        err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
 178        err |= setup_sigcontext(frame, regs);
 179        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 180        if (err)
 181                return -EFAULT;
 182
 183        /* Set up to return from userspace. */
 184        regs->ra = (unsigned long)VDSO_SYMBOL(
 185                current->mm->context.vdso, rt_sigreturn);
 186
 187        /*
 188         * Set up registers for signal handler.
 189         * Registers that we don't modify keep the value they had from
 190         * user-space at the time we took the signal.
 191         * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
 192         * since some things rely on this (e.g. glibc's debug/segfault.c).
 193         */
 194        regs->sepc = (unsigned long)ksig->ka.sa.sa_handler;
 195        regs->sp = (unsigned long)frame;
 196        regs->a0 = ksig->sig;                     /* a0: signal number */
 197        regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */
 198        regs->a2 = (unsigned long)(&frame->uc);   /* a2: ucontext pointer */
 199
 200#if DEBUG_SIG
 201        pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n",
 202                current->comm, task_pid_nr(current), ksig->sig,
 203                (void *)regs->sepc, (void *)regs->ra, frame);
 204#endif
 205
 206        return 0;
 207}
 208
 209static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 210{
 211        sigset_t *oldset = sigmask_to_save();
 212        int ret;
 213
 214        /* Are we from a system call? */
 215        if (regs->scause == EXC_SYSCALL) {
 216                /* If so, check system call restarting.. */
 217                switch (regs->a0) {
 218                case -ERESTART_RESTARTBLOCK:
 219                case -ERESTARTNOHAND:
 220                        regs->a0 = -EINTR;
 221                        break;
 222
 223                case -ERESTARTSYS:
 224                        if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
 225                                regs->a0 = -EINTR;
 226                                break;
 227                        }
 228                        /* fallthrough */
 229                case -ERESTARTNOINTR:
 230                        regs->a0 = regs->orig_a0;
 231                        regs->sepc -= 0x4;
 232                        break;
 233                }
 234        }
 235
 236        /* Set up the stack frame */
 237        ret = setup_rt_frame(ksig, oldset, regs);
 238
 239        signal_setup_done(ret, ksig, 0);
 240}
 241
 242static void do_signal(struct pt_regs *regs)
 243{
 244        struct ksignal ksig;
 245
 246        if (get_signal(&ksig)) {
 247                /* Actually deliver the signal */
 248                handle_signal(&ksig, regs);
 249                return;
 250        }
 251
 252        /* Did we come from a system call? */
 253        if (regs->scause == EXC_SYSCALL) {
 254                /* Restart the system call - no handlers present */
 255                switch (regs->a0) {
 256                case -ERESTARTNOHAND:
 257                case -ERESTARTSYS:
 258                case -ERESTARTNOINTR:
 259                        regs->a0 = regs->orig_a0;
 260                        regs->sepc -= 0x4;
 261                        break;
 262                case -ERESTART_RESTARTBLOCK:
 263                        regs->a0 = regs->orig_a0;
 264                        regs->a7 = __NR_restart_syscall;
 265                        regs->sepc -= 0x4;
 266                        break;
 267                }
 268        }
 269
 270        /*
 271         * If there is no signal to deliver, we just put the saved
 272         * sigmask back.
 273         */
 274        restore_saved_sigmask();
 275}
 276
 277/*
 278 * notification of userspace execution resumption
 279 * - triggered by the _TIF_WORK_MASK flags
 280 */
 281asmlinkage void do_notify_resume(struct pt_regs *regs,
 282        unsigned long thread_info_flags)
 283{
 284        /* Handle pending signal delivery */
 285        if (thread_info_flags & _TIF_SIGPENDING)
 286                do_signal(regs);
 287
 288        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 289                clear_thread_flag(TIF_NOTIFY_RESUME);
 290                tracehook_notify_resume(regs);
 291        }
 292}
 293