linux/arch/hexagon/kernel/signal.c
<<
>>
Prefs
   1/*
   2 * Signal support for Hexagon processor
   3 *
   4 * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 and
   8 * only version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18 * 02110-1301, USA.
  19 */
  20
  21#include <linux/linkage.h>
  22#include <linux/syscalls.h>
  23#include <linux/tracehook.h>
  24#include <asm/registers.h>
  25#include <asm/thread_info.h>
  26#include <asm/unistd.h>
  27#include <asm/uaccess.h>
  28#include <asm/ucontext.h>
  29#include <asm/cacheflush.h>
  30#include <asm/signal.h>
  31#include <asm/vdso.h>
  32
  33struct rt_sigframe {
  34        unsigned long tramp[2];
  35        struct siginfo info;
  36        struct ucontext uc;
  37};
  38
  39static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
  40                          size_t frame_size)
  41{
  42        unsigned long sp = regs->r29;
  43
  44        /* check if we would overflow the alt stack */
  45        if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
  46                return (void __user __force *)-1UL;
  47
  48        /* Switch to signal stack if appropriate */
  49        if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
  50                sp = current->sas_ss_sp + current->sas_ss_size;
  51
  52        return (void __user *)((sp - frame_size) & ~(sizeof(long long) - 1));
  53}
  54
  55static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
  56{
  57        unsigned long tmp;
  58        int err = 0;
  59
  60        err |= copy_to_user(&sc->sc_regs.r0, &regs->r00,
  61                            32*sizeof(unsigned long));
  62
  63        err |= __put_user(regs->sa0, &sc->sc_regs.sa0);
  64        err |= __put_user(regs->lc0, &sc->sc_regs.lc0);
  65        err |= __put_user(regs->sa1, &sc->sc_regs.sa1);
  66        err |= __put_user(regs->lc1, &sc->sc_regs.lc1);
  67        err |= __put_user(regs->m0, &sc->sc_regs.m0);
  68        err |= __put_user(regs->m1, &sc->sc_regs.m1);
  69        err |= __put_user(regs->usr, &sc->sc_regs.usr);
  70        err |= __put_user(regs->preds, &sc->sc_regs.p3_0);
  71        err |= __put_user(regs->gp, &sc->sc_regs.gp);
  72        err |= __put_user(regs->ugp, &sc->sc_regs.ugp);
  73#if CONFIG_HEXAGON_ARCH_VERSION >= 4
  74        err |= __put_user(regs->cs0, &sc->sc_regs.cs0);
  75        err |= __put_user(regs->cs1, &sc->sc_regs.cs1);
  76#endif
  77        tmp = pt_elr(regs); err |= __put_user(tmp, &sc->sc_regs.pc);
  78        tmp = pt_cause(regs); err |= __put_user(tmp, &sc->sc_regs.cause);
  79        tmp = pt_badva(regs); err |= __put_user(tmp, &sc->sc_regs.badva);
  80
  81        return err;
  82}
  83
  84static int restore_sigcontext(struct pt_regs *regs,
  85                              struct sigcontext __user *sc)
  86{
  87        unsigned long tmp;
  88        int err = 0;
  89
  90        err |= copy_from_user(&regs->r00, &sc->sc_regs.r0,
  91                              32 * sizeof(unsigned long));
  92
  93        err |= __get_user(regs->sa0, &sc->sc_regs.sa0);
  94        err |= __get_user(regs->lc0, &sc->sc_regs.lc0);
  95        err |= __get_user(regs->sa1, &sc->sc_regs.sa1);
  96        err |= __get_user(regs->lc1, &sc->sc_regs.lc1);
  97        err |= __get_user(regs->m0, &sc->sc_regs.m0);
  98        err |= __get_user(regs->m1, &sc->sc_regs.m1);
  99        err |= __get_user(regs->usr, &sc->sc_regs.usr);
 100        err |= __get_user(regs->preds, &sc->sc_regs.p3_0);
 101        err |= __get_user(regs->gp, &sc->sc_regs.gp);
 102        err |= __get_user(regs->ugp, &sc->sc_regs.ugp);
 103#if CONFIG_HEXAGON_ARCH_VERSION >= 4
 104        err |= __get_user(regs->cs0, &sc->sc_regs.cs0);
 105        err |= __get_user(regs->cs1, &sc->sc_regs.cs1);
 106#endif
 107        err |= __get_user(tmp, &sc->sc_regs.pc); pt_set_elr(regs, tmp);
 108
 109        return err;
 110}
 111
 112/*
 113 * Setup signal stack frame with siginfo structure
 114 */
 115static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
 116                          sigset_t *set,  struct pt_regs *regs)
 117{
 118        int err = 0;
 119        struct rt_sigframe __user *frame;
 120        struct hexagon_vdso *vdso = current->mm->context.vdso;
 121
 122        frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe));
 123
 124        if (!access_ok(VERIFY_WRITE, frame, sizeof(struct rt_sigframe)))
 125                goto    sigsegv;
 126
 127        if (copy_siginfo_to_user(&frame->info, info))
 128                goto    sigsegv;
 129
 130        /* The on-stack signal trampoline is no longer executed;
 131         * however, the libgcc signal frame unwinding code checks for
 132         * the presence of these two numeric magic values.
 133         */
 134        err |= __put_user(0x7800d166, &frame->tramp[0]);
 135        err |= __put_user(0x5400c004, &frame->tramp[1]);
 136        err |= setup_sigcontext(regs, &frame->uc.uc_mcontext);
 137        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 138        err |= __save_altstack(&frame->uc.uc_stack, user_stack_pointer(regs));
 139        if (err)
 140                goto sigsegv;
 141
 142        /* Load r0/r1 pair with signumber/siginfo pointer... */
 143        regs->r0100 = ((unsigned long long)((unsigned long)&frame->info) << 32)
 144                | (unsigned long long)signr;
 145        regs->r02 = (unsigned long) &frame->uc;
 146        regs->r31 = (unsigned long) vdso->rt_signal_trampoline;
 147        pt_psp(regs) = (unsigned long) frame;
 148        pt_set_elr(regs, (unsigned long)ka->sa.sa_handler);
 149
 150        return 0;
 151
 152sigsegv:
 153        force_sigsegv(signr, current);
 154        return -EFAULT;
 155}
 156
 157/*
 158 * Setup invocation of signal handler
 159 */
 160static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
 161                         struct pt_regs *regs)
 162{
 163        /*
 164         * If we're handling a signal that aborted a system call,
 165         * set up the error return value before adding the signal
 166         * frame to the stack.
 167         */
 168
 169        if (regs->syscall_nr >= 0) {
 170                switch (regs->r00) {
 171                case -ERESTART_RESTARTBLOCK:
 172                case -ERESTARTNOHAND:
 173                        regs->r00 = -EINTR;
 174                        break;
 175                case -ERESTARTSYS:
 176                        if (!(ka->sa.sa_flags & SA_RESTART)) {
 177                                regs->r00 = -EINTR;
 178                                break;
 179                        }
 180                        /* Fall through */
 181                case -ERESTARTNOINTR:
 182                        regs->r06 = regs->syscall_nr;
 183                        pt_set_elr(regs, pt_elr(regs) - 4);
 184                        regs->r00 = regs->restart_r0;
 185                        break;
 186                default:
 187                        break;
 188                }
 189        }
 190
 191        /*
 192         * Set up the stack frame; not doing the SA_SIGINFO thing.  We
 193         * only set up the rt_frame flavor.
 194         */
 195        /* If there was an error on setup, no signal was delivered. */
 196        if (setup_rt_frame(sig, ka, info, sigmask_to_save(), regs) < 0)
 197                return;
 198
 199        signal_delivered(sig, info, ka, regs,
 200                        test_thread_flag(TIF_SINGLESTEP));
 201}
 202
 203/*
 204 * Called from return-from-event code.
 205 */
 206void do_signal(struct pt_regs *regs)
 207{
 208        struct k_sigaction sigact;
 209        siginfo_t info;
 210        int signo;
 211
 212        if (!user_mode(regs))
 213                return;
 214
 215        signo = get_signal_to_deliver(&info, &sigact, regs, NULL);
 216
 217        if (signo > 0) {
 218                handle_signal(signo, &info, &sigact, regs);
 219                return;
 220        }
 221
 222        /*
 223         * No (more) signals; if we came from a system call, handle the restart.
 224         */
 225
 226        if (regs->syscall_nr >= 0) {
 227                switch (regs->r00) {
 228                case -ERESTARTNOHAND:
 229                case -ERESTARTSYS:
 230                case -ERESTARTNOINTR:
 231                        regs->r06 = regs->syscall_nr;
 232                        break;
 233                case -ERESTART_RESTARTBLOCK:
 234                        regs->r06 = __NR_restart_syscall;
 235                        break;
 236                default:
 237                        goto no_restart;
 238                }
 239                pt_set_elr(regs, pt_elr(regs) - 4);
 240                regs->r00 = regs->restart_r0;
 241        }
 242
 243no_restart:
 244        /* If there's no signal to deliver, put the saved sigmask back */
 245        restore_saved_sigmask();
 246}
 247
 248/*
 249 * Architecture-specific wrappers for signal-related system calls
 250 */
 251
 252asmlinkage int sys_rt_sigreturn(void)
 253{
 254        struct pt_regs *regs = current_pt_regs();
 255        struct rt_sigframe __user *frame;
 256        sigset_t blocked;
 257
 258        /* Always make any pending restarted system calls return -EINTR */
 259        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 260
 261        frame = (struct rt_sigframe __user *)pt_psp(regs);
 262        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 263                goto badframe;
 264        if (__copy_from_user(&blocked, &frame->uc.uc_sigmask, sizeof(blocked)))
 265                goto badframe;
 266
 267        set_current_blocked(&blocked);
 268
 269        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 270                goto badframe;
 271
 272        /* Restore the user's stack as well */
 273        pt_psp(regs) = regs->r29;
 274
 275        regs->syscall_nr = -1;
 276
 277        if (restore_altstack(&frame->uc.uc_stack))
 278                goto badframe;
 279
 280        return regs->r00;
 281
 282badframe:
 283        force_sig(SIGSEGV, current);
 284        return 0;
 285}
 286