xref: /openbmc/linux/arch/s390/kernel/compat_signal.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
3a53c8fabSHeiko Carstens  *    Copyright IBM Corp. 2000, 2006
41da177e4SLinus Torvalds  *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
51da177e4SLinus Torvalds  *               Gerhard Tonn (ton@de.ibm.com)
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992  Linus Torvalds
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/compat.h>
131da177e4SLinus Torvalds #include <linux/sched.h>
1468db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
151da177e4SLinus Torvalds #include <linux/mm.h>
161da177e4SLinus Torvalds #include <linux/smp.h>
171da177e4SLinus Torvalds #include <linux/kernel.h>
181da177e4SLinus Torvalds #include <linux/signal.h>
191da177e4SLinus Torvalds #include <linux/errno.h>
201da177e4SLinus Torvalds #include <linux/wait.h>
211da177e4SLinus Torvalds #include <linux/ptrace.h>
221da177e4SLinus Torvalds #include <linux/unistd.h>
231da177e4SLinus Torvalds #include <linux/stddef.h>
241da177e4SLinus Torvalds #include <linux/tty.h>
251da177e4SLinus Torvalds #include <linux/personality.h>
261da177e4SLinus Torvalds #include <linux/binfmts.h>
271da177e4SLinus Torvalds #include <asm/ucontext.h>
287c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
291da177e4SLinus Torvalds #include <asm/lowcore.h>
30a0616cdeSDavid Howells #include <asm/switch_to.h>
31df29a744SSven Schnelle #include <asm/vdso.h>
321da177e4SLinus Torvalds #include "compat_linux.h"
331da177e4SLinus Torvalds #include "compat_ptrace.h"
34a806170eSHeiko Carstens #include "entry.h"
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds typedef struct
371da177e4SLinus Torvalds {
381da177e4SLinus Torvalds 	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
391da177e4SLinus Torvalds 	struct sigcontext32 sc;
401da177e4SLinus Torvalds 	_sigregs32 sregs;
411da177e4SLinus Torvalds 	int signo;
4280703617SMartin Schwidefsky 	_sigregs_ext32 sregs_ext;
4380703617SMartin Schwidefsky 	__u16 svc_insn;		/* Offset of svc_insn is NOT fixed! */
441da177e4SLinus Torvalds } sigframe32;
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds typedef struct
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds 	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
4980703617SMartin Schwidefsky 	__u16 svc_insn;
501da177e4SLinus Torvalds 	compat_siginfo_t info;
511da177e4SLinus Torvalds 	struct ucontext32 uc;
521da177e4SLinus Torvalds } rt_sigframe32;
531da177e4SLinus Torvalds 
5480703617SMartin Schwidefsky /* Store registers needed to create the signal frame */
store_sigregs(void)5580703617SMartin Schwidefsky static void store_sigregs(void)
5680703617SMartin Schwidefsky {
5780703617SMartin Schwidefsky 	save_access_regs(current->thread.acrs);
58d0164ee2SHendrik Brueckner 	save_fpu_regs();
5980703617SMartin Schwidefsky }
6080703617SMartin Schwidefsky 
6180703617SMartin Schwidefsky /* Load registers after signal return */
load_sigregs(void)6280703617SMartin Schwidefsky static void load_sigregs(void)
6380703617SMartin Schwidefsky {
6480703617SMartin Schwidefsky 	restore_access_regs(current->thread.acrs);
6580703617SMartin Schwidefsky }
6680703617SMartin Schwidefsky 
save_sigregs32(struct pt_regs * regs,_sigregs32 __user * sregs)671da177e4SLinus Torvalds static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
681da177e4SLinus Torvalds {
694725c860SMartin Schwidefsky 	_sigregs32 user_sregs;
704725c860SMartin Schwidefsky 	int i;
711da177e4SLinus Torvalds 
725ebf250dSHeiko Carstens 	user_sregs.regs.psw.mask = (__u32)(regs->psw.mask >> 32);
735ebf250dSHeiko Carstens 	user_sregs.regs.psw.mask &= PSW32_MASK_USER | PSW32_MASK_RI;
74f26946d7SHeiko Carstens 	user_sregs.regs.psw.mask |= PSW32_USER_BITS;
754725c860SMartin Schwidefsky 	user_sregs.regs.psw.addr = (__u32) regs->psw.addr |
76d4e81b35SMartin Schwidefsky 		(__u32)(regs->psw.mask & PSW_MASK_BA);
771da177e4SLinus Torvalds 	for (i = 0; i < NUM_GPRS; i++)
784725c860SMartin Schwidefsky 		user_sregs.regs.gprs[i] = (__u32) regs->gprs[i];
794725c860SMartin Schwidefsky 	memcpy(&user_sregs.regs.acrs, current->thread.acrs,
804725c860SMartin Schwidefsky 	       sizeof(user_sregs.regs.acrs));
81904818e2SHendrik Brueckner 	fpregs_store((_s390_fp_regs *) &user_sregs.fpregs, &current->thread.fpu);
824725c860SMartin Schwidefsky 	if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs32)))
83f8544ec4SHeiko Carstens 		return -EFAULT;
84f8544ec4SHeiko Carstens 	return 0;
851da177e4SLinus Torvalds }
861da177e4SLinus Torvalds 
restore_sigregs32(struct pt_regs * regs,_sigregs32 __user * sregs)871da177e4SLinus Torvalds static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
881da177e4SLinus Torvalds {
894725c860SMartin Schwidefsky 	_sigregs32 user_sregs;
904725c860SMartin Schwidefsky 	int i;
911da177e4SLinus Torvalds 
920ecf337fSHeiko Carstens 	/* Always make any pending restarted system call return -EINTR */
93f56141e3SAndy Lutomirski 	current->restart_block.fn = do_no_restart_syscall;
941da177e4SLinus Torvalds 
954725c860SMartin Schwidefsky 	if (__copy_from_user(&user_sregs, &sregs->regs, sizeof(user_sregs)))
96f8544ec4SHeiko Carstens 		return -EFAULT;
974725c860SMartin Schwidefsky 
985ebf250dSHeiko Carstens 	if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW32_MASK_RI))
995ebf250dSHeiko Carstens 		return -EINVAL;
1005ebf250dSHeiko Carstens 
1014084eb77SHendrik Brueckner 	/* Test the floating-point-control word. */
1024084eb77SHendrik Brueckner 	if (test_fp_ctl(user_sregs.fpregs.fpc))
1034725c860SMartin Schwidefsky 		return -EINVAL;
1044725c860SMartin Schwidefsky 
1054725c860SMartin Schwidefsky 	/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
106aa7e04b3SHendrik Brueckner 	regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) |
1074725c860SMartin Schwidefsky 		(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_USER) << 32 |
1085ebf250dSHeiko Carstens 		(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_RI) << 32 |
1094725c860SMartin Schwidefsky 		(__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_AMODE);
110fa968ee2SMartin Schwidefsky 	/* Check for invalid user address space control. */
111e258d719SMartin Schwidefsky 	if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME)
112e258d719SMartin Schwidefsky 		regs->psw.mask = PSW_ASC_PRIMARY |
113fa968ee2SMartin Schwidefsky 			(regs->psw.mask & ~PSW_MASK_ASC);
1144725c860SMartin Schwidefsky 	regs->psw.addr = (__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_INSN);
1151da177e4SLinus Torvalds 	for (i = 0; i < NUM_GPRS; i++)
1164725c860SMartin Schwidefsky 		regs->gprs[i] = (__u64) user_sregs.regs.gprs[i];
1174725c860SMartin Schwidefsky 	memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
1184725c860SMartin Schwidefsky 	       sizeof(current->thread.acrs));
119904818e2SHendrik Brueckner 	fpregs_load((_s390_fp_regs *) &user_sregs.fpregs, &current->thread.fpu);
1201da177e4SLinus Torvalds 
121d3a73acbSMartin Schwidefsky 	clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
1221da177e4SLinus Torvalds 	return 0;
1231da177e4SLinus Torvalds }
1241da177e4SLinus Torvalds 
save_sigregs_ext32(struct pt_regs * regs,_sigregs_ext32 __user * sregs_ext)12580703617SMartin Schwidefsky static int save_sigregs_ext32(struct pt_regs *regs,
12680703617SMartin Schwidefsky 			      _sigregs_ext32 __user *sregs_ext)
127ea2a4d3aSHeiko Carstens {
128ea2a4d3aSHeiko Carstens 	__u32 gprs_high[NUM_GPRS];
12980703617SMartin Schwidefsky 	__u64 vxrs[__NUM_VXRS_LOW];
130ea2a4d3aSHeiko Carstens 	int i;
131ea2a4d3aSHeiko Carstens 
13280703617SMartin Schwidefsky 	/* Save high gprs to signal stack */
133ea2a4d3aSHeiko Carstens 	for (i = 0; i < NUM_GPRS; i++)
134ea2a4d3aSHeiko Carstens 		gprs_high[i] = regs->gprs[i] >> 32;
13580703617SMartin Schwidefsky 	if (__copy_to_user(&sregs_ext->gprs_high, &gprs_high,
13680703617SMartin Schwidefsky 			   sizeof(sregs_ext->gprs_high)))
137f8544ec4SHeiko Carstens 		return -EFAULT;
13880703617SMartin Schwidefsky 
13980703617SMartin Schwidefsky 	/* Save vector registers to signal stack */
140b5510d9bSHendrik Brueckner 	if (MACHINE_HAS_VX) {
14180703617SMartin Schwidefsky 		for (i = 0; i < __NUM_VXRS_LOW; i++)
142*a02d584eSHeiko Carstens 			vxrs[i] = current->thread.fpu.vxrs[i].low;
14380703617SMartin Schwidefsky 		if (__copy_to_user(&sregs_ext->vxrs_low, vxrs,
14480703617SMartin Schwidefsky 				   sizeof(sregs_ext->vxrs_low)) ||
14580703617SMartin Schwidefsky 		    __copy_to_user(&sregs_ext->vxrs_high,
146904818e2SHendrik Brueckner 				   current->thread.fpu.vxrs + __NUM_VXRS_LOW,
14780703617SMartin Schwidefsky 				   sizeof(sregs_ext->vxrs_high)))
14880703617SMartin Schwidefsky 			return -EFAULT;
14980703617SMartin Schwidefsky 	}
150f8544ec4SHeiko Carstens 	return 0;
151ea2a4d3aSHeiko Carstens }
152ea2a4d3aSHeiko Carstens 
restore_sigregs_ext32(struct pt_regs * regs,_sigregs_ext32 __user * sregs_ext)15380703617SMartin Schwidefsky static int restore_sigregs_ext32(struct pt_regs *regs,
15480703617SMartin Schwidefsky 				 _sigregs_ext32 __user *sregs_ext)
155ea2a4d3aSHeiko Carstens {
156ea2a4d3aSHeiko Carstens 	__u32 gprs_high[NUM_GPRS];
15780703617SMartin Schwidefsky 	__u64 vxrs[__NUM_VXRS_LOW];
158f8544ec4SHeiko Carstens 	int i;
159ea2a4d3aSHeiko Carstens 
16080703617SMartin Schwidefsky 	/* Restore high gprs from signal stack */
16180703617SMartin Schwidefsky 	if (__copy_from_user(&gprs_high, &sregs_ext->gprs_high,
162342300ccSMartin Schwidefsky 			     sizeof(sregs_ext->gprs_high)))
163f8544ec4SHeiko Carstens 		return -EFAULT;
164ea2a4d3aSHeiko Carstens 	for (i = 0; i < NUM_GPRS; i++)
165ea2a4d3aSHeiko Carstens 		*(__u32 *)&regs->gprs[i] = gprs_high[i];
16680703617SMartin Schwidefsky 
16780703617SMartin Schwidefsky 	/* Restore vector registers from signal stack */
168b5510d9bSHendrik Brueckner 	if (MACHINE_HAS_VX) {
16980703617SMartin Schwidefsky 		if (__copy_from_user(vxrs, &sregs_ext->vxrs_low,
17080703617SMartin Schwidefsky 				     sizeof(sregs_ext->vxrs_low)) ||
171904818e2SHendrik Brueckner 		    __copy_from_user(current->thread.fpu.vxrs + __NUM_VXRS_LOW,
17280703617SMartin Schwidefsky 				     &sregs_ext->vxrs_high,
17380703617SMartin Schwidefsky 				     sizeof(sregs_ext->vxrs_high)))
17480703617SMartin Schwidefsky 			return -EFAULT;
17580703617SMartin Schwidefsky 		for (i = 0; i < __NUM_VXRS_LOW; i++)
176*a02d584eSHeiko Carstens 			current->thread.fpu.vxrs[i].low = vxrs[i];
17780703617SMartin Schwidefsky 	}
178ea2a4d3aSHeiko Carstens 	return 0;
179ea2a4d3aSHeiko Carstens }
180ea2a4d3aSHeiko Carstens 
COMPAT_SYSCALL_DEFINE0(sigreturn)1815b098c20SHeiko Carstens COMPAT_SYSCALL_DEFINE0(sigreturn)
1821da177e4SLinus Torvalds {
18303ff9a23SMartin Schwidefsky 	struct pt_regs *regs = task_pt_regs(current);
1841da177e4SLinus Torvalds 	sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
1851da177e4SLinus Torvalds 	sigset_t set;
1861da177e4SLinus Torvalds 
187c60a03feSAl Viro 	if (get_compat_sigset(&set, (compat_sigset_t __user *)frame->sc.oldmask))
1881da177e4SLinus Torvalds 		goto badframe;
189391c62feSHeiko Carstens 	set_current_blocked(&set);
190d0164ee2SHendrik Brueckner 	save_fpu_regs();
1911da177e4SLinus Torvalds 	if (restore_sigregs32(regs, &frame->sregs))
1921da177e4SLinus Torvalds 		goto badframe;
19380703617SMartin Schwidefsky 	if (restore_sigregs_ext32(regs, &frame->sregs_ext))
194ea2a4d3aSHeiko Carstens 		goto badframe;
19580703617SMartin Schwidefsky 	load_sigregs();
1961da177e4SLinus Torvalds 	return regs->gprs[2];
1971da177e4SLinus Torvalds badframe:
1983cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
1991da177e4SLinus Torvalds 	return 0;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds 
COMPAT_SYSCALL_DEFINE0(rt_sigreturn)2025b098c20SHeiko Carstens COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
2031da177e4SLinus Torvalds {
20403ff9a23SMartin Schwidefsky 	struct pt_regs *regs = task_pt_regs(current);
2051da177e4SLinus Torvalds 	rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
2061da177e4SLinus Torvalds 	sigset_t set;
2071da177e4SLinus Torvalds 
208c60a03feSAl Viro 	if (get_compat_sigset(&set, &frame->uc.uc_sigmask))
2091da177e4SLinus Torvalds 		goto badframe;
210391c62feSHeiko Carstens 	set_current_blocked(&set);
211e214125aSAl Viro 	if (compat_restore_altstack(&frame->uc.uc_stack))
2121da177e4SLinus Torvalds 		goto badframe;
213d0164ee2SHendrik Brueckner 	save_fpu_regs();
21480703617SMartin Schwidefsky 	if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
21580703617SMartin Schwidefsky 		goto badframe;
21680703617SMartin Schwidefsky 	if (restore_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
21780703617SMartin Schwidefsky 		goto badframe;
21880703617SMartin Schwidefsky 	load_sigregs();
2191da177e4SLinus Torvalds 	return regs->gprs[2];
2201da177e4SLinus Torvalds badframe:
2213cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
2221da177e4SLinus Torvalds 	return 0;
2231da177e4SLinus Torvalds }
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds /*
2261da177e4SLinus Torvalds  * Set up a signal frame.
2271da177e4SLinus Torvalds  */
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds /*
2311da177e4SLinus Torvalds  * Determine which stack to use..
2321da177e4SLinus Torvalds  */
2331da177e4SLinus Torvalds static inline void __user *
get_sigframe(struct k_sigaction * ka,struct pt_regs * regs,size_t frame_size)2341da177e4SLinus Torvalds get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
2351da177e4SLinus Torvalds {
2361da177e4SLinus Torvalds 	unsigned long sp;
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 	/* Default to using normal stack */
2391da177e4SLinus Torvalds 	sp = (unsigned long) A(regs->gprs[15]);
2401da177e4SLinus Torvalds 
241de553438SHeiko Carstens 	/* Overflow on alternate signal stack gives SIGSEGV. */
242de553438SHeiko Carstens 	if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
243de553438SHeiko Carstens 		return (void __user *) -1UL;
244de553438SHeiko Carstens 
2451da177e4SLinus Torvalds 	/* This is the X/Open sanctioned signal stack switching.  */
2461da177e4SLinus Torvalds 	if (ka->sa.sa_flags & SA_ONSTACK) {
24728f22378SLaurent Meyer 		if (! sas_ss_flags(sp))
2481da177e4SLinus Torvalds 			sp = current->sas_ss_sp + current->sas_ss_size;
2491da177e4SLinus Torvalds 	}
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	return (void __user *)((sp - frame_size) & -8ul);
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
setup_frame32(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)254067bf2d4SRichard Weinberger static int setup_frame32(struct ksignal *ksig, sigset_t *set,
255067bf2d4SRichard Weinberger 			 struct pt_regs *regs)
2561da177e4SLinus Torvalds {
257067bf2d4SRichard Weinberger 	int sig = ksig->sig;
25880703617SMartin Schwidefsky 	sigframe32 __user *frame;
25980703617SMartin Schwidefsky 	unsigned long restorer;
26080703617SMartin Schwidefsky 	size_t frame_size;
2611da177e4SLinus Torvalds 
26280703617SMartin Schwidefsky 	/*
26380703617SMartin Schwidefsky 	 * gprs_high are always present for 31-bit compat tasks.
26480703617SMartin Schwidefsky 	 * The space for vector registers is only allocated if
26580703617SMartin Schwidefsky 	 * the machine supports it
26680703617SMartin Schwidefsky 	 */
26780703617SMartin Schwidefsky 	frame_size = sizeof(*frame) - sizeof(frame->sregs_ext.__reserved);
26880703617SMartin Schwidefsky 	if (!MACHINE_HAS_VX)
26980703617SMartin Schwidefsky 		frame_size -= sizeof(frame->sregs_ext.vxrs_low) +
27080703617SMartin Schwidefsky 			      sizeof(frame->sregs_ext.vxrs_high);
27180703617SMartin Schwidefsky 	frame = get_sigframe(&ksig->ka, regs, frame_size);
272de553438SHeiko Carstens 	if (frame == (void __user *) -1UL)
273067bf2d4SRichard Weinberger 		return -EFAULT;
274de553438SHeiko Carstens 
2751da177e4SLinus Torvalds 	/* Set up backchain. */
2761da177e4SLinus Torvalds 	if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
277067bf2d4SRichard Weinberger 		return -EFAULT;
2781da177e4SLinus Torvalds 
27980703617SMartin Schwidefsky 	/* Create struct sigcontext32 on the signal stack */
280c60a03feSAl Viro 	if (put_compat_sigset((compat_sigset_t __user *)frame->sc.oldmask,
281c60a03feSAl Viro 			      set, sizeof(compat_sigset_t)))
282c60a03feSAl Viro 		return -EFAULT;
2838b09ca74SHeiko Carstens 	if (__put_user(ptr_to_compat(&frame->sregs), &frame->sc.sregs))
28480703617SMartin Schwidefsky 		return -EFAULT;
28580703617SMartin Schwidefsky 
28680703617SMartin Schwidefsky 	/* Store registers needed to create the signal frame */
28780703617SMartin Schwidefsky 	store_sigregs();
28880703617SMartin Schwidefsky 
28980703617SMartin Schwidefsky 	/* Create _sigregs32 on the signal stack */
29080703617SMartin Schwidefsky 	if (save_sigregs32(regs, &frame->sregs))
29180703617SMartin Schwidefsky 		return -EFAULT;
29280703617SMartin Schwidefsky 
29380703617SMartin Schwidefsky 	/* Place signal number on stack to allow backtrace from handler.  */
29480703617SMartin Schwidefsky 	if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
29580703617SMartin Schwidefsky 		return -EFAULT;
29680703617SMartin Schwidefsky 
29780703617SMartin Schwidefsky 	/* Create _sigregs_ext32 on the signal stack */
29880703617SMartin Schwidefsky 	if (save_sigregs_ext32(regs, &frame->sregs_ext))
29980703617SMartin Schwidefsky 		return -EFAULT;
30080703617SMartin Schwidefsky 
30180703617SMartin Schwidefsky 	/* Set up to return from userspace.  If provided, use a stub
30280703617SMartin Schwidefsky 	   already in userspace.  */
30380703617SMartin Schwidefsky 	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
30480703617SMartin Schwidefsky 		restorer = (unsigned long __force)
30580703617SMartin Schwidefsky 			ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
30680703617SMartin Schwidefsky 	} else {
307df29a744SSven Schnelle 		restorer = VDSO32_SYMBOL(current, sigreturn);
30880703617SMartin Schwidefsky         }
30980703617SMartin Schwidefsky 
3101da177e4SLinus Torvalds 	/* Set up registers for signal handler */
31180703617SMartin Schwidefsky 	regs->gprs[14] = restorer;
3123c52e49dSMartin Schwidefsky 	regs->gprs[15] = (__force __u64) frame;
313fa968ee2SMartin Schwidefsky 	/* Force 31 bit amode and default user address space control. */
314fa968ee2SMartin Schwidefsky 	regs->psw.mask = PSW_MASK_BA |
315e258d719SMartin Schwidefsky 		(PSW_USER_BITS & PSW_MASK_ASC) |
316fa968ee2SMartin Schwidefsky 		(regs->psw.mask & ~PSW_MASK_ASC);
317067bf2d4SRichard Weinberger 	regs->psw.addr = (__force __u64) ksig->ka.sa.sa_handler;
3181da177e4SLinus Torvalds 
3196a32591aSRichard Weinberger 	regs->gprs[2] = sig;
3203c52e49dSMartin Schwidefsky 	regs->gprs[3] = (__force __u64) &frame->sc;
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 	/* We forgot to include these in the sigcontext.
3231da177e4SLinus Torvalds 	   To avoid breaking binary compatibility, they are passed as args. */
324aa33c8cbSMartin Schwidefsky 	if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
325aa33c8cbSMartin Schwidefsky 	    sig == SIGTRAP || sig == SIGFPE) {
326aa33c8cbSMartin Schwidefsky 		/* set extra registers only for synchronous signals */
327aa33c8cbSMartin Schwidefsky 		regs->gprs[4] = regs->int_code & 127;
328aa33c8cbSMartin Schwidefsky 		regs->gprs[5] = regs->int_parm_long;
329ef280c85SMartin Schwidefsky 		regs->gprs[6] = current->thread.last_break;
330aa33c8cbSMartin Schwidefsky 	}
3311da177e4SLinus Torvalds 
332067bf2d4SRichard Weinberger 	return 0;
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
setup_rt_frame32(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)335067bf2d4SRichard Weinberger static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set,
336067bf2d4SRichard Weinberger 			    struct pt_regs *regs)
3371da177e4SLinus Torvalds {
33880703617SMartin Schwidefsky 	rt_sigframe32 __user *frame;
33980703617SMartin Schwidefsky 	unsigned long restorer;
34080703617SMartin Schwidefsky 	size_t frame_size;
34180703617SMartin Schwidefsky 	u32 uc_flags;
3421da177e4SLinus Torvalds 
34380703617SMartin Schwidefsky 	frame_size = sizeof(*frame) -
34480703617SMartin Schwidefsky 		     sizeof(frame->uc.uc_mcontext_ext.__reserved);
34580703617SMartin Schwidefsky 	/*
34680703617SMartin Schwidefsky 	 * gprs_high are always present for 31-bit compat tasks.
34780703617SMartin Schwidefsky 	 * The space for vector registers is only allocated if
34880703617SMartin Schwidefsky 	 * the machine supports it
34980703617SMartin Schwidefsky 	 */
35080703617SMartin Schwidefsky 	uc_flags = UC_GPRS_HIGH;
35180703617SMartin Schwidefsky 	if (MACHINE_HAS_VX) {
35280703617SMartin Schwidefsky 		uc_flags |= UC_VXRS;
35380703617SMartin Schwidefsky 	} else
35480703617SMartin Schwidefsky 		frame_size -= sizeof(frame->uc.uc_mcontext_ext.vxrs_low) +
35580703617SMartin Schwidefsky 			      sizeof(frame->uc.uc_mcontext_ext.vxrs_high);
35680703617SMartin Schwidefsky 	frame = get_sigframe(&ksig->ka, regs, frame_size);
357de553438SHeiko Carstens 	if (frame == (void __user *) -1UL)
358067bf2d4SRichard Weinberger 		return -EFAULT;
359de553438SHeiko Carstens 
3601da177e4SLinus Torvalds 	/* Set up backchain. */
3613c52e49dSMartin Schwidefsky 	if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
362067bf2d4SRichard Weinberger 		return -EFAULT;
3631da177e4SLinus Torvalds 
36480703617SMartin Schwidefsky 	/* Set up to return from userspace.  If provided, use a stub
36580703617SMartin Schwidefsky 	   already in userspace.  */
36680703617SMartin Schwidefsky 	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
36780703617SMartin Schwidefsky 		restorer = (unsigned long __force)
36880703617SMartin Schwidefsky 			ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
36980703617SMartin Schwidefsky 	} else {
370df29a744SSven Schnelle 		restorer = VDSO32_SYMBOL(current, rt_sigreturn);
37180703617SMartin Schwidefsky 	}
37280703617SMartin Schwidefsky 
37380703617SMartin Schwidefsky 	/* Create siginfo on the signal stack */
37480703617SMartin Schwidefsky 	if (copy_siginfo_to_user32(&frame->info, &ksig->info))
37580703617SMartin Schwidefsky 		return -EFAULT;
37680703617SMartin Schwidefsky 
37780703617SMartin Schwidefsky 	/* Store registers needed to create the signal frame */
37880703617SMartin Schwidefsky 	store_sigregs();
37980703617SMartin Schwidefsky 
38080703617SMartin Schwidefsky 	/* Create ucontext on the signal stack. */
38180703617SMartin Schwidefsky 	if (__put_user(uc_flags, &frame->uc.uc_flags) ||
38280703617SMartin Schwidefsky 	    __put_user(0, &frame->uc.uc_link) ||
38380703617SMartin Schwidefsky 	    __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
38480703617SMartin Schwidefsky 	    save_sigregs32(regs, &frame->uc.uc_mcontext) ||
385c60a03feSAl Viro 	    put_compat_sigset(&frame->uc.uc_sigmask, set, sizeof(compat_sigset_t)) ||
38680703617SMartin Schwidefsky 	    save_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
38780703617SMartin Schwidefsky 		return -EFAULT;
38880703617SMartin Schwidefsky 
3891da177e4SLinus Torvalds 	/* Set up registers for signal handler */
39080703617SMartin Schwidefsky 	regs->gprs[14] = restorer;
3913c52e49dSMartin Schwidefsky 	regs->gprs[15] = (__force __u64) frame;
392fa968ee2SMartin Schwidefsky 	/* Force 31 bit amode and default user address space control. */
393fa968ee2SMartin Schwidefsky 	regs->psw.mask = PSW_MASK_BA |
394e258d719SMartin Schwidefsky 		(PSW_USER_BITS & PSW_MASK_ASC) |
395fa968ee2SMartin Schwidefsky 		(regs->psw.mask & ~PSW_MASK_ASC);
396067bf2d4SRichard Weinberger 	regs->psw.addr = (__u64 __force) ksig->ka.sa.sa_handler;
3971da177e4SLinus Torvalds 
3986a32591aSRichard Weinberger 	regs->gprs[2] = ksig->sig;
3993c52e49dSMartin Schwidefsky 	regs->gprs[3] = (__force __u64) &frame->info;
4003c52e49dSMartin Schwidefsky 	regs->gprs[4] = (__force __u64) &frame->uc;
401ef280c85SMartin Schwidefsky 	regs->gprs[5] = current->thread.last_break;
40254dfe5ddSHeiko Carstens 	return 0;
4031da177e4SLinus Torvalds }
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds /*
4061da177e4SLinus Torvalds  * OK, we're invoking a handler
4071da177e4SLinus Torvalds  */
4081da177e4SLinus Torvalds 
handle_signal32(struct ksignal * ksig,sigset_t * oldset,struct pt_regs * regs)409067bf2d4SRichard Weinberger void handle_signal32(struct ksignal *ksig, sigset_t *oldset,
410067bf2d4SRichard Weinberger 		     struct pt_regs *regs)
4111da177e4SLinus Torvalds {
41254dfe5ddSHeiko Carstens 	int ret;
41354dfe5ddSHeiko Carstens 
4141da177e4SLinus Torvalds 	/* Set up the stack frame */
415067bf2d4SRichard Weinberger 	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
416067bf2d4SRichard Weinberger 		ret = setup_rt_frame32(ksig, oldset, regs);
4171da177e4SLinus Torvalds 	else
418067bf2d4SRichard Weinberger 		ret = setup_frame32(ksig, oldset, regs);
419067bf2d4SRichard Weinberger 
420067bf2d4SRichard Weinberger 	signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLE_STEP));
42154dfe5ddSHeiko Carstens }
4221da177e4SLinus Torvalds 
423