162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Based on arch/arm/kernel/signal.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1995-2009 Russell King
662306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
762306a36Sopenharmony_ci * Modified by Will Deacon <will.deacon@arm.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/compat.h>
1162306a36Sopenharmony_ci#include <linux/signal.h>
1262306a36Sopenharmony_ci#include <linux/syscalls.h>
1362306a36Sopenharmony_ci#include <linux/ratelimit.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm/esr.h>
1662306a36Sopenharmony_ci#include <asm/fpsimd.h>
1762306a36Sopenharmony_ci#include <asm/signal32.h>
1862306a36Sopenharmony_ci#include <asm/traps.h>
1962306a36Sopenharmony_ci#include <linux/uaccess.h>
2062306a36Sopenharmony_ci#include <asm/unistd.h>
2162306a36Sopenharmony_ci#include <asm/vdso.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct compat_vfp_sigframe {
2462306a36Sopenharmony_ci	compat_ulong_t	magic;
2562306a36Sopenharmony_ci	compat_ulong_t	size;
2662306a36Sopenharmony_ci	struct compat_user_vfp {
2762306a36Sopenharmony_ci		compat_u64	fpregs[32];
2862306a36Sopenharmony_ci		compat_ulong_t	fpscr;
2962306a36Sopenharmony_ci	} ufp;
3062306a36Sopenharmony_ci	struct compat_user_vfp_exc {
3162306a36Sopenharmony_ci		compat_ulong_t	fpexc;
3262306a36Sopenharmony_ci		compat_ulong_t	fpinst;
3362306a36Sopenharmony_ci		compat_ulong_t	fpinst2;
3462306a36Sopenharmony_ci	} ufp_exc;
3562306a36Sopenharmony_ci} __attribute__((__aligned__(8)));
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define VFP_MAGIC		0x56465001
3862306a36Sopenharmony_ci#define VFP_STORAGE_SIZE	sizeof(struct compat_vfp_sigframe)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define FSR_WRITE_SHIFT		(11)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistruct compat_aux_sigframe {
4362306a36Sopenharmony_ci	struct compat_vfp_sigframe	vfp;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* Something that isn't a valid magic number for any coprocessor.  */
4662306a36Sopenharmony_ci	unsigned long			end_magic;
4762306a36Sopenharmony_ci} __attribute__((__aligned__(8)));
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	compat_sigset_t	cset;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	cset.sig[0] = set->sig[0] & 0xffffffffull;
5462306a36Sopenharmony_ci	cset.sig[1] = set->sig[0] >> 32;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return copy_to_user(uset, &cset, sizeof(*uset));
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic inline int get_sigset_t(sigset_t *set,
6062306a36Sopenharmony_ci			       const compat_sigset_t __user *uset)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	compat_sigset_t s32;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (copy_from_user(&s32, uset, sizeof(*uset)))
6562306a36Sopenharmony_ci		return -EFAULT;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	set->sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
6862306a36Sopenharmony_ci	return 0;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/*
7262306a36Sopenharmony_ci * VFP save/restore code.
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * We have to be careful with endianness, since the fpsimd context-switch
7562306a36Sopenharmony_ci * code operates on 128-bit (Q) register values whereas the compat ABI
7662306a36Sopenharmony_ci * uses an array of 64-bit (D) registers. Consequently, we need to swap
7762306a36Sopenharmony_ci * the two halves of each Q register when running on a big-endian CPU.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_ciunion __fpsimd_vreg {
8062306a36Sopenharmony_ci	__uint128_t	raw;
8162306a36Sopenharmony_ci	struct {
8262306a36Sopenharmony_ci#ifdef __AARCH64EB__
8362306a36Sopenharmony_ci		u64	hi;
8462306a36Sopenharmony_ci		u64	lo;
8562306a36Sopenharmony_ci#else
8662306a36Sopenharmony_ci		u64	lo;
8762306a36Sopenharmony_ci		u64	hi;
8862306a36Sopenharmony_ci#endif
8962306a36Sopenharmony_ci	};
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct user_fpsimd_state const *fpsimd =
9562306a36Sopenharmony_ci		&current->thread.uw.fpsimd_state;
9662306a36Sopenharmony_ci	compat_ulong_t magic = VFP_MAGIC;
9762306a36Sopenharmony_ci	compat_ulong_t size = VFP_STORAGE_SIZE;
9862306a36Sopenharmony_ci	compat_ulong_t fpscr, fpexc;
9962306a36Sopenharmony_ci	int i, err = 0;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/*
10262306a36Sopenharmony_ci	 * Save the hardware registers to the fpsimd_state structure.
10362306a36Sopenharmony_ci	 * Note that this also saves V16-31, which aren't visible
10462306a36Sopenharmony_ci	 * in AArch32.
10562306a36Sopenharmony_ci	 */
10662306a36Sopenharmony_ci	fpsimd_signal_preserve_current_state();
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Place structure header on the stack */
10962306a36Sopenharmony_ci	__put_user_error(magic, &frame->magic, err);
11062306a36Sopenharmony_ci	__put_user_error(size, &frame->size, err);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/*
11362306a36Sopenharmony_ci	 * Now copy the FP registers. Since the registers are packed,
11462306a36Sopenharmony_ci	 * we can copy the prefix we want (V0-V15) as it is.
11562306a36Sopenharmony_ci	 */
11662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(frame->ufp.fpregs); i += 2) {
11762306a36Sopenharmony_ci		union __fpsimd_vreg vreg = {
11862306a36Sopenharmony_ci			.raw = fpsimd->vregs[i >> 1],
11962306a36Sopenharmony_ci		};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		__put_user_error(vreg.lo, &frame->ufp.fpregs[i], err);
12262306a36Sopenharmony_ci		__put_user_error(vreg.hi, &frame->ufp.fpregs[i + 1], err);
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* Create an AArch32 fpscr from the fpsr and the fpcr. */
12662306a36Sopenharmony_ci	fpscr = (fpsimd->fpsr & VFP_FPSCR_STAT_MASK) |
12762306a36Sopenharmony_ci		(fpsimd->fpcr & VFP_FPSCR_CTRL_MASK);
12862306a36Sopenharmony_ci	__put_user_error(fpscr, &frame->ufp.fpscr, err);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/*
13162306a36Sopenharmony_ci	 * The exception register aren't available so we fake up a
13262306a36Sopenharmony_ci	 * basic FPEXC and zero everything else.
13362306a36Sopenharmony_ci	 */
13462306a36Sopenharmony_ci	fpexc = (1 << 30);
13562306a36Sopenharmony_ci	__put_user_error(fpexc, &frame->ufp_exc.fpexc, err);
13662306a36Sopenharmony_ci	__put_user_error(0, &frame->ufp_exc.fpinst, err);
13762306a36Sopenharmony_ci	__put_user_error(0, &frame->ufp_exc.fpinst2, err);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return err ? -EFAULT : 0;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct user_fpsimd_state fpsimd;
14562306a36Sopenharmony_ci	compat_ulong_t magic = VFP_MAGIC;
14662306a36Sopenharmony_ci	compat_ulong_t size = VFP_STORAGE_SIZE;
14762306a36Sopenharmony_ci	compat_ulong_t fpscr;
14862306a36Sopenharmony_ci	int i, err = 0;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	__get_user_error(magic, &frame->magic, err);
15162306a36Sopenharmony_ci	__get_user_error(size, &frame->size, err);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (err)
15462306a36Sopenharmony_ci		return -EFAULT;
15562306a36Sopenharmony_ci	if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
15662306a36Sopenharmony_ci		return -EINVAL;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* Copy the FP registers into the start of the fpsimd_state. */
15962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(frame->ufp.fpregs); i += 2) {
16062306a36Sopenharmony_ci		union __fpsimd_vreg vreg;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		__get_user_error(vreg.lo, &frame->ufp.fpregs[i], err);
16362306a36Sopenharmony_ci		__get_user_error(vreg.hi, &frame->ufp.fpregs[i + 1], err);
16462306a36Sopenharmony_ci		fpsimd.vregs[i >> 1] = vreg.raw;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* Extract the fpsr and the fpcr from the fpscr */
16862306a36Sopenharmony_ci	__get_user_error(fpscr, &frame->ufp.fpscr, err);
16962306a36Sopenharmony_ci	fpsimd.fpsr = fpscr & VFP_FPSCR_STAT_MASK;
17062306a36Sopenharmony_ci	fpsimd.fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/*
17362306a36Sopenharmony_ci	 * We don't need to touch the exception register, so
17462306a36Sopenharmony_ci	 * reload the hardware state.
17562306a36Sopenharmony_ci	 */
17662306a36Sopenharmony_ci	if (!err)
17762306a36Sopenharmony_ci		fpsimd_update_current_state(&fpsimd);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return err ? -EFAULT : 0;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic int compat_restore_sigframe(struct pt_regs *regs,
18362306a36Sopenharmony_ci				   struct compat_sigframe __user *sf)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	int err;
18662306a36Sopenharmony_ci	sigset_t set;
18762306a36Sopenharmony_ci	struct compat_aux_sigframe __user *aux;
18862306a36Sopenharmony_ci	unsigned long psr;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	err = get_sigset_t(&set, &sf->uc.uc_sigmask);
19162306a36Sopenharmony_ci	if (err == 0)
19262306a36Sopenharmony_ci		set_current_blocked(&set);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	__get_user_error(regs->regs[0], &sf->uc.uc_mcontext.arm_r0, err);
19562306a36Sopenharmony_ci	__get_user_error(regs->regs[1], &sf->uc.uc_mcontext.arm_r1, err);
19662306a36Sopenharmony_ci	__get_user_error(regs->regs[2], &sf->uc.uc_mcontext.arm_r2, err);
19762306a36Sopenharmony_ci	__get_user_error(regs->regs[3], &sf->uc.uc_mcontext.arm_r3, err);
19862306a36Sopenharmony_ci	__get_user_error(regs->regs[4], &sf->uc.uc_mcontext.arm_r4, err);
19962306a36Sopenharmony_ci	__get_user_error(regs->regs[5], &sf->uc.uc_mcontext.arm_r5, err);
20062306a36Sopenharmony_ci	__get_user_error(regs->regs[6], &sf->uc.uc_mcontext.arm_r6, err);
20162306a36Sopenharmony_ci	__get_user_error(regs->regs[7], &sf->uc.uc_mcontext.arm_r7, err);
20262306a36Sopenharmony_ci	__get_user_error(regs->regs[8], &sf->uc.uc_mcontext.arm_r8, err);
20362306a36Sopenharmony_ci	__get_user_error(regs->regs[9], &sf->uc.uc_mcontext.arm_r9, err);
20462306a36Sopenharmony_ci	__get_user_error(regs->regs[10], &sf->uc.uc_mcontext.arm_r10, err);
20562306a36Sopenharmony_ci	__get_user_error(regs->regs[11], &sf->uc.uc_mcontext.arm_fp, err);
20662306a36Sopenharmony_ci	__get_user_error(regs->regs[12], &sf->uc.uc_mcontext.arm_ip, err);
20762306a36Sopenharmony_ci	__get_user_error(regs->compat_sp, &sf->uc.uc_mcontext.arm_sp, err);
20862306a36Sopenharmony_ci	__get_user_error(regs->compat_lr, &sf->uc.uc_mcontext.arm_lr, err);
20962306a36Sopenharmony_ci	__get_user_error(regs->pc, &sf->uc.uc_mcontext.arm_pc, err);
21062306a36Sopenharmony_ci	__get_user_error(psr, &sf->uc.uc_mcontext.arm_cpsr, err);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	regs->pstate = compat_psr_to_pstate(psr);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	/*
21562306a36Sopenharmony_ci	 * Avoid compat_sys_sigreturn() restarting.
21662306a36Sopenharmony_ci	 */
21762306a36Sopenharmony_ci	forget_syscall(regs);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	err |= !valid_user_regs(&regs->user_regs, current);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace;
22262306a36Sopenharmony_ci	if (err == 0 && system_supports_fpsimd())
22362306a36Sopenharmony_ci		err |= compat_restore_vfp_context(&aux->vfp);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return err;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE0(sigreturn)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct pt_regs *regs = current_pt_regs();
23162306a36Sopenharmony_ci	struct compat_sigframe __user *frame;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* Always make any pending restarted system calls return -EINTR */
23462306a36Sopenharmony_ci	current->restart_block.fn = do_no_restart_syscall;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/*
23762306a36Sopenharmony_ci	 * Since we stacked the signal on a 64-bit boundary,
23862306a36Sopenharmony_ci	 * then 'sp' should be word aligned here.  If it's
23962306a36Sopenharmony_ci	 * not, then the user is trying to mess with us.
24062306a36Sopenharmony_ci	 */
24162306a36Sopenharmony_ci	if (regs->compat_sp & 7)
24262306a36Sopenharmony_ci		goto badframe;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	frame = (struct compat_sigframe __user *)regs->compat_sp;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (!access_ok(frame, sizeof (*frame)))
24762306a36Sopenharmony_ci		goto badframe;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (compat_restore_sigframe(regs, frame))
25062306a36Sopenharmony_ci		goto badframe;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return regs->regs[0];
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cibadframe:
25562306a36Sopenharmony_ci	arm64_notify_segfault(regs->compat_sp);
25662306a36Sopenharmony_ci	return 0;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE0(rt_sigreturn)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct pt_regs *regs = current_pt_regs();
26262306a36Sopenharmony_ci	struct compat_rt_sigframe __user *frame;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	/* Always make any pending restarted system calls return -EINTR */
26562306a36Sopenharmony_ci	current->restart_block.fn = do_no_restart_syscall;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/*
26862306a36Sopenharmony_ci	 * Since we stacked the signal on a 64-bit boundary,
26962306a36Sopenharmony_ci	 * then 'sp' should be word aligned here.  If it's
27062306a36Sopenharmony_ci	 * not, then the user is trying to mess with us.
27162306a36Sopenharmony_ci	 */
27262306a36Sopenharmony_ci	if (regs->compat_sp & 7)
27362306a36Sopenharmony_ci		goto badframe;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	frame = (struct compat_rt_sigframe __user *)regs->compat_sp;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (!access_ok(frame, sizeof (*frame)))
27862306a36Sopenharmony_ci		goto badframe;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (compat_restore_sigframe(regs, &frame->sig))
28162306a36Sopenharmony_ci		goto badframe;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (compat_restore_altstack(&frame->sig.uc.uc_stack))
28462306a36Sopenharmony_ci		goto badframe;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return regs->regs[0];
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cibadframe:
28962306a36Sopenharmony_ci	arm64_notify_segfault(regs->compat_sp);
29062306a36Sopenharmony_ci	return 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic void __user *compat_get_sigframe(struct ksignal *ksig,
29462306a36Sopenharmony_ci					struct pt_regs *regs,
29562306a36Sopenharmony_ci					int framesize)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	compat_ulong_t sp = sigsp(regs->compat_sp, ksig);
29862306a36Sopenharmony_ci	void __user *frame;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/*
30162306a36Sopenharmony_ci	 * ATPCS B01 mandates 8-byte alignment
30262306a36Sopenharmony_ci	 */
30362306a36Sopenharmony_ci	frame = compat_ptr((compat_uptr_t)((sp - framesize) & ~7));
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/*
30662306a36Sopenharmony_ci	 * Check that we can actually write to the signal frame.
30762306a36Sopenharmony_ci	 */
30862306a36Sopenharmony_ci	if (!access_ok(frame, framesize))
30962306a36Sopenharmony_ci		frame = NULL;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return frame;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
31562306a36Sopenharmony_ci				compat_ulong_t __user *rc, void __user *frame,
31662306a36Sopenharmony_ci				int usig)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler);
31962306a36Sopenharmony_ci	compat_ulong_t retcode;
32062306a36Sopenharmony_ci	compat_ulong_t spsr = regs->pstate & ~(PSR_f | PSR_AA32_E_BIT);
32162306a36Sopenharmony_ci	int thumb;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* Check if the handler is written for ARM or Thumb */
32462306a36Sopenharmony_ci	thumb = handler & 1;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (thumb)
32762306a36Sopenharmony_ci		spsr |= PSR_AA32_T_BIT;
32862306a36Sopenharmony_ci	else
32962306a36Sopenharmony_ci		spsr &= ~PSR_AA32_T_BIT;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* The IT state must be cleared for both ARM and Thumb-2 */
33262306a36Sopenharmony_ci	spsr &= ~PSR_AA32_IT_MASK;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* Restore the original endianness */
33562306a36Sopenharmony_ci	spsr |= PSR_AA32_ENDSTATE;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if (ka->sa.sa_flags & SA_RESTORER) {
33862306a36Sopenharmony_ci		retcode = ptr_to_compat(ka->sa.sa_restorer);
33962306a36Sopenharmony_ci	} else {
34062306a36Sopenharmony_ci		/* Set up sigreturn pointer */
34162306a36Sopenharmony_ci		unsigned int idx = thumb << 1;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		if (ka->sa.sa_flags & SA_SIGINFO)
34462306a36Sopenharmony_ci			idx += 3;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		retcode = (unsigned long)current->mm->context.sigpage +
34762306a36Sopenharmony_ci			  (idx << 2) + thumb;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	regs->regs[0]	= usig;
35162306a36Sopenharmony_ci	regs->compat_sp	= ptr_to_compat(frame);
35262306a36Sopenharmony_ci	regs->compat_lr	= retcode;
35362306a36Sopenharmony_ci	regs->pc	= handler;
35462306a36Sopenharmony_ci	regs->pstate	= spsr;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic int compat_setup_sigframe(struct compat_sigframe __user *sf,
35862306a36Sopenharmony_ci				 struct pt_regs *regs, sigset_t *set)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct compat_aux_sigframe __user *aux;
36162306a36Sopenharmony_ci	unsigned long psr = pstate_to_compat_psr(regs->pstate);
36262306a36Sopenharmony_ci	int err = 0;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	__put_user_error(regs->regs[0], &sf->uc.uc_mcontext.arm_r0, err);
36562306a36Sopenharmony_ci	__put_user_error(regs->regs[1], &sf->uc.uc_mcontext.arm_r1, err);
36662306a36Sopenharmony_ci	__put_user_error(regs->regs[2], &sf->uc.uc_mcontext.arm_r2, err);
36762306a36Sopenharmony_ci	__put_user_error(regs->regs[3], &sf->uc.uc_mcontext.arm_r3, err);
36862306a36Sopenharmony_ci	__put_user_error(regs->regs[4], &sf->uc.uc_mcontext.arm_r4, err);
36962306a36Sopenharmony_ci	__put_user_error(regs->regs[5], &sf->uc.uc_mcontext.arm_r5, err);
37062306a36Sopenharmony_ci	__put_user_error(regs->regs[6], &sf->uc.uc_mcontext.arm_r6, err);
37162306a36Sopenharmony_ci	__put_user_error(regs->regs[7], &sf->uc.uc_mcontext.arm_r7, err);
37262306a36Sopenharmony_ci	__put_user_error(regs->regs[8], &sf->uc.uc_mcontext.arm_r8, err);
37362306a36Sopenharmony_ci	__put_user_error(regs->regs[9], &sf->uc.uc_mcontext.arm_r9, err);
37462306a36Sopenharmony_ci	__put_user_error(regs->regs[10], &sf->uc.uc_mcontext.arm_r10, err);
37562306a36Sopenharmony_ci	__put_user_error(regs->regs[11], &sf->uc.uc_mcontext.arm_fp, err);
37662306a36Sopenharmony_ci	__put_user_error(regs->regs[12], &sf->uc.uc_mcontext.arm_ip, err);
37762306a36Sopenharmony_ci	__put_user_error(regs->compat_sp, &sf->uc.uc_mcontext.arm_sp, err);
37862306a36Sopenharmony_ci	__put_user_error(regs->compat_lr, &sf->uc.uc_mcontext.arm_lr, err);
37962306a36Sopenharmony_ci	__put_user_error(regs->pc, &sf->uc.uc_mcontext.arm_pc, err);
38062306a36Sopenharmony_ci	__put_user_error(psr, &sf->uc.uc_mcontext.arm_cpsr, err);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	__put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err);
38362306a36Sopenharmony_ci	/* set the compat FSR WnR */
38462306a36Sopenharmony_ci	__put_user_error(!!(current->thread.fault_code & ESR_ELx_WNR) <<
38562306a36Sopenharmony_ci			 FSR_WRITE_SHIFT, &sf->uc.uc_mcontext.error_code, err);
38662306a36Sopenharmony_ci	__put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
38762306a36Sopenharmony_ci	__put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	err |= put_sigset_t(&sf->uc.uc_sigmask, set);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (err == 0 && system_supports_fpsimd())
39462306a36Sopenharmony_ci		err |= compat_preserve_vfp_context(&aux->vfp);
39562306a36Sopenharmony_ci	__put_user_error(0, &aux->end_magic, err);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return err;
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci/*
40162306a36Sopenharmony_ci * 32-bit signal handling routines called from signal.c
40262306a36Sopenharmony_ci */
40362306a36Sopenharmony_ciint compat_setup_rt_frame(int usig, struct ksignal *ksig,
40462306a36Sopenharmony_ci			  sigset_t *set, struct pt_regs *regs)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct compat_rt_sigframe __user *frame;
40762306a36Sopenharmony_ci	int err = 0;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	frame = compat_get_sigframe(ksig, regs, sizeof(*frame));
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (!frame)
41262306a36Sopenharmony_ci		return 1;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	__put_user_error(0, &frame->sig.uc.uc_flags, err);
41762306a36Sopenharmony_ci	__put_user_error(0, &frame->sig.uc.uc_link, err);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	err |= __compat_save_altstack(&frame->sig.uc.uc_stack, regs->compat_sp);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	err |= compat_setup_sigframe(&frame->sig, regs, set);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (err == 0) {
42462306a36Sopenharmony_ci		compat_setup_return(regs, &ksig->ka, frame->sig.retcode, frame, usig);
42562306a36Sopenharmony_ci		regs->regs[1] = (compat_ulong_t)(unsigned long)&frame->info;
42662306a36Sopenharmony_ci		regs->regs[2] = (compat_ulong_t)(unsigned long)&frame->sig.uc;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return err;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciint compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
43362306a36Sopenharmony_ci		       struct pt_regs *regs)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct compat_sigframe __user *frame;
43662306a36Sopenharmony_ci	int err = 0;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	frame = compat_get_sigframe(ksig, regs, sizeof(*frame));
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (!frame)
44162306a36Sopenharmony_ci		return 1;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	__put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	err |= compat_setup_sigframe(frame, regs, set);
44662306a36Sopenharmony_ci	if (err == 0)
44762306a36Sopenharmony_ci		compat_setup_return(regs, &ksig->ka, frame->retcode, frame, usig);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	return err;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_civoid compat_setup_restart_syscall(struct pt_regs *regs)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci       regs->regs[7] = __NR_compat_restart_syscall;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci/*
45862306a36Sopenharmony_ci * Compile-time assertions for siginfo_t offsets. Check NSIG* as well, as
45962306a36Sopenharmony_ci * changes likely come with new fields that should be added below.
46062306a36Sopenharmony_ci */
46162306a36Sopenharmony_cistatic_assert(NSIGILL	== 11);
46262306a36Sopenharmony_cistatic_assert(NSIGFPE	== 15);
46362306a36Sopenharmony_cistatic_assert(NSIGSEGV	== 10);
46462306a36Sopenharmony_cistatic_assert(NSIGBUS	== 5);
46562306a36Sopenharmony_cistatic_assert(NSIGTRAP	== 6);
46662306a36Sopenharmony_cistatic_assert(NSIGCHLD	== 6);
46762306a36Sopenharmony_cistatic_assert(NSIGSYS	== 2);
46862306a36Sopenharmony_cistatic_assert(sizeof(compat_siginfo_t) == 128);
46962306a36Sopenharmony_cistatic_assert(__alignof__(compat_siginfo_t) == 4);
47062306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_signo)	== 0x00);
47162306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_errno)	== 0x04);
47262306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_code)	== 0x08);
47362306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_pid)	== 0x0c);
47462306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_uid)	== 0x10);
47562306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_tid)	== 0x0c);
47662306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_overrun)	== 0x10);
47762306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_status)	== 0x14);
47862306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_utime)	== 0x18);
47962306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_stime)	== 0x1c);
48062306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_value)	== 0x14);
48162306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_int)	== 0x14);
48262306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_ptr)	== 0x14);
48362306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_addr)	== 0x0c);
48462306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_addr_lsb)	== 0x10);
48562306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_lower)	== 0x14);
48662306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_upper)	== 0x18);
48762306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_pkey)	== 0x14);
48862306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_perf_data)	== 0x10);
48962306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_perf_type)	== 0x14);
49062306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_perf_flags)	== 0x18);
49162306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_band)	== 0x0c);
49262306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_fd)		== 0x10);
49362306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_call_addr)	== 0x0c);
49462306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_syscall)	== 0x10);
49562306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_arch)	== 0x14);
496