11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2a53c8fab3f87c995c30ac226a03af95361243144Heiko Carstens *    Copyright IBM Corp. 2000, 2006
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *               Gerhard Tonn (ton@de.ibm.com)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1991, 1992  Linus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/compat.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wait.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/unistd.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/personality.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/binfmts.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/ucontext.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/lowcore.h>
28a0616cdebcfd575dcd4c46102d1b52fbb827fc29David Howells#include <asm/switch_to.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "compat_linux.h"
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "compat_ptrace.h"
31a806170e29c5468b1d641a22518243bdf1b8d58bHeiko Carstens#include "entry.h"
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sigcontext32 sc;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_sigregs32 sregs;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int signo;
398070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	_sigregs_ext32 sregs_ext;
408070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	__u16 svc_insn;		/* Offset of svc_insn is NOT fixed! */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} sigframe32;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
468070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	__u16 svc_insn;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	compat_siginfo_t info;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ucontext32 uc;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} rt_sigframe32;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51ce3959604878c1c693979ec552069dc8bdb5ccdeAl Viroint copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If you change siginfo_t structure, please be sure
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   this code is fixed accordingly.
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   It should never copy any pad contained in the structure
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   to avoid security leaks, but must copy the generic
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   3 ints plus the relevant union member.
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   This routine must convert siginfo from 64bit to 32bit as well
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   at the same time.  */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = __put_user(from->si_signo, &to->si_signo);
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __put_user(from->si_errno, &to->si_errno);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __put_user((short)from->si_code, &to->si_code);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (from->si_code < 0)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (from->si_code >> 16) {
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_MESGQ >> 16:
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_int, &to->si_int);
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* fallthrough */
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_KILL >> 16:
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_pid, &to->si_pid);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_uid, &to->si_uid);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_CHLD >> 16:
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_pid, &to->si_pid);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_uid, &to->si_uid);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_utime, &to->si_utime);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_stime, &to->si_stime);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_status, &to->si_status);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_FAULT >> 16:
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user((unsigned long) from->si_addr,
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  &to->si_addr);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_POLL >> 16:
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_band, &to->si_band);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_fd, &to->si_fd);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_TIMER >> 16:
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_tid, &to->si_tid);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_overrun, &to->si_overrun);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __put_user(from->si_int, &to->si_int);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1010ebfd313fd4baf3fa1bd02d5f106e377595d4987Heiko Carstens	return err ? -EFAULT : 0;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 tmp;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = __get_user(to->si_signo, &from->si_signo);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __get_user(to->si_errno, &from->si_errno);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err |= __get_user(to->si_code, &from->si_code);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (to->si_code < 0)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (to->si_code >> 16) {
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_MESGQ >> 16:
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_int, &from->si_int);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* fallthrough */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_KILL >> 16:
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_pid, &from->si_pid);
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_uid, &from->si_uid);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_CHLD >> 16:
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_pid, &from->si_pid);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_uid, &from->si_uid);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_utime, &from->si_utime);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_stime, &from->si_stime);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_status, &from->si_status);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_FAULT >> 16:
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(tmp, &from->si_addr);
1343c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky			to->si_addr = (void __force __user *)
1353c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky				(u64) (tmp & PSW32_ADDR_INSN);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_POLL >> 16:
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_band, &from->si_band);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_fd, &from->si_fd);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case __SI_TIMER >> 16:
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_tid, &from->si_tid);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_overrun, &from->si_overrun);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err |= __get_user(to->si_int, &from->si_int);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1500ebfd313fd4baf3fa1bd02d5f106e377595d4987Heiko Carstens	return err ? -EFAULT : 0;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1538070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky/* Store registers needed to create the signal frame */
1548070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefskystatic void store_sigregs(void)
1558070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky{
1568070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	int i;
1578070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
1588070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	save_access_regs(current->thread.acrs);
1598070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	save_fp_ctl(&current->thread.fp_regs.fpc);
1608070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (current->thread.vxrs) {
1618070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		save_vx_regs(current->thread.vxrs);
1628070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		for (i = 0; i < __NUM_FPRS; i++)
1638070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			current->thread.fp_regs.fprs[i] =
1648070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				*(freg_t *)(current->thread.vxrs + i);
1658070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	} else
1668070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		save_fp_regs(current->thread.fp_regs.fprs);
1678070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky}
1688070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
1698070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky/* Load registers after signal return */
1708070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefskystatic void load_sigregs(void)
1718070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky{
1728070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	int i;
1738070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
1748070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	restore_access_regs(current->thread.acrs);
1758070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* restore_fp_ctl is done in restore_sigregs */
1768070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (current->thread.vxrs) {
1778070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		for (i = 0; i < __NUM_FPRS; i++)
1788070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			*(freg_t *)(current->thread.vxrs + i) =
1798070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				current->thread.fp_regs.fprs[i];
1808070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		restore_vx_regs(current->thread.vxrs);
1818070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	} else
1828070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		restore_fp_regs(current->thread.fp_regs.fprs);
1838070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky}
1848070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1874725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	_sigregs32 user_sregs;
1884725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	int i;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1905ebf250dabbae83ad875f0dda5a108503cf78f3bHeiko Carstens	user_sregs.regs.psw.mask = (__u32)(regs->psw.mask >> 32);
1915ebf250dabbae83ad875f0dda5a108503cf78f3bHeiko Carstens	user_sregs.regs.psw.mask &= PSW32_MASK_USER | PSW32_MASK_RI;
192f26946d7ecad0afdd85e6ae56663d0fe26676b34Heiko Carstens	user_sregs.regs.psw.mask |= PSW32_USER_BITS;
1934725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	user_sregs.regs.psw.addr = (__u32) regs->psw.addr |
194d4e81b35b882d96f059afdb0f98e5b6025973b09Martin Schwidefsky		(__u32)(regs->psw.mask & PSW_MASK_BA);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NUM_GPRS; i++)
1964725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky		user_sregs.regs.gprs[i] = (__u32) regs->gprs[i];
1974725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	memcpy(&user_sregs.regs.acrs, current->thread.acrs,
1984725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	       sizeof(user_sregs.regs.acrs));
1994725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	memcpy(&user_sregs.fpregs, &current->thread.fp_regs,
2004725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	       sizeof(user_sregs.fpregs));
2014725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs32)))
202f8544ec4f49ffb9cb93419e41f0d8c0fb39eb78fHeiko Carstens		return -EFAULT;
203f8544ec4f49ffb9cb93419e41f0d8c0fb39eb78fHeiko Carstens	return 0;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2084725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	_sigregs32 user_sregs;
2094725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	int i;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Alwys make any pending restarted system call return -EINTR */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	current_thread_info()->restart_block.fn = do_no_restart_syscall;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2144725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	if (__copy_from_user(&user_sregs, &sregs->regs, sizeof(user_sregs)))
215f8544ec4f49ffb9cb93419e41f0d8c0fb39eb78fHeiko Carstens		return -EFAULT;
2164725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky
2175ebf250dabbae83ad875f0dda5a108503cf78f3bHeiko Carstens	if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW32_MASK_RI))
2185ebf250dabbae83ad875f0dda5a108503cf78f3bHeiko Carstens		return -EINVAL;
2195ebf250dabbae83ad875f0dda5a108503cf78f3bHeiko Carstens
2204725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	/* Loading the floating-point-control word can fail. Do that first. */
2214725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	if (restore_fp_ctl(&user_sregs.fpregs.fpc))
2224725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky		return -EINVAL;
2234725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky
2244725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
225aa7e04b3808614980d474735cdb0bf35ac5cdf26Hendrik Brueckner	regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) |
2264725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky		(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_USER) << 32 |
2275ebf250dabbae83ad875f0dda5a108503cf78f3bHeiko Carstens		(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_RI) << 32 |
2284725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky		(__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_AMODE);
229fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	/* Check for invalid user address space control. */
230e258d719ff28ecc7a048eb8f78380e68c4b3a3f0Martin Schwidefsky	if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME)
231e258d719ff28ecc7a048eb8f78380e68c4b3a3f0Martin Schwidefsky		regs->psw.mask = PSW_ASC_PRIMARY |
232fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky			(regs->psw.mask & ~PSW_MASK_ASC);
2334725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	regs->psw.addr = (__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_INSN);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < NUM_GPRS; i++)
2354725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky		regs->gprs[i] = (__u64) user_sregs.regs.gprs[i];
2364725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
2374725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	       sizeof(current->thread.acrs));
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2394725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	memcpy(&current->thread.fp_regs, &user_sregs.fpregs,
2404725c86055f5bbdcdfe47199c0715881893a2c79Martin Schwidefsky	       sizeof(current->thread.fp_regs));
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
242d3a73acbc26a4a81a01a35fd162973e53d0386f5Martin Schwidefsky	clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2468070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefskystatic int save_sigregs_ext32(struct pt_regs *regs,
2478070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			      _sigregs_ext32 __user *sregs_ext)
248ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens{
249ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	__u32 gprs_high[NUM_GPRS];
2508070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	__u64 vxrs[__NUM_VXRS_LOW];
251ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	int i;
252ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
2538070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Save high gprs to signal stack */
254ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	for (i = 0; i < NUM_GPRS; i++)
255ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		gprs_high[i] = regs->gprs[i] >> 32;
2568070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (__copy_to_user(&sregs_ext->gprs_high, &gprs_high,
2578070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			   sizeof(sregs_ext->gprs_high)))
258f8544ec4f49ffb9cb93419e41f0d8c0fb39eb78fHeiko Carstens		return -EFAULT;
2598070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
2608070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Save vector registers to signal stack */
2618070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (current->thread.vxrs) {
2628070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		for (i = 0; i < __NUM_VXRS_LOW; i++)
2638070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			vxrs[i] = *((__u64 *)(current->thread.vxrs + i) + 1);
2648070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		if (__copy_to_user(&sregs_ext->vxrs_low, vxrs,
2658070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				   sizeof(sregs_ext->vxrs_low)) ||
2668070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		    __copy_to_user(&sregs_ext->vxrs_high,
2678070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				   current->thread.vxrs + __NUM_VXRS_LOW,
2688070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				   sizeof(sregs_ext->vxrs_high)))
2698070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			return -EFAULT;
2708070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	}
271f8544ec4f49ffb9cb93419e41f0d8c0fb39eb78fHeiko Carstens	return 0;
272ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens}
273ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
2748070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefskystatic int restore_sigregs_ext32(struct pt_regs *regs,
2758070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				 _sigregs_ext32 __user *sregs_ext)
276ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens{
277ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	__u32 gprs_high[NUM_GPRS];
2788070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	__u64 vxrs[__NUM_VXRS_LOW];
279f8544ec4f49ffb9cb93419e41f0d8c0fb39eb78fHeiko Carstens	int i;
280ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
2818070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Restore high gprs from signal stack */
2828070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (__copy_from_user(&gprs_high, &sregs_ext->gprs_high,
2838070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			     sizeof(&sregs_ext->gprs_high)))
284f8544ec4f49ffb9cb93419e41f0d8c0fb39eb78fHeiko Carstens		return -EFAULT;
285ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	for (i = 0; i < NUM_GPRS; i++)
286ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		*(__u32 *)&regs->gprs[i] = gprs_high[i];
2878070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
2888070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Restore vector registers from signal stack */
2898070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (current->thread.vxrs) {
2908070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		if (__copy_from_user(vxrs, &sregs_ext->vxrs_low,
2918070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				     sizeof(sregs_ext->vxrs_low)) ||
2928070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		    __copy_from_user(current->thread.vxrs + __NUM_VXRS_LOW,
2938070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				     &sregs_ext->vxrs_high,
2948070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky				     sizeof(sregs_ext->vxrs_high)))
2958070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			return -EFAULT;
2968070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		for (i = 0; i < __NUM_VXRS_LOW; i++)
2978070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			*((__u64 *)(current->thread.vxrs + i) + 1) = vxrs[i];
2988070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	}
299ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens	return 0;
300ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens}
301ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens
3025b098c204827ed21961988b4206b411f90cc89c8Heiko CarstensCOMPAT_SYSCALL_DEFINE0(sigreturn)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
30403ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefsky	struct pt_regs *regs = task_pt_regs(current);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigset_t set;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
310391c62feb1798b6d31bd88076eae649b091ad8bfHeiko Carstens	set_current_blocked(&set);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (restore_sigregs32(regs, &frame->sregs))
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
3138070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (restore_sigregs_ext32(regs, &frame->sregs_ext))
314ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		goto badframe;
3158070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	load_sigregs();
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return regs->gprs[2];
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbadframe:
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	force_sig(SIGSEGV, current);
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3225b098c204827ed21961988b4206b411f90cc89c8Heiko CarstensCOMPAT_SYSCALL_DEFINE0(rt_sigreturn)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32403ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefsky	struct pt_regs *regs = task_pt_regs(current);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigset_t set;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
330391c62feb1798b6d31bd88076eae649b091ad8bfHeiko Carstens	set_current_blocked(&set);
3318070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (compat_restore_altstack(&frame->uc.uc_stack))
3328070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		goto badframe;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto badframe;
3358070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (restore_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
336ea2a4d3a3a929ef494952bba57a0ef1a8a877881Heiko Carstens		goto badframe;
3378070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	load_sigregs();
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return regs->gprs[2];
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbadframe:
34003ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefsky	force_sig(SIGSEGV, current);
34103ff9a235a0602724fc54916469b6e0939c62c9bMartin Schwidefsky	return 0;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up a signal frame.
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine which stack to use..
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __user *
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long sp;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Default to using normal stack */
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp = (unsigned long) A(regs->gprs[15]);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
360de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens	/* Overflow on alternate signal stack gives SIGSEGV. */
361de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens	if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
362de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens		return (void __user *) -1UL;
363de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This is the X/Open sanctioned signal stack switching.  */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ka->sa.sa_flags & SA_ONSTACK) {
36628f223782bca914ae65d08234c57c2175ecd7f5dLaurent Meyer		if (! sas_ss_flags(sp))
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sp = current->sas_ss_sp + current->sas_ss_size;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (void __user *)((sp - frame_size) & -8ul);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int map_signal(int sig)
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (current_thread_info()->exec_domain
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    && current_thread_info()->exec_domain->signal_invmap
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    && sig < 32)
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return current_thread_info()->exec_domain->signal_invmap[sig];
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        else
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return sig;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
383067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinbergerstatic int setup_frame32(struct ksignal *ksig, sigset_t *set,
384067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger			 struct pt_regs *regs)
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
386067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger	int sig = ksig->sig;
3878070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	sigframe32 __user *frame;
3888070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	struct sigcontext32 sc;
3898070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	unsigned long restorer;
3908070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	size_t frame_size;
3918070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
3928070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/*
3938070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	 * gprs_high are always present for 31-bit compat tasks.
3948070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	 * The space for vector registers is only allocated if
3958070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	 * the machine supports it
3968070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	 */
3978070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	frame_size = sizeof(*frame) - sizeof(frame->sregs_ext.__reserved);
3988070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (!MACHINE_HAS_VX)
3998070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		frame_size -= sizeof(frame->sregs_ext.vxrs_low) +
4008070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			      sizeof(frame->sregs_ext.vxrs_high);
4018070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	frame = get_sigframe(&ksig->ka, regs, frame_size);
402de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens	if (frame == (void __user *) -1UL)
403067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		return -EFAULT;
404de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens
4058070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Set up backchain. */
4068070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
4078070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		return -EFAULT;
4088070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
4098070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Create struct sigcontext32 on the signal stack */
4108070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32);
4118070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	sc.sregs = (__u32)(unsigned long __force) &frame->sregs;
4128070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc)))
413067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		return -EFAULT;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4158070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Store registers needed to create the signal frame */
4168070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	store_sigregs();
4178070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
4188070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Create _sigregs32 on the signal stack */
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (save_sigregs32(regs, &frame->sregs))
420067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		return -EFAULT;
4218070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
4228070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Place signal number on stack to allow backtrace from handler.  */
4238070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
424067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		return -EFAULT;
4258070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
4268070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Create _sigregs_ext32 on the signal stack */
4278070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (save_sigregs_ext32(regs, &frame->sregs_ext))
428067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		return -EFAULT;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up to return from userspace.  If provided, use a stub
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   already in userspace.  */
432067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
4338070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		restorer = (unsigned long __force)
4348070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4368070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		/* Signal frames without vectors registers are short ! */
4378070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		__u16 __user *svc = (void *) frame + frame_size - 2;
4388070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc))
439067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger			return -EFAULT;
4408070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up registers for signal handler */
4448070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	regs->gprs[14] = restorer;
4453c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[15] = (__force __u64) frame;
446fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	/* Force 31 bit amode and default user address space control. */
447fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	regs->psw.mask = PSW_MASK_BA |
448e258d719ff28ecc7a048eb8f78380e68c4b3a3f0Martin Schwidefsky		(PSW_USER_BITS & PSW_MASK_ASC) |
449fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky		(regs->psw.mask & ~PSW_MASK_ASC);
450067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger	regs->psw.addr = (__force __u64) ksig->ka.sa.sa_handler;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	regs->gprs[2] = map_signal(sig);
4533c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[3] = (__force __u64) &frame->sc;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We forgot to include these in the sigcontext.
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   To avoid breaking binary compatibility, they are passed as args. */
457aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky	if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
458aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky	    sig == SIGTRAP || sig == SIGFPE) {
459aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky		/* set extra registers only for synchronous signals */
460aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky		regs->gprs[4] = regs->int_code & 127;
461aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky		regs->gprs[5] = regs->int_parm_long;
462bd9e034ef340e3a00301f67b00a247617891f1f0Michael Holzheu		regs->gprs[6] = task_thread_info(current)->last_break;
463aa33c8cbbae2eb98489a3a363099b362146a8f4cMartin Schwidefsky	}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46554dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens	return 0;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
468067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinbergerstatic int setup_rt_frame32(struct ksignal *ksig, sigset_t *set,
469067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger			    struct pt_regs *regs)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4718070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	rt_sigframe32 __user *frame;
4728070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	unsigned long restorer;
4738070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	size_t frame_size;
4748070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	u32 uc_flags;
4758070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
4768070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	frame_size = sizeof(*frame) -
4778070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		     sizeof(frame->uc.uc_mcontext_ext.__reserved);
4788070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/*
4798070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	 * gprs_high are always present for 31-bit compat tasks.
4808070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	 * The space for vector registers is only allocated if
4818070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	 * the machine supports it
4828070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	 */
4838070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	uc_flags = UC_GPRS_HIGH;
4848070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (MACHINE_HAS_VX) {
4858070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		if (current->thread.vxrs)
4868070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			uc_flags |= UC_VXRS;
4878070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	} else
4888070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		frame_size -= sizeof(frame->uc.uc_mcontext_ext.vxrs_low) +
4898070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			      sizeof(frame->uc.uc_mcontext_ext.vxrs_high);
4908070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	frame = get_sigframe(&ksig->ka, regs, frame_size);
491de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens	if (frame == (void __user *) -1UL)
492067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		return -EFAULT;
493de553438eb6c487f72d46019eb3821f6687ce011Heiko Carstens
4948070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Set up backchain. */
4958070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
496067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		return -EFAULT;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up to return from userspace.  If provided, use a stub
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   already in userspace.  */
500067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
5018070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		restorer = (unsigned long __force)
5028070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky			ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5048070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		__u16 __user *svc = &frame->svc_insn;
5058070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, svc))
506067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger			return -EFAULT;
5078070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5108070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Create siginfo on the signal stack */
5118070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (copy_siginfo_to_user32(&frame->info, &ksig->info))
5128070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky		return -EFAULT;
5138070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
5148070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Store registers needed to create the signal frame */
5158070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	store_sigregs();
5168070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky
5178070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	/* Create ucontext on the signal stack. */
5188070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	if (__put_user(uc_flags, &frame->uc.uc_flags) ||
5198070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	    __put_user(0, &frame->uc.uc_link) ||
5208070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	    __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
5218070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	    save_sigregs32(regs, &frame->uc.uc_mcontext) ||
5228070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	    __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) ||
5238070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	    save_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
524067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		return -EFAULT;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up registers for signal handler */
5278070361799ae1e3f4ef347bd10f0a508ac10acfbMartin Schwidefsky	regs->gprs[14] = restorer;
5283c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[15] = (__force __u64) frame;
529fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	/* Force 31 bit amode and default user address space control. */
530fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky	regs->psw.mask = PSW_MASK_BA |
531e258d719ff28ecc7a048eb8f78380e68c4b3a3f0Martin Schwidefsky		(PSW_USER_BITS & PSW_MASK_ASC) |
532fa968ee215c0ca91e4a9c3a69ac2405aae6e5d2fMartin Schwidefsky		(regs->psw.mask & ~PSW_MASK_ASC);
533067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger	regs->psw.addr = (__u64 __force) ksig->ka.sa.sa_handler;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
535067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger	regs->gprs[2] = map_signal(ksig->sig);
5363c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[3] = (__force __u64) &frame->info;
5373c52e49d7c81434e3d2ccb520b3a654c2cc7d03dMartin Schwidefsky	regs->gprs[4] = (__force __u64) &frame->uc;
538bd9e034ef340e3a00301f67b00a247617891f1f0Michael Holzheu	regs->gprs[5] = task_thread_info(current)->last_break;
53954dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens	return 0;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OK, we're invoking a handler
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
546067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinbergervoid handle_signal32(struct ksignal *ksig, sigset_t *oldset,
547067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		     struct pt_regs *regs)
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
54954dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens	int ret;
55054dfe5dd9abc547f63060d132dad2c024a47de1eHeiko Carstens
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set up the stack frame */
552067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
553067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		ret = setup_rt_frame32(ksig, oldset, regs);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
555067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger		ret = setup_frame32(ksig, oldset, regs);
556067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger
557067bf2d4d3a7aedc5982f6a58716054e5004b801Richard Weinberger	signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLE_STEP));
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
560