11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (C) 2003 Broadcom Corporation 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 51da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 61da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 2 71da177e4SLinus Torvalds * of the License, or (at your option) any later version. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 101da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 111da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 121da177e4SLinus Torvalds * GNU General Public License for more details. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 151da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 161da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 171da177e4SLinus Torvalds */ 1802416dcfSRalf Baechle #include <linux/cache.h> 1902416dcfSRalf Baechle #include <linux/sched.h> 201da177e4SLinus Torvalds #include <linux/mm.h> 211da177e4SLinus Torvalds #include <linux/smp.h> 221da177e4SLinus Torvalds #include <linux/kernel.h> 231da177e4SLinus Torvalds #include <linux/signal.h> 241da177e4SLinus Torvalds #include <linux/errno.h> 251da177e4SLinus Torvalds #include <linux/wait.h> 261da177e4SLinus Torvalds #include <linux/ptrace.h> 271da177e4SLinus Torvalds #include <linux/unistd.h> 281da177e4SLinus Torvalds #include <linux/compat.h> 291da177e4SLinus Torvalds #include <linux/bitops.h> 301da177e4SLinus Torvalds 31151fd6acSRalf Baechle #include <asm/abi.h> 321da177e4SLinus Torvalds #include <asm/asm.h> 331da177e4SLinus Torvalds #include <asm/cacheflush.h> 34431dc804SRalf Baechle #include <asm/compat-signal.h> 351da177e4SLinus Torvalds #include <asm/sim.h> 367c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 371da177e4SLinus Torvalds #include <asm/ucontext.h> 381da177e4SLinus Torvalds #include <asm/fpu.h> 391da177e4SLinus Torvalds #include <asm/cpu-features.h> 4002416dcfSRalf Baechle #include <asm/war.h> 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds #include "signal-common.h" 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* 451da177e4SLinus Torvalds * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 461da177e4SLinus Torvalds */ 471da177e4SLinus Torvalds #define __NR_N32_restart_syscall 6214 481da177e4SLinus Torvalds 49205d84aaSRalf Baechle extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); 50205d84aaSRalf Baechle extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); 51205d84aaSRalf Baechle 521da177e4SLinus Torvalds struct ucontextn32 { 531da177e4SLinus Torvalds u32 uc_flags; 541da177e4SLinus Torvalds s32 uc_link; 55ea536ad4SAl Viro compat_stack_t uc_stack; 561da177e4SLinus Torvalds struct sigcontext uc_mcontext; 57431dc804SRalf Baechle compat_sigset_t uc_sigmask; /* mask last for extensibility */ 581da177e4SLinus Torvalds }; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds struct rt_sigframe_n32 { 611da177e4SLinus Torvalds u32 rs_ass[4]; /* argument save space for o32 */ 62d814c28cSDavid Daney u32 rs_pad[2]; /* Was: signal trampoline */ 63a76f3a41SPavel Kiryukhin struct compat_siginfo rs_info; 641da177e4SLinus Torvalds struct ucontextn32 rs_uc; 651da177e4SLinus Torvalds }; 661da177e4SLinus Torvalds 6796a68b14SPaul Burton asmlinkage void sysn32_rt_sigreturn(void) 681da177e4SLinus Torvalds { 699bbf28a3SAtsushi Nemoto struct rt_sigframe_n32 __user *frame; 7096a68b14SPaul Burton struct pt_regs *regs; 711da177e4SLinus Torvalds sigset_t set; 72c6a2f467SAtsushi Nemoto int sig; 731da177e4SLinus Torvalds 7496a68b14SPaul Burton regs = current_pt_regs(); 7596a68b14SPaul Burton frame = (struct rt_sigframe_n32 __user *)regs->regs[29]; 7696d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame))) 771da177e4SLinus Torvalds goto badframe; 78431dc804SRalf Baechle if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) 791da177e4SLinus Torvalds goto badframe; 801da177e4SLinus Torvalds 818598f3cdSMatt Fleming set_current_blocked(&set); 821da177e4SLinus Torvalds 8396a68b14SPaul Burton sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); 84c6a2f467SAtsushi Nemoto if (sig < 0) 851da177e4SLinus Torvalds goto badframe; 86c6a2f467SAtsushi Nemoto else if (sig) 87*3cf5d076SEric W. Biederman force_sig(sig); 881da177e4SLinus Torvalds 89ea536ad4SAl Viro if (compat_restore_altstack(&frame->rs_uc.uc_stack)) 901da177e4SLinus Torvalds goto badframe; 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds /* 931da177e4SLinus Torvalds * Don't let your children do this ... 941da177e4SLinus Torvalds */ 951da177e4SLinus Torvalds __asm__ __volatile__( 961da177e4SLinus Torvalds "move\t$29, %0\n\t" 971da177e4SLinus Torvalds "j\tsyscall_exit" 981da177e4SLinus Torvalds : /* no outputs */ 9996a68b14SPaul Burton : "r" (regs)); 1001da177e4SLinus Torvalds /* Unreached */ 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds badframe: 103*3cf5d076SEric W. Biederman force_sig(SIGSEGV); 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 10681d103bfSRichard Weinberger static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig, 10781d103bfSRichard Weinberger struct pt_regs *regs, sigset_t *set) 1081da177e4SLinus Torvalds { 1099bbf28a3SAtsushi Nemoto struct rt_sigframe_n32 __user *frame; 1101da177e4SLinus Torvalds int err = 0; 1111da177e4SLinus Torvalds 1127c4f5635SRichard Weinberger frame = get_sigframe(ksig, regs, sizeof(*frame)); 11396d4f267SLinus Torvalds if (!access_ok(frame, sizeof (*frame))) 11481d103bfSRichard Weinberger return -EFAULT; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* Create siginfo. */ 11781d103bfSRichard Weinberger err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info); 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /* Create the ucontext. */ 1201da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_flags); 1211da177e4SLinus Torvalds err |= __put_user(0, &frame->rs_uc.uc_link); 122ea536ad4SAl Viro err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); 1231da177e4SLinus Torvalds err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); 124431dc804SRalf Baechle err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds if (err) 12781d103bfSRichard Weinberger return -EFAULT; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds /* 1301da177e4SLinus Torvalds * Arguments to signal handler: 1311da177e4SLinus Torvalds * 1321da177e4SLinus Torvalds * a0 = signal number 1331da177e4SLinus Torvalds * a1 = 0 (should be cause) 1341da177e4SLinus Torvalds * a2 = pointer to ucontext 1351da177e4SLinus Torvalds * 1361da177e4SLinus Torvalds * $25 and c0_epc point to the signal handler, $29 points to 1371da177e4SLinus Torvalds * the struct rt_sigframe. 1381da177e4SLinus Torvalds */ 13981d103bfSRichard Weinberger regs->regs[ 4] = ksig->sig; 1401da177e4SLinus Torvalds regs->regs[ 5] = (unsigned long) &frame->rs_info; 1411da177e4SLinus Torvalds regs->regs[ 6] = (unsigned long) &frame->rs_uc; 1421da177e4SLinus Torvalds regs->regs[29] = (unsigned long) frame; 143d814c28cSDavid Daney regs->regs[31] = (unsigned long) sig_return; 14481d103bfSRichard Weinberger regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; 1451da177e4SLinus Torvalds 146722bb63dSFranck Bui-Huu DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", 1471da177e4SLinus Torvalds current->comm, current->pid, 1481da177e4SLinus Torvalds frame, regs->cp0_epc, regs->regs[31]); 149722bb63dSFranck Bui-Huu 1507b3e2fc8SRalf Baechle return 0; 1511da177e4SLinus Torvalds } 152151fd6acSRalf Baechle 153151fd6acSRalf Baechle struct mips_abi mips_abi_n32 = { 154151fd6acSRalf Baechle .setup_rt_frame = setup_rt_frame_n32, 15577856100SPaul Burton .restart = __NR_N32_restart_syscall, 15677856100SPaul Burton 15777856100SPaul Burton .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), 15877856100SPaul Burton .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), 15977856100SPaul Burton .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), 160ebb5e78cSAlex Smith 161ebb5e78cSAlex Smith .vdso = &vdso_image_n32, 162151fd6acSRalf Baechle }; 163