xref: /kernel/linux/linux-6.6/arch/s390/kernel/signal.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *    Copyright IBM Corp. 1999, 2006
462306a36Sopenharmony_ci *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *    Based on Intel version
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Copyright (C) 1991, 1992  Linus Torvalds
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/sched.h>
1462306a36Sopenharmony_ci#include <linux/sched/task_stack.h>
1562306a36Sopenharmony_ci#include <linux/mm.h>
1662306a36Sopenharmony_ci#include <linux/smp.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/signal.h>
1962306a36Sopenharmony_ci#include <linux/entry-common.h>
2062306a36Sopenharmony_ci#include <linux/errno.h>
2162306a36Sopenharmony_ci#include <linux/wait.h>
2262306a36Sopenharmony_ci#include <linux/ptrace.h>
2362306a36Sopenharmony_ci#include <linux/unistd.h>
2462306a36Sopenharmony_ci#include <linux/stddef.h>
2562306a36Sopenharmony_ci#include <linux/tty.h>
2662306a36Sopenharmony_ci#include <linux/personality.h>
2762306a36Sopenharmony_ci#include <linux/binfmts.h>
2862306a36Sopenharmony_ci#include <linux/syscalls.h>
2962306a36Sopenharmony_ci#include <linux/compat.h>
3062306a36Sopenharmony_ci#include <asm/ucontext.h>
3162306a36Sopenharmony_ci#include <linux/uaccess.h>
3262306a36Sopenharmony_ci#include <asm/lowcore.h>
3362306a36Sopenharmony_ci#include <asm/switch_to.h>
3462306a36Sopenharmony_ci#include <asm/vdso.h>
3562306a36Sopenharmony_ci#include "entry.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * Layout of an old-style signal-frame:
3962306a36Sopenharmony_ci *	-----------------------------------------
4062306a36Sopenharmony_ci *	| save area (_SIGNAL_FRAMESIZE)		|
4162306a36Sopenharmony_ci *	-----------------------------------------
4262306a36Sopenharmony_ci *	| struct sigcontext			|
4362306a36Sopenharmony_ci *	|	oldmask				|
4462306a36Sopenharmony_ci *	|	_sigregs *			|
4562306a36Sopenharmony_ci *	-----------------------------------------
4662306a36Sopenharmony_ci *	| _sigregs with				|
4762306a36Sopenharmony_ci *	|	_s390_regs_common		|
4862306a36Sopenharmony_ci *	|	_s390_fp_regs			|
4962306a36Sopenharmony_ci *	-----------------------------------------
5062306a36Sopenharmony_ci *	| int signo				|
5162306a36Sopenharmony_ci *	-----------------------------------------
5262306a36Sopenharmony_ci *	| _sigregs_ext with			|
5362306a36Sopenharmony_ci *	|	gprs_high 64 byte (opt)		|
5462306a36Sopenharmony_ci *	|	vxrs_low 128 byte (opt)		|
5562306a36Sopenharmony_ci *	|	vxrs_high 256 byte (opt)	|
5662306a36Sopenharmony_ci *	|	reserved 128 byte (opt)		|
5762306a36Sopenharmony_ci *	-----------------------------------------
5862306a36Sopenharmony_ci *	| __u16 svc_insn			|
5962306a36Sopenharmony_ci *	-----------------------------------------
6062306a36Sopenharmony_ci * The svc_insn entry with the sigreturn system call opcode does not
6162306a36Sopenharmony_ci * have a fixed position and moves if gprs_high or vxrs exist.
6262306a36Sopenharmony_ci * Future extensions will be added to _sigregs_ext.
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_cistruct sigframe
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
6762306a36Sopenharmony_ci	struct sigcontext sc;
6862306a36Sopenharmony_ci	_sigregs sregs;
6962306a36Sopenharmony_ci	int signo;
7062306a36Sopenharmony_ci	_sigregs_ext sregs_ext;
7162306a36Sopenharmony_ci	__u16 svc_insn;		/* Offset of svc_insn is NOT fixed! */
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci * Layout of an rt signal-frame:
7662306a36Sopenharmony_ci *	-----------------------------------------
7762306a36Sopenharmony_ci *	| save area (_SIGNAL_FRAMESIZE)		|
7862306a36Sopenharmony_ci *	-----------------------------------------
7962306a36Sopenharmony_ci *	| svc __NR_rt_sigreturn 2 byte		|
8062306a36Sopenharmony_ci *	-----------------------------------------
8162306a36Sopenharmony_ci *	| struct siginfo			|
8262306a36Sopenharmony_ci *	-----------------------------------------
8362306a36Sopenharmony_ci *	| struct ucontext_extended with		|
8462306a36Sopenharmony_ci *	|	unsigned long uc_flags		|
8562306a36Sopenharmony_ci *	|	struct ucontext *uc_link	|
8662306a36Sopenharmony_ci *	|	stack_t uc_stack		|
8762306a36Sopenharmony_ci *	|	_sigregs uc_mcontext with	|
8862306a36Sopenharmony_ci *	|		_s390_regs_common	|
8962306a36Sopenharmony_ci *	|		_s390_fp_regs		|
9062306a36Sopenharmony_ci *	|	sigset_t uc_sigmask		|
9162306a36Sopenharmony_ci *	|	_sigregs_ext uc_mcontext_ext	|
9262306a36Sopenharmony_ci *	|		gprs_high 64 byte (opt)	|
9362306a36Sopenharmony_ci *	|		vxrs_low 128 byte (opt)	|
9462306a36Sopenharmony_ci *	|		vxrs_high 256 byte (opt)|
9562306a36Sopenharmony_ci *	|		reserved 128 byte (opt)	|
9662306a36Sopenharmony_ci *	-----------------------------------------
9762306a36Sopenharmony_ci * Future extensions will be added to _sigregs_ext.
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_cistruct rt_sigframe
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
10262306a36Sopenharmony_ci	__u16 svc_insn;
10362306a36Sopenharmony_ci	struct siginfo info;
10462306a36Sopenharmony_ci	struct ucontext_extended uc;
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/* Store registers needed to create the signal frame */
10862306a36Sopenharmony_cistatic void store_sigregs(void)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	save_access_regs(current->thread.acrs);
11162306a36Sopenharmony_ci	save_fpu_regs();
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/* Load registers after signal return */
11562306a36Sopenharmony_cistatic void load_sigregs(void)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	restore_access_regs(current->thread.acrs);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/* Returns non-zero on fault. */
12162306a36Sopenharmony_cistatic int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	_sigregs user_sregs;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* Copy a 'clean' PSW mask to the user to avoid leaking
12662306a36Sopenharmony_ci	   information about whether PER is currently on.  */
12762306a36Sopenharmony_ci	user_sregs.regs.psw.mask = PSW_USER_BITS |
12862306a36Sopenharmony_ci		(regs->psw.mask & (PSW_MASK_USER | PSW_MASK_RI));
12962306a36Sopenharmony_ci	user_sregs.regs.psw.addr = regs->psw.addr;
13062306a36Sopenharmony_ci	memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
13162306a36Sopenharmony_ci	memcpy(&user_sregs.regs.acrs, current->thread.acrs,
13262306a36Sopenharmony_ci	       sizeof(user_sregs.regs.acrs));
13362306a36Sopenharmony_ci	fpregs_store(&user_sregs.fpregs, &current->thread.fpu);
13462306a36Sopenharmony_ci	if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs)))
13562306a36Sopenharmony_ci		return -EFAULT;
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	_sigregs user_sregs;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* Always make any pending restarted system call return -EINTR */
14462306a36Sopenharmony_ci	current->restart_block.fn = do_no_restart_syscall;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (__copy_from_user(&user_sregs, sregs, sizeof(user_sregs)))
14762306a36Sopenharmony_ci		return -EFAULT;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI))
15062306a36Sopenharmony_ci		return -EINVAL;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* Test the floating-point-control word. */
15362306a36Sopenharmony_ci	if (test_fp_ctl(user_sregs.fpregs.fpc))
15462306a36Sopenharmony_ci		return -EINVAL;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
15762306a36Sopenharmony_ci	regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) |
15862306a36Sopenharmony_ci		(user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI));
15962306a36Sopenharmony_ci	/* Check for invalid user address space control. */
16062306a36Sopenharmony_ci	if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME)
16162306a36Sopenharmony_ci		regs->psw.mask = PSW_ASC_PRIMARY |
16262306a36Sopenharmony_ci			(regs->psw.mask & ~PSW_MASK_ASC);
16362306a36Sopenharmony_ci	/* Check for invalid amode */
16462306a36Sopenharmony_ci	if (regs->psw.mask & PSW_MASK_EA)
16562306a36Sopenharmony_ci		regs->psw.mask |= PSW_MASK_BA;
16662306a36Sopenharmony_ci	regs->psw.addr = user_sregs.regs.psw.addr;
16762306a36Sopenharmony_ci	memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
16862306a36Sopenharmony_ci	memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
16962306a36Sopenharmony_ci	       sizeof(current->thread.acrs));
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	fpregs_load(&user_sregs.fpregs, &current->thread.fpu);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
17462306a36Sopenharmony_ci	return 0;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/* Returns non-zero on fault. */
17862306a36Sopenharmony_cistatic int save_sigregs_ext(struct pt_regs *regs,
17962306a36Sopenharmony_ci			    _sigregs_ext __user *sregs_ext)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	__u64 vxrs[__NUM_VXRS_LOW];
18262306a36Sopenharmony_ci	int i;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* Save vector registers to signal stack */
18562306a36Sopenharmony_ci	if (MACHINE_HAS_VX) {
18662306a36Sopenharmony_ci		for (i = 0; i < __NUM_VXRS_LOW; i++)
18762306a36Sopenharmony_ci			vxrs[i] = current->thread.fpu.vxrs[i].low;
18862306a36Sopenharmony_ci		if (__copy_to_user(&sregs_ext->vxrs_low, vxrs,
18962306a36Sopenharmony_ci				   sizeof(sregs_ext->vxrs_low)) ||
19062306a36Sopenharmony_ci		    __copy_to_user(&sregs_ext->vxrs_high,
19162306a36Sopenharmony_ci				   current->thread.fpu.vxrs + __NUM_VXRS_LOW,
19262306a36Sopenharmony_ci				   sizeof(sregs_ext->vxrs_high)))
19362306a36Sopenharmony_ci			return -EFAULT;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	return 0;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int restore_sigregs_ext(struct pt_regs *regs,
19962306a36Sopenharmony_ci			       _sigregs_ext __user *sregs_ext)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	__u64 vxrs[__NUM_VXRS_LOW];
20262306a36Sopenharmony_ci	int i;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Restore vector registers from signal stack */
20562306a36Sopenharmony_ci	if (MACHINE_HAS_VX) {
20662306a36Sopenharmony_ci		if (__copy_from_user(vxrs, &sregs_ext->vxrs_low,
20762306a36Sopenharmony_ci				     sizeof(sregs_ext->vxrs_low)) ||
20862306a36Sopenharmony_ci		    __copy_from_user(current->thread.fpu.vxrs + __NUM_VXRS_LOW,
20962306a36Sopenharmony_ci				     &sregs_ext->vxrs_high,
21062306a36Sopenharmony_ci				     sizeof(sregs_ext->vxrs_high)))
21162306a36Sopenharmony_ci			return -EFAULT;
21262306a36Sopenharmony_ci		for (i = 0; i < __NUM_VXRS_LOW; i++)
21362306a36Sopenharmony_ci			current->thread.fpu.vxrs[i].low = vxrs[i];
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ciSYSCALL_DEFINE0(sigreturn)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct pt_regs *regs = task_pt_regs(current);
22162306a36Sopenharmony_ci	struct sigframe __user *frame =
22262306a36Sopenharmony_ci		(struct sigframe __user *) regs->gprs[15];
22362306a36Sopenharmony_ci	sigset_t set;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
22662306a36Sopenharmony_ci		goto badframe;
22762306a36Sopenharmony_ci	set_current_blocked(&set);
22862306a36Sopenharmony_ci	save_fpu_regs();
22962306a36Sopenharmony_ci	if (restore_sigregs(regs, &frame->sregs))
23062306a36Sopenharmony_ci		goto badframe;
23162306a36Sopenharmony_ci	if (restore_sigregs_ext(regs, &frame->sregs_ext))
23262306a36Sopenharmony_ci		goto badframe;
23362306a36Sopenharmony_ci	load_sigregs();
23462306a36Sopenharmony_ci	return regs->gprs[2];
23562306a36Sopenharmony_cibadframe:
23662306a36Sopenharmony_ci	force_sig(SIGSEGV);
23762306a36Sopenharmony_ci	return 0;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ciSYSCALL_DEFINE0(rt_sigreturn)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct pt_regs *regs = task_pt_regs(current);
24362306a36Sopenharmony_ci	struct rt_sigframe __user *frame =
24462306a36Sopenharmony_ci		(struct rt_sigframe __user *)regs->gprs[15];
24562306a36Sopenharmony_ci	sigset_t set;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
24862306a36Sopenharmony_ci		goto badframe;
24962306a36Sopenharmony_ci	set_current_blocked(&set);
25062306a36Sopenharmony_ci	if (restore_altstack(&frame->uc.uc_stack))
25162306a36Sopenharmony_ci		goto badframe;
25262306a36Sopenharmony_ci	save_fpu_regs();
25362306a36Sopenharmony_ci	if (restore_sigregs(regs, &frame->uc.uc_mcontext))
25462306a36Sopenharmony_ci		goto badframe;
25562306a36Sopenharmony_ci	if (restore_sigregs_ext(regs, &frame->uc.uc_mcontext_ext))
25662306a36Sopenharmony_ci		goto badframe;
25762306a36Sopenharmony_ci	load_sigregs();
25862306a36Sopenharmony_ci	return regs->gprs[2];
25962306a36Sopenharmony_cibadframe:
26062306a36Sopenharmony_ci	force_sig(SIGSEGV);
26162306a36Sopenharmony_ci	return 0;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/*
26562306a36Sopenharmony_ci * Determine which stack to use..
26662306a36Sopenharmony_ci */
26762306a36Sopenharmony_cistatic inline void __user *
26862306a36Sopenharmony_ciget_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	unsigned long sp;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Default to using normal stack */
27362306a36Sopenharmony_ci	sp = regs->gprs[15];
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Overflow on alternate signal stack gives SIGSEGV. */
27662306a36Sopenharmony_ci	if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
27762306a36Sopenharmony_ci		return (void __user *) -1UL;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* This is the X/Open sanctioned signal stack switching.  */
28062306a36Sopenharmony_ci	if (ka->sa.sa_flags & SA_ONSTACK) {
28162306a36Sopenharmony_ci		if (! sas_ss_flags(sp))
28262306a36Sopenharmony_ci			sp = current->sas_ss_sp + current->sas_ss_size;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return (void __user *)((sp - frame_size) & -8ul);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int setup_frame(int sig, struct k_sigaction *ka,
28962306a36Sopenharmony_ci		       sigset_t *set, struct pt_regs * regs)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct sigframe __user *frame;
29262306a36Sopenharmony_ci	struct sigcontext sc;
29362306a36Sopenharmony_ci	unsigned long restorer;
29462306a36Sopenharmony_ci	size_t frame_size;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/*
29762306a36Sopenharmony_ci	 * gprs_high are only present for a 31-bit task running on
29862306a36Sopenharmony_ci	 * a 64-bit kernel (see compat_signal.c) but the space for
29962306a36Sopenharmony_ci	 * gprs_high need to be allocated if vector registers are
30062306a36Sopenharmony_ci	 * included in the signal frame on a 31-bit system.
30162306a36Sopenharmony_ci	 */
30262306a36Sopenharmony_ci	frame_size = sizeof(*frame) - sizeof(frame->sregs_ext);
30362306a36Sopenharmony_ci	if (MACHINE_HAS_VX)
30462306a36Sopenharmony_ci		frame_size += sizeof(frame->sregs_ext);
30562306a36Sopenharmony_ci	frame = get_sigframe(ka, regs, frame_size);
30662306a36Sopenharmony_ci	if (frame == (void __user *) -1UL)
30762306a36Sopenharmony_ci		return -EFAULT;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* Set up backchain. */
31062306a36Sopenharmony_ci	if (__put_user(regs->gprs[15], (addr_t __user *) frame))
31162306a36Sopenharmony_ci		return -EFAULT;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* Create struct sigcontext on the signal stack */
31462306a36Sopenharmony_ci	memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE);
31562306a36Sopenharmony_ci	sc.sregs = (_sigregs __user __force *) &frame->sregs;
31662306a36Sopenharmony_ci	if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc)))
31762306a36Sopenharmony_ci		return -EFAULT;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* Store registers needed to create the signal frame */
32062306a36Sopenharmony_ci	store_sigregs();
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* Create _sigregs on the signal stack */
32362306a36Sopenharmony_ci	if (save_sigregs(regs, &frame->sregs))
32462306a36Sopenharmony_ci		return -EFAULT;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* Place signal number on stack to allow backtrace from handler.  */
32762306a36Sopenharmony_ci	if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
32862306a36Sopenharmony_ci		return -EFAULT;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Create _sigregs_ext on the signal stack */
33162306a36Sopenharmony_ci	if (save_sigregs_ext(regs, &frame->sregs_ext))
33262306a36Sopenharmony_ci		return -EFAULT;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* Set up to return from userspace.  If provided, use a stub
33562306a36Sopenharmony_ci	   already in userspace.  */
33662306a36Sopenharmony_ci	if (ka->sa.sa_flags & SA_RESTORER)
33762306a36Sopenharmony_ci		restorer = (unsigned long) ka->sa.sa_restorer;
33862306a36Sopenharmony_ci	else
33962306a36Sopenharmony_ci		restorer = VDSO64_SYMBOL(current, sigreturn);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* Set up registers for signal handler */
34262306a36Sopenharmony_ci	regs->gprs[14] = restorer;
34362306a36Sopenharmony_ci	regs->gprs[15] = (unsigned long) frame;
34462306a36Sopenharmony_ci	/* Force default amode and default user address space control. */
34562306a36Sopenharmony_ci	regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
34662306a36Sopenharmony_ci		(PSW_USER_BITS & PSW_MASK_ASC) |
34762306a36Sopenharmony_ci		(regs->psw.mask & ~PSW_MASK_ASC);
34862306a36Sopenharmony_ci	regs->psw.addr = (unsigned long) ka->sa.sa_handler;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	regs->gprs[2] = sig;
35162306a36Sopenharmony_ci	regs->gprs[3] = (unsigned long) &frame->sc;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* We forgot to include these in the sigcontext.
35462306a36Sopenharmony_ci	   To avoid breaking binary compatibility, they are passed as args. */
35562306a36Sopenharmony_ci	if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
35662306a36Sopenharmony_ci	    sig == SIGTRAP || sig == SIGFPE) {
35762306a36Sopenharmony_ci		/* set extra registers only for synchronous signals */
35862306a36Sopenharmony_ci		regs->gprs[4] = regs->int_code & 127;
35962306a36Sopenharmony_ci		regs->gprs[5] = regs->int_parm_long;
36062306a36Sopenharmony_ci		regs->gprs[6] = current->thread.last_break;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci	return 0;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
36662306a36Sopenharmony_ci			  struct pt_regs *regs)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct rt_sigframe __user *frame;
36962306a36Sopenharmony_ci	unsigned long uc_flags, restorer;
37062306a36Sopenharmony_ci	size_t frame_size;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	frame_size = sizeof(struct rt_sigframe) - sizeof(_sigregs_ext);
37362306a36Sopenharmony_ci	/*
37462306a36Sopenharmony_ci	 * gprs_high are only present for a 31-bit task running on
37562306a36Sopenharmony_ci	 * a 64-bit kernel (see compat_signal.c) but the space for
37662306a36Sopenharmony_ci	 * gprs_high need to be allocated if vector registers are
37762306a36Sopenharmony_ci	 * included in the signal frame on a 31-bit system.
37862306a36Sopenharmony_ci	 */
37962306a36Sopenharmony_ci	uc_flags = 0;
38062306a36Sopenharmony_ci	if (MACHINE_HAS_VX) {
38162306a36Sopenharmony_ci		frame_size += sizeof(_sigregs_ext);
38262306a36Sopenharmony_ci		uc_flags |= UC_VXRS;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	frame = get_sigframe(&ksig->ka, regs, frame_size);
38562306a36Sopenharmony_ci	if (frame == (void __user *) -1UL)
38662306a36Sopenharmony_ci		return -EFAULT;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* Set up backchain. */
38962306a36Sopenharmony_ci	if (__put_user(regs->gprs[15], (addr_t __user *) frame))
39062306a36Sopenharmony_ci		return -EFAULT;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* Set up to return from userspace.  If provided, use a stub
39362306a36Sopenharmony_ci	   already in userspace.  */
39462306a36Sopenharmony_ci	if (ksig->ka.sa.sa_flags & SA_RESTORER)
39562306a36Sopenharmony_ci		restorer = (unsigned long) ksig->ka.sa.sa_restorer;
39662306a36Sopenharmony_ci	else
39762306a36Sopenharmony_ci		restorer = VDSO64_SYMBOL(current, rt_sigreturn);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Create siginfo on the signal stack */
40062306a36Sopenharmony_ci	if (copy_siginfo_to_user(&frame->info, &ksig->info))
40162306a36Sopenharmony_ci		return -EFAULT;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* Store registers needed to create the signal frame */
40462306a36Sopenharmony_ci	store_sigregs();
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* Create ucontext on the signal stack. */
40762306a36Sopenharmony_ci	if (__put_user(uc_flags, &frame->uc.uc_flags) ||
40862306a36Sopenharmony_ci	    __put_user(NULL, &frame->uc.uc_link) ||
40962306a36Sopenharmony_ci	    __save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
41062306a36Sopenharmony_ci	    save_sigregs(regs, &frame->uc.uc_mcontext) ||
41162306a36Sopenharmony_ci	    __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) ||
41262306a36Sopenharmony_ci	    save_sigregs_ext(regs, &frame->uc.uc_mcontext_ext))
41362306a36Sopenharmony_ci		return -EFAULT;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* Set up registers for signal handler */
41662306a36Sopenharmony_ci	regs->gprs[14] = restorer;
41762306a36Sopenharmony_ci	regs->gprs[15] = (unsigned long) frame;
41862306a36Sopenharmony_ci	/* Force default amode and default user address space control. */
41962306a36Sopenharmony_ci	regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
42062306a36Sopenharmony_ci		(PSW_USER_BITS & PSW_MASK_ASC) |
42162306a36Sopenharmony_ci		(regs->psw.mask & ~PSW_MASK_ASC);
42262306a36Sopenharmony_ci	regs->psw.addr = (unsigned long) ksig->ka.sa.sa_handler;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	regs->gprs[2] = ksig->sig;
42562306a36Sopenharmony_ci	regs->gprs[3] = (unsigned long) &frame->info;
42662306a36Sopenharmony_ci	regs->gprs[4] = (unsigned long) &frame->uc;
42762306a36Sopenharmony_ci	regs->gprs[5] = current->thread.last_break;
42862306a36Sopenharmony_ci	return 0;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic void handle_signal(struct ksignal *ksig, sigset_t *oldset,
43262306a36Sopenharmony_ci			  struct pt_regs *regs)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	int ret;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* Set up the stack frame */
43762306a36Sopenharmony_ci	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
43862306a36Sopenharmony_ci		ret = setup_rt_frame(ksig, oldset, regs);
43962306a36Sopenharmony_ci	else
44062306a36Sopenharmony_ci		ret = setup_frame(ksig->sig, &ksig->ka, oldset, regs);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLE_STEP));
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci/*
44662306a36Sopenharmony_ci * Note that 'init' is a special process: it doesn't get signals it doesn't
44762306a36Sopenharmony_ci * want to handle. Thus you cannot kill init even with a SIGKILL even by
44862306a36Sopenharmony_ci * mistake.
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * Note that we go through the signals twice: once to check the signals that
45162306a36Sopenharmony_ci * the kernel can handle, and then we build all the user-level signal handling
45262306a36Sopenharmony_ci * stack-frames in one go after that.
45362306a36Sopenharmony_ci */
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_civoid arch_do_signal_or_restart(struct pt_regs *regs)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct ksignal ksig;
45862306a36Sopenharmony_ci	sigset_t *oldset = sigmask_to_save();
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/*
46162306a36Sopenharmony_ci	 * Get signal to deliver. When running under ptrace, at this point
46262306a36Sopenharmony_ci	 * the debugger may change all our registers, including the system
46362306a36Sopenharmony_ci	 * call information.
46462306a36Sopenharmony_ci	 */
46562306a36Sopenharmony_ci	current->thread.system_call =
46662306a36Sopenharmony_ci		test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (get_signal(&ksig)) {
46962306a36Sopenharmony_ci		/* Whee!  Actually deliver the signal.  */
47062306a36Sopenharmony_ci		if (current->thread.system_call) {
47162306a36Sopenharmony_ci			regs->int_code = current->thread.system_call;
47262306a36Sopenharmony_ci			/* Check for system call restarting. */
47362306a36Sopenharmony_ci			switch (regs->gprs[2]) {
47462306a36Sopenharmony_ci			case -ERESTART_RESTARTBLOCK:
47562306a36Sopenharmony_ci			case -ERESTARTNOHAND:
47662306a36Sopenharmony_ci				regs->gprs[2] = -EINTR;
47762306a36Sopenharmony_ci				break;
47862306a36Sopenharmony_ci			case -ERESTARTSYS:
47962306a36Sopenharmony_ci				if (!(ksig.ka.sa.sa_flags & SA_RESTART)) {
48062306a36Sopenharmony_ci					regs->gprs[2] = -EINTR;
48162306a36Sopenharmony_ci					break;
48262306a36Sopenharmony_ci				}
48362306a36Sopenharmony_ci				fallthrough;
48462306a36Sopenharmony_ci			case -ERESTARTNOINTR:
48562306a36Sopenharmony_ci				regs->gprs[2] = regs->orig_gpr2;
48662306a36Sopenharmony_ci				regs->psw.addr =
48762306a36Sopenharmony_ci					__rewind_psw(regs->psw,
48862306a36Sopenharmony_ci						     regs->int_code >> 16);
48962306a36Sopenharmony_ci				break;
49062306a36Sopenharmony_ci			}
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci		/* No longer in a system call */
49362306a36Sopenharmony_ci		clear_pt_regs_flag(regs, PIF_SYSCALL);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		rseq_signal_deliver(&ksig, regs);
49662306a36Sopenharmony_ci		if (is_compat_task())
49762306a36Sopenharmony_ci			handle_signal32(&ksig, oldset, regs);
49862306a36Sopenharmony_ci		else
49962306a36Sopenharmony_ci			handle_signal(&ksig, oldset, regs);
50062306a36Sopenharmony_ci		return;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* No handlers present - check for system call restart */
50462306a36Sopenharmony_ci	clear_pt_regs_flag(regs, PIF_SYSCALL);
50562306a36Sopenharmony_ci	if (current->thread.system_call) {
50662306a36Sopenharmony_ci		regs->int_code = current->thread.system_call;
50762306a36Sopenharmony_ci		switch (regs->gprs[2]) {
50862306a36Sopenharmony_ci		case -ERESTART_RESTARTBLOCK:
50962306a36Sopenharmony_ci			/* Restart with sys_restart_syscall */
51062306a36Sopenharmony_ci			regs->gprs[2] = regs->orig_gpr2;
51162306a36Sopenharmony_ci			current->restart_block.arch_data = regs->psw.addr;
51262306a36Sopenharmony_ci			if (is_compat_task())
51362306a36Sopenharmony_ci				regs->psw.addr = VDSO32_SYMBOL(current, restart_syscall);
51462306a36Sopenharmony_ci			else
51562306a36Sopenharmony_ci				regs->psw.addr = VDSO64_SYMBOL(current, restart_syscall);
51662306a36Sopenharmony_ci			if (test_thread_flag(TIF_SINGLE_STEP))
51762306a36Sopenharmony_ci				clear_thread_flag(TIF_PER_TRAP);
51862306a36Sopenharmony_ci			break;
51962306a36Sopenharmony_ci		case -ERESTARTNOHAND:
52062306a36Sopenharmony_ci		case -ERESTARTSYS:
52162306a36Sopenharmony_ci		case -ERESTARTNOINTR:
52262306a36Sopenharmony_ci			regs->gprs[2] = regs->orig_gpr2;
52362306a36Sopenharmony_ci			regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
52462306a36Sopenharmony_ci			if (test_thread_flag(TIF_SINGLE_STEP))
52562306a36Sopenharmony_ci				clear_thread_flag(TIF_PER_TRAP);
52662306a36Sopenharmony_ci			break;
52762306a36Sopenharmony_ci		}
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/*
53162306a36Sopenharmony_ci	 * If there's no signal to deliver, we just put the saved sigmask back.
53262306a36Sopenharmony_ci	 */
53362306a36Sopenharmony_ci	restore_saved_sigmask();
53462306a36Sopenharmony_ci}
535