linux/arch/mips/kernel/signal_n32.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2003 Broadcom Corporation
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public License
   6 * as published by the Free Software Foundation; either version 2
   7 * of the License, or (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17 */
  18#include <linux/cache.h>
  19#include <linux/sched.h>
  20#include <linux/mm.h>
  21#include <linux/smp.h>
  22#include <linux/kernel.h>
  23#include <linux/signal.h>
  24#include <linux/errno.h>
  25#include <linux/wait.h>
  26#include <linux/ptrace.h>
  27#include <linux/unistd.h>
  28#include <linux/compat.h>
  29#include <linux/bitops.h>
  30
  31#include <asm/abi.h>
  32#include <asm/asm.h>
  33#include <asm/cacheflush.h>
  34#include <asm/compat-signal.h>
  35#include <asm/sim.h>
  36#include <asm/uaccess.h>
  37#include <asm/ucontext.h>
  38#include <asm/fpu.h>
  39#include <asm/cpu-features.h>
  40#include <asm/war.h>
  41
  42#include "signal-common.h"
  43
  44/*
  45 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
  46 */
  47#define __NR_N32_restart_syscall        6214
  48
  49extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *);
  50extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
  51
  52struct ucontextn32 {
  53        u32                 uc_flags;
  54        s32                 uc_link;
  55        compat_stack_t      uc_stack;
  56        struct sigcontext   uc_mcontext;
  57        compat_sigset_t     uc_sigmask;   /* mask last for extensibility */
  58};
  59
  60struct rt_sigframe_n32 {
  61        u32 rs_ass[4];                  /* argument save space for o32 */
  62        u32 rs_pad[2];                  /* Was: signal trampoline */
  63        struct compat_siginfo rs_info;
  64        struct ucontextn32 rs_uc;
  65};
  66
  67asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
  68{
  69        struct rt_sigframe_n32 __user *frame;
  70        sigset_t set;
  71        int sig;
  72
  73        frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
  74        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  75                goto badframe;
  76        if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
  77                goto badframe;
  78
  79        set_current_blocked(&set);
  80
  81        sig = restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext);
  82        if (sig < 0)
  83                goto badframe;
  84        else if (sig)
  85                force_sig(sig, current);
  86
  87        if (compat_restore_altstack(&frame->rs_uc.uc_stack))
  88                goto badframe;
  89
  90        /*
  91         * Don't let your children do this ...
  92         */
  93        __asm__ __volatile__(
  94                "move\t$29, %0\n\t"
  95                "j\tsyscall_exit"
  96                :/* no outputs */
  97                :"r" (&regs));
  98        /* Unreached */
  99
 100badframe:
 101        force_sig(SIGSEGV, current);
 102}
 103
 104static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig,
 105                              struct pt_regs *regs, sigset_t *set)
 106{
 107        struct rt_sigframe_n32 __user *frame;
 108        int err = 0;
 109
 110        frame = get_sigframe(ksig, regs, sizeof(*frame));
 111        if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
 112                return -EFAULT;
 113
 114        /* Create siginfo.  */
 115        err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info);
 116
 117        /* Create the ucontext.  */
 118        err |= __put_user(0, &frame->rs_uc.uc_flags);
 119        err |= __put_user(0, &frame->rs_uc.uc_link);
 120        err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
 121        err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
 122        err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
 123
 124        if (err)
 125                return -EFAULT;
 126
 127        /*
 128         * Arguments to signal handler:
 129         *
 130         *   a0 = signal number
 131         *   a1 = 0 (should be cause)
 132         *   a2 = pointer to ucontext
 133         *
 134         * $25 and c0_epc point to the signal handler, $29 points to
 135         * the struct rt_sigframe.
 136         */
 137        regs->regs[ 4] = ksig->sig;
 138        regs->regs[ 5] = (unsigned long) &frame->rs_info;
 139        regs->regs[ 6] = (unsigned long) &frame->rs_uc;
 140        regs->regs[29] = (unsigned long) frame;
 141        regs->regs[31] = (unsigned long) sig_return;
 142        regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
 143
 144        DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
 145               current->comm, current->pid,
 146               frame, regs->cp0_epc, regs->regs[31]);
 147
 148        return 0;
 149}
 150
 151struct mips_abi mips_abi_n32 = {
 152        .setup_rt_frame = setup_rt_frame_n32,
 153        .restart        = __NR_N32_restart_syscall,
 154
 155        .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
 156        .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
 157        .off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
 158
 159        .vdso           = &vdso_image_n32,
 160};
 161