162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*  arch/sparc64/kernel/signal32.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 1991, 1992  Linus Torvalds
562306a36Sopenharmony_ci *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
662306a36Sopenharmony_ci *  Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
762306a36Sopenharmony_ci *  Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
862306a36Sopenharmony_ci *  Copyright (C) 1997,1998 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/sched.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/signal.h>
1462306a36Sopenharmony_ci#include <linux/errno.h>
1562306a36Sopenharmony_ci#include <linux/wait.h>
1662306a36Sopenharmony_ci#include <linux/ptrace.h>
1762306a36Sopenharmony_ci#include <linux/unistd.h>
1862306a36Sopenharmony_ci#include <linux/mm.h>
1962306a36Sopenharmony_ci#include <linux/tty.h>
2062306a36Sopenharmony_ci#include <linux/binfmts.h>
2162306a36Sopenharmony_ci#include <linux/compat.h>
2262306a36Sopenharmony_ci#include <linux/bitops.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <linux/uaccess.h>
2562306a36Sopenharmony_ci#include <asm/ptrace.h>
2662306a36Sopenharmony_ci#include <asm/psrcompat.h>
2762306a36Sopenharmony_ci#include <asm/fpumacro.h>
2862306a36Sopenharmony_ci#include <asm/visasm.h>
2962306a36Sopenharmony_ci#include <asm/compat_signal.h>
3062306a36Sopenharmony_ci#include <asm/switch_to.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "sigutil.h"
3362306a36Sopenharmony_ci#include "kernel.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* This magic should be in g_upper[0] for all upper parts
3662306a36Sopenharmony_ci * to be valid.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci#define SIGINFO_EXTRA_V8PLUS_MAGIC	0x130e269
3962306a36Sopenharmony_citypedef struct {
4062306a36Sopenharmony_ci	unsigned int g_upper[8];
4162306a36Sopenharmony_ci	unsigned int o_upper[8];
4262306a36Sopenharmony_ci	unsigned int asi;
4362306a36Sopenharmony_ci} siginfo_extra_v8plus_t;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct signal_frame32 {
4662306a36Sopenharmony_ci	struct sparc_stackf32	ss;
4762306a36Sopenharmony_ci	__siginfo32_t		info;
4862306a36Sopenharmony_ci	/* __siginfo_fpu_t * */ u32 fpu_save;
4962306a36Sopenharmony_ci	unsigned int		insns[2];
5062306a36Sopenharmony_ci	unsigned int		extramask[_COMPAT_NSIG_WORDS - 1];
5162306a36Sopenharmony_ci	unsigned int		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
5262306a36Sopenharmony_ci	/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
5362306a36Sopenharmony_ci	siginfo_extra_v8plus_t	v8plus;
5462306a36Sopenharmony_ci	/* __siginfo_rwin_t * */u32 rwin_save;
5562306a36Sopenharmony_ci} __attribute__((aligned(8)));
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct rt_signal_frame32 {
5862306a36Sopenharmony_ci	struct sparc_stackf32	ss;
5962306a36Sopenharmony_ci	compat_siginfo_t	info;
6062306a36Sopenharmony_ci	struct pt_regs32	regs;
6162306a36Sopenharmony_ci	compat_sigset_t		mask;
6262306a36Sopenharmony_ci	/* __siginfo_fpu_t * */ u32 fpu_save;
6362306a36Sopenharmony_ci	unsigned int		insns[2];
6462306a36Sopenharmony_ci	compat_stack_t		stack;
6562306a36Sopenharmony_ci	unsigned int		extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
6662306a36Sopenharmony_ci	/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
6762306a36Sopenharmony_ci	siginfo_extra_v8plus_t	v8plus;
6862306a36Sopenharmony_ci	/* __siginfo_rwin_t * */u32 rwin_save;
6962306a36Sopenharmony_ci} __attribute__((aligned(8)));
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Checks if the fp is valid.  We always build signal frames which are
7262306a36Sopenharmony_ci * 16-byte aligned, therefore we can always enforce that the restore
7362306a36Sopenharmony_ci * frame has that property as well.
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_cistatic bool invalid_frame_pointer(void __user *fp, int fplen)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	if ((((unsigned long) fp) & 15) ||
7862306a36Sopenharmony_ci	    ((unsigned long)fp) > 0x100000000ULL - fplen)
7962306a36Sopenharmony_ci		return true;
8062306a36Sopenharmony_ci	return false;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_civoid do_sigreturn32(struct pt_regs *regs)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct signal_frame32 __user *sf;
8662306a36Sopenharmony_ci	compat_uptr_t fpu_save;
8762306a36Sopenharmony_ci	compat_uptr_t rwin_save;
8862306a36Sopenharmony_ci	unsigned int psr, ufp;
8962306a36Sopenharmony_ci	unsigned int pc, npc;
9062306a36Sopenharmony_ci	sigset_t set;
9162306a36Sopenharmony_ci	compat_sigset_t seta;
9262306a36Sopenharmony_ci	int err, i;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* Always make any pending restarted system calls return -EINTR */
9562306a36Sopenharmony_ci	current->restart_block.fn = do_no_restart_syscall;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	synchronize_user_stack();
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
10062306a36Sopenharmony_ci	sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* 1. Make sure we are not getting garbage from the user */
10362306a36Sopenharmony_ci	if (invalid_frame_pointer(sf, sizeof(*sf)))
10462306a36Sopenharmony_ci		goto segv;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
10762306a36Sopenharmony_ci		goto segv;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (ufp & 0x7)
11062306a36Sopenharmony_ci		goto segv;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (__get_user(pc, &sf->info.si_regs.pc) ||
11362306a36Sopenharmony_ci	    __get_user(npc, &sf->info.si_regs.npc))
11462306a36Sopenharmony_ci		goto segv;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if ((pc | npc) & 3)
11762306a36Sopenharmony_ci		goto segv;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (test_thread_flag(TIF_32BIT)) {
12062306a36Sopenharmony_ci		pc &= 0xffffffff;
12162306a36Sopenharmony_ci		npc &= 0xffffffff;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci	regs->tpc = pc;
12462306a36Sopenharmony_ci	regs->tnpc = npc;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* 2. Restore the state */
12762306a36Sopenharmony_ci	err = __get_user(regs->y, &sf->info.si_regs.y);
12862306a36Sopenharmony_ci	err |= __get_user(psr, &sf->info.si_regs.psr);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	for (i = UREG_G1; i <= UREG_I7; i++)
13162306a36Sopenharmony_ci		err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
13262306a36Sopenharmony_ci	if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
13362306a36Sopenharmony_ci		err |= __get_user(i, &sf->v8plus.g_upper[0]);
13462306a36Sopenharmony_ci		if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
13562306a36Sopenharmony_ci			unsigned long asi;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci			for (i = UREG_G1; i <= UREG_I7; i++)
13862306a36Sopenharmony_ci				err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
13962306a36Sopenharmony_ci			err |= __get_user(asi, &sf->v8plus.asi);
14062306a36Sopenharmony_ci			regs->tstate &= ~TSTATE_ASI;
14162306a36Sopenharmony_ci			regs->tstate |= ((asi & 0xffUL) << 24UL);
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* User can only change condition codes in %tstate. */
14662306a36Sopenharmony_ci	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
14762306a36Sopenharmony_ci	regs->tstate |= psr_to_tstate_icc(psr);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* Prevent syscall restart.  */
15062306a36Sopenharmony_ci	pt_regs_clear_syscall(regs);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	err |= __get_user(fpu_save, &sf->fpu_save);
15362306a36Sopenharmony_ci	if (!err && fpu_save)
15462306a36Sopenharmony_ci		err |= restore_fpu_state(regs, compat_ptr(fpu_save));
15562306a36Sopenharmony_ci	err |= __get_user(rwin_save, &sf->rwin_save);
15662306a36Sopenharmony_ci	if (!err && rwin_save) {
15762306a36Sopenharmony_ci		if (restore_rwin_state(compat_ptr(rwin_save)))
15862306a36Sopenharmony_ci			goto segv;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci	err |= __get_user(seta.sig[0], &sf->info.si_mask);
16162306a36Sopenharmony_ci	err |= copy_from_user(&seta.sig[1], &sf->extramask,
16262306a36Sopenharmony_ci			      (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
16362306a36Sopenharmony_ci	if (err)
16462306a36Sopenharmony_ci	    	goto segv;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
16762306a36Sopenharmony_ci	set_current_blocked(&set);
16862306a36Sopenharmony_ci	return;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cisegv:
17162306a36Sopenharmony_ci	force_sig(SIGSEGV);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ciasmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct rt_signal_frame32 __user *sf;
17762306a36Sopenharmony_ci	unsigned int psr, pc, npc, ufp;
17862306a36Sopenharmony_ci	compat_uptr_t fpu_save;
17962306a36Sopenharmony_ci	compat_uptr_t rwin_save;
18062306a36Sopenharmony_ci	sigset_t set;
18162306a36Sopenharmony_ci	int err, i;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Always make any pending restarted system calls return -EINTR */
18462306a36Sopenharmony_ci	current->restart_block.fn = do_no_restart_syscall;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	synchronize_user_stack();
18762306a36Sopenharmony_ci	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
18862306a36Sopenharmony_ci	sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* 1. Make sure we are not getting garbage from the user */
19162306a36Sopenharmony_ci	if (invalid_frame_pointer(sf, sizeof(*sf)))
19262306a36Sopenharmony_ci		goto segv;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
19562306a36Sopenharmony_ci		goto segv;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (ufp & 0x7)
19862306a36Sopenharmony_ci		goto segv;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (__get_user(pc, &sf->regs.pc) ||
20162306a36Sopenharmony_ci	    __get_user(npc, &sf->regs.npc))
20262306a36Sopenharmony_ci		goto segv;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if ((pc | npc) & 3)
20562306a36Sopenharmony_ci		goto segv;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (test_thread_flag(TIF_32BIT)) {
20862306a36Sopenharmony_ci		pc &= 0xffffffff;
20962306a36Sopenharmony_ci		npc &= 0xffffffff;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	regs->tpc = pc;
21262306a36Sopenharmony_ci	regs->tnpc = npc;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	/* 2. Restore the state */
21562306a36Sopenharmony_ci	err = __get_user(regs->y, &sf->regs.y);
21662306a36Sopenharmony_ci	err |= __get_user(psr, &sf->regs.psr);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	for (i = UREG_G1; i <= UREG_I7; i++)
21962306a36Sopenharmony_ci		err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]);
22062306a36Sopenharmony_ci	if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
22162306a36Sopenharmony_ci		err |= __get_user(i, &sf->v8plus.g_upper[0]);
22262306a36Sopenharmony_ci		if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
22362306a36Sopenharmony_ci			unsigned long asi;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci			for (i = UREG_G1; i <= UREG_I7; i++)
22662306a36Sopenharmony_ci				err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
22762306a36Sopenharmony_ci			err |= __get_user(asi, &sf->v8plus.asi);
22862306a36Sopenharmony_ci			regs->tstate &= ~TSTATE_ASI;
22962306a36Sopenharmony_ci			regs->tstate |= ((asi & 0xffUL) << 24UL);
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* User can only change condition codes in %tstate. */
23462306a36Sopenharmony_ci	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
23562306a36Sopenharmony_ci	regs->tstate |= psr_to_tstate_icc(psr);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* Prevent syscall restart.  */
23862306a36Sopenharmony_ci	pt_regs_clear_syscall(regs);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	err |= __get_user(fpu_save, &sf->fpu_save);
24162306a36Sopenharmony_ci	if (!err && fpu_save)
24262306a36Sopenharmony_ci		err |= restore_fpu_state(regs, compat_ptr(fpu_save));
24362306a36Sopenharmony_ci	err |= get_compat_sigset(&set, &sf->mask);
24462306a36Sopenharmony_ci	err |= compat_restore_altstack(&sf->stack);
24562306a36Sopenharmony_ci	if (err)
24662306a36Sopenharmony_ci		goto segv;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	err |= __get_user(rwin_save, &sf->rwin_save);
24962306a36Sopenharmony_ci	if (!err && rwin_save) {
25062306a36Sopenharmony_ci		if (restore_rwin_state(compat_ptr(rwin_save)))
25162306a36Sopenharmony_ci			goto segv;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	set_current_blocked(&set);
25562306a36Sopenharmony_ci	return;
25662306a36Sopenharmony_cisegv:
25762306a36Sopenharmony_ci	force_sig(SIGSEGV);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	unsigned long sp;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
26562306a36Sopenharmony_ci	sp = regs->u_regs[UREG_FP];
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/*
26862306a36Sopenharmony_ci	 * If we are on the alternate signal stack and would overflow it, don't.
26962306a36Sopenharmony_ci	 * Return an always-bogus address instead so we will die with SIGSEGV.
27062306a36Sopenharmony_ci	 */
27162306a36Sopenharmony_ci	if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
27262306a36Sopenharmony_ci		return (void __user *) -1L;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* This is the X/Open sanctioned signal stack switching.  */
27562306a36Sopenharmony_ci	sp = sigsp(sp, ksig) - framesize;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* Always align the stack frame.  This handles two cases.  First,
27862306a36Sopenharmony_ci	 * sigaltstack need not be mindful of platform specific stack
27962306a36Sopenharmony_ci	 * alignment.  Second, if we took this signal because the stack
28062306a36Sopenharmony_ci	 * is not aligned properly, we'd like to take the signal cleanly
28162306a36Sopenharmony_ci	 * and report that.
28262306a36Sopenharmony_ci	 */
28362306a36Sopenharmony_ci	sp &= ~15UL;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return (void __user *) sp;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci/* The I-cache flush instruction only works in the primary ASI, which
28962306a36Sopenharmony_ci * right now is the nucleus, aka. kernel space.
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci * Therefore we have to kick the instructions out using the kernel
29262306a36Sopenharmony_ci * side linear mapping of the physical address backing the user
29362306a36Sopenharmony_ci * instructions.
29462306a36Sopenharmony_ci */
29562306a36Sopenharmony_cistatic void flush_signal_insns(unsigned long address)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	unsigned long pstate, paddr;
29862306a36Sopenharmony_ci	pte_t *ptep, pte;
29962306a36Sopenharmony_ci	pgd_t *pgdp;
30062306a36Sopenharmony_ci	p4d_t *p4dp;
30162306a36Sopenharmony_ci	pud_t *pudp;
30262306a36Sopenharmony_ci	pmd_t *pmdp;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/* Commit all stores of the instructions we are about to flush.  */
30562306a36Sopenharmony_ci	wmb();
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* Disable cross-call reception.  In this way even a very wide
30862306a36Sopenharmony_ci	 * munmap() on another cpu can't tear down the page table
30962306a36Sopenharmony_ci	 * hierarchy from underneath us, since that can't complete
31062306a36Sopenharmony_ci	 * until the IPI tlb flush returns.
31162306a36Sopenharmony_ci	 */
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
31462306a36Sopenharmony_ci	__asm__ __volatile__("wrpr %0, %1, %%pstate"
31562306a36Sopenharmony_ci				: : "r" (pstate), "i" (PSTATE_IE));
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	pgdp = pgd_offset(current->mm, address);
31862306a36Sopenharmony_ci	if (pgd_none(*pgdp))
31962306a36Sopenharmony_ci		goto out_irqs_on;
32062306a36Sopenharmony_ci	p4dp = p4d_offset(pgdp, address);
32162306a36Sopenharmony_ci	if (p4d_none(*p4dp))
32262306a36Sopenharmony_ci		goto out_irqs_on;
32362306a36Sopenharmony_ci	pudp = pud_offset(p4dp, address);
32462306a36Sopenharmony_ci	if (pud_none(*pudp))
32562306a36Sopenharmony_ci		goto out_irqs_on;
32662306a36Sopenharmony_ci	pmdp = pmd_offset(pudp, address);
32762306a36Sopenharmony_ci	if (pmd_none(*pmdp))
32862306a36Sopenharmony_ci		goto out_irqs_on;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	ptep = pte_offset_map(pmdp, address);
33162306a36Sopenharmony_ci	if (!ptep)
33262306a36Sopenharmony_ci		goto out_irqs_on;
33362306a36Sopenharmony_ci	pte = *ptep;
33462306a36Sopenharmony_ci	if (!pte_present(pte))
33562306a36Sopenharmony_ci		goto out_unmap;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	paddr = (unsigned long) page_address(pte_page(pte));
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	__asm__ __volatile__("flush	%0 + %1"
34062306a36Sopenharmony_ci			     : /* no outputs */
34162306a36Sopenharmony_ci			     : "r" (paddr),
34262306a36Sopenharmony_ci			       "r" (address & (PAGE_SIZE - 1))
34362306a36Sopenharmony_ci			     : "memory");
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ciout_unmap:
34662306a36Sopenharmony_ci	pte_unmap(ptep);
34762306a36Sopenharmony_ciout_irqs_on:
34862306a36Sopenharmony_ci	__asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int setup_frame32(struct ksignal *ksig, struct pt_regs *regs,
35362306a36Sopenharmony_ci			 sigset_t *oldset)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct signal_frame32 __user *sf;
35662306a36Sopenharmony_ci	int i, err, wsaved;
35762306a36Sopenharmony_ci	void __user *tail;
35862306a36Sopenharmony_ci	int sigframe_size;
35962306a36Sopenharmony_ci	u32 psr;
36062306a36Sopenharmony_ci	compat_sigset_t seta;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* 1. Make sure everything is clean */
36362306a36Sopenharmony_ci	synchronize_user_stack();
36462306a36Sopenharmony_ci	save_and_clear_fpu();
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	wsaved = get_thread_wsaved();
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	sigframe_size = sizeof(*sf);
36962306a36Sopenharmony_ci	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
37062306a36Sopenharmony_ci		sigframe_size += sizeof(__siginfo_fpu_t);
37162306a36Sopenharmony_ci	if (wsaved)
37262306a36Sopenharmony_ci		sigframe_size += sizeof(__siginfo_rwin_t);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	sf = (struct signal_frame32 __user *)
37562306a36Sopenharmony_ci		get_sigframe(ksig, regs, sigframe_size);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (invalid_frame_pointer(sf, sigframe_size)) {
37862306a36Sopenharmony_ci		if (show_unhandled_signals)
37962306a36Sopenharmony_ci			pr_info("%s[%d] bad frame in setup_frame32: %08lx TPC %08lx O7 %08lx\n",
38062306a36Sopenharmony_ci				current->comm, current->pid, (unsigned long)sf,
38162306a36Sopenharmony_ci				regs->tpc, regs->u_regs[UREG_I7]);
38262306a36Sopenharmony_ci		force_sigsegv(ksig->sig);
38362306a36Sopenharmony_ci		return -EINVAL;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	tail = (sf + 1);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* 2. Save the current process state */
38962306a36Sopenharmony_ci	if (test_thread_flag(TIF_32BIT)) {
39062306a36Sopenharmony_ci		regs->tpc &= 0xffffffff;
39162306a36Sopenharmony_ci		regs->tnpc &= 0xffffffff;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci	err  = put_user(regs->tpc, &sf->info.si_regs.pc);
39462306a36Sopenharmony_ci	err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
39562306a36Sopenharmony_ci	err |= __put_user(regs->y, &sf->info.si_regs.y);
39662306a36Sopenharmony_ci	psr = tstate_to_psr(regs->tstate);
39762306a36Sopenharmony_ci	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
39862306a36Sopenharmony_ci		psr |= PSR_EF;
39962306a36Sopenharmony_ci	err |= __put_user(psr, &sf->info.si_regs.psr);
40062306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
40162306a36Sopenharmony_ci		err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
40262306a36Sopenharmony_ci	err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
40362306a36Sopenharmony_ci	err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
40462306a36Sopenharmony_ci	for (i = 1; i < 16; i++)
40562306a36Sopenharmony_ci		err |= __put_user(((u32 *)regs->u_regs)[2*i],
40662306a36Sopenharmony_ci				  &sf->v8plus.g_upper[i]);
40762306a36Sopenharmony_ci	err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
40862306a36Sopenharmony_ci			  &sf->v8plus.asi);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (psr & PSR_EF) {
41162306a36Sopenharmony_ci		__siginfo_fpu_t __user *fp = tail;
41262306a36Sopenharmony_ci		tail += sizeof(*fp);
41362306a36Sopenharmony_ci		err |= save_fpu_state(regs, fp);
41462306a36Sopenharmony_ci		err |= __put_user((u64)fp, &sf->fpu_save);
41562306a36Sopenharmony_ci	} else {
41662306a36Sopenharmony_ci		err |= __put_user(0, &sf->fpu_save);
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci	if (wsaved) {
41962306a36Sopenharmony_ci		__siginfo_rwin_t __user *rwp = tail;
42062306a36Sopenharmony_ci		tail += sizeof(*rwp);
42162306a36Sopenharmony_ci		err |= save_rwin_state(wsaved, rwp);
42262306a36Sopenharmony_ci		err |= __put_user((u64)rwp, &sf->rwin_save);
42362306a36Sopenharmony_ci		set_thread_wsaved(0);
42462306a36Sopenharmony_ci	} else {
42562306a36Sopenharmony_ci		err |= __put_user(0, &sf->rwin_save);
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	/* If these change we need to know - assignments to seta relies on these sizes */
42962306a36Sopenharmony_ci	BUILD_BUG_ON(_NSIG_WORDS != 1);
43062306a36Sopenharmony_ci	BUILD_BUG_ON(_COMPAT_NSIG_WORDS != 2);
43162306a36Sopenharmony_ci	seta.sig[1] = (oldset->sig[0] >> 32);
43262306a36Sopenharmony_ci	seta.sig[0] = oldset->sig[0];
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	err |= __put_user(seta.sig[0], &sf->info.si_mask);
43562306a36Sopenharmony_ci	err |= __copy_to_user(sf->extramask, &seta.sig[1],
43662306a36Sopenharmony_ci			      (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (!wsaved) {
43962306a36Sopenharmony_ci		err |= raw_copy_in_user((u32 __user *)sf,
44062306a36Sopenharmony_ci					(u32 __user *)(regs->u_regs[UREG_FP]),
44162306a36Sopenharmony_ci					sizeof(struct reg_window32));
44262306a36Sopenharmony_ci	} else {
44362306a36Sopenharmony_ci		struct reg_window *rp;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		rp = &current_thread_info()->reg_window[wsaved - 1];
44662306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
44762306a36Sopenharmony_ci			err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
44862306a36Sopenharmony_ci		for (i = 0; i < 6; i++)
44962306a36Sopenharmony_ci			err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
45062306a36Sopenharmony_ci		err |= __put_user(rp->ins[6], &sf->ss.fp);
45162306a36Sopenharmony_ci		err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci	if (err)
45462306a36Sopenharmony_ci		return err;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/* 3. signal handler back-trampoline and parameters */
45762306a36Sopenharmony_ci	regs->u_regs[UREG_FP] = (unsigned long) sf;
45862306a36Sopenharmony_ci	regs->u_regs[UREG_I0] = ksig->sig;
45962306a36Sopenharmony_ci	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
46062306a36Sopenharmony_ci	regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* 4. signal handler */
46362306a36Sopenharmony_ci	regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;
46462306a36Sopenharmony_ci	regs->tnpc = (regs->tpc + 4);
46562306a36Sopenharmony_ci	if (test_thread_flag(TIF_32BIT)) {
46662306a36Sopenharmony_ci		regs->tpc &= 0xffffffff;
46762306a36Sopenharmony_ci		regs->tnpc &= 0xffffffff;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* 5. return to kernel instructions */
47162306a36Sopenharmony_ci	if (ksig->ka.ka_restorer) {
47262306a36Sopenharmony_ci		regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
47362306a36Sopenharmony_ci	} else {
47462306a36Sopenharmony_ci		unsigned long address = ((unsigned long)&(sf->insns[0]));
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		err  = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/
47962306a36Sopenharmony_ci		err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
48062306a36Sopenharmony_ci		if (err)
48162306a36Sopenharmony_ci			return err;
48262306a36Sopenharmony_ci		flush_signal_insns(address);
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci	return 0;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs,
48862306a36Sopenharmony_ci			    sigset_t *oldset)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	struct rt_signal_frame32 __user *sf;
49162306a36Sopenharmony_ci	int i, err, wsaved;
49262306a36Sopenharmony_ci	void __user *tail;
49362306a36Sopenharmony_ci	int sigframe_size;
49462306a36Sopenharmony_ci	u32 psr;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	/* 1. Make sure everything is clean */
49762306a36Sopenharmony_ci	synchronize_user_stack();
49862306a36Sopenharmony_ci	save_and_clear_fpu();
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	wsaved = get_thread_wsaved();
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	sigframe_size = sizeof(*sf);
50362306a36Sopenharmony_ci	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
50462306a36Sopenharmony_ci		sigframe_size += sizeof(__siginfo_fpu_t);
50562306a36Sopenharmony_ci	if (wsaved)
50662306a36Sopenharmony_ci		sigframe_size += sizeof(__siginfo_rwin_t);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	sf = (struct rt_signal_frame32 __user *)
50962306a36Sopenharmony_ci		get_sigframe(ksig, regs, sigframe_size);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (invalid_frame_pointer(sf, sigframe_size)) {
51262306a36Sopenharmony_ci		if (show_unhandled_signals)
51362306a36Sopenharmony_ci			pr_info("%s[%d] bad frame in setup_rt_frame32: %08lx TPC %08lx O7 %08lx\n",
51462306a36Sopenharmony_ci				current->comm, current->pid, (unsigned long)sf,
51562306a36Sopenharmony_ci				regs->tpc, regs->u_regs[UREG_I7]);
51662306a36Sopenharmony_ci		force_sigsegv(ksig->sig);
51762306a36Sopenharmony_ci		return -EINVAL;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	tail = (sf + 1);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	/* 2. Save the current process state */
52362306a36Sopenharmony_ci	if (test_thread_flag(TIF_32BIT)) {
52462306a36Sopenharmony_ci		regs->tpc &= 0xffffffff;
52562306a36Sopenharmony_ci		regs->tnpc &= 0xffffffff;
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci	err  = put_user(regs->tpc, &sf->regs.pc);
52862306a36Sopenharmony_ci	err |= __put_user(regs->tnpc, &sf->regs.npc);
52962306a36Sopenharmony_ci	err |= __put_user(regs->y, &sf->regs.y);
53062306a36Sopenharmony_ci	psr = tstate_to_psr(regs->tstate);
53162306a36Sopenharmony_ci	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
53262306a36Sopenharmony_ci		psr |= PSR_EF;
53362306a36Sopenharmony_ci	err |= __put_user(psr, &sf->regs.psr);
53462306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
53562306a36Sopenharmony_ci		err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
53662306a36Sopenharmony_ci	err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
53762306a36Sopenharmony_ci	err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
53862306a36Sopenharmony_ci	for (i = 1; i < 16; i++)
53962306a36Sopenharmony_ci		err |= __put_user(((u32 *)regs->u_regs)[2*i],
54062306a36Sopenharmony_ci				  &sf->v8plus.g_upper[i]);
54162306a36Sopenharmony_ci	err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
54262306a36Sopenharmony_ci			  &sf->v8plus.asi);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	if (psr & PSR_EF) {
54562306a36Sopenharmony_ci		__siginfo_fpu_t __user *fp = tail;
54662306a36Sopenharmony_ci		tail += sizeof(*fp);
54762306a36Sopenharmony_ci		err |= save_fpu_state(regs, fp);
54862306a36Sopenharmony_ci		err |= __put_user((u64)fp, &sf->fpu_save);
54962306a36Sopenharmony_ci	} else {
55062306a36Sopenharmony_ci		err |= __put_user(0, &sf->fpu_save);
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci	if (wsaved) {
55362306a36Sopenharmony_ci		__siginfo_rwin_t __user *rwp = tail;
55462306a36Sopenharmony_ci		tail += sizeof(*rwp);
55562306a36Sopenharmony_ci		err |= save_rwin_state(wsaved, rwp);
55662306a36Sopenharmony_ci		err |= __put_user((u64)rwp, &sf->rwin_save);
55762306a36Sopenharmony_ci		set_thread_wsaved(0);
55862306a36Sopenharmony_ci	} else {
55962306a36Sopenharmony_ci		err |= __put_user(0, &sf->rwin_save);
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/* Update the siginfo structure.  */
56362306a36Sopenharmony_ci	err |= copy_siginfo_to_user32(&sf->info, &ksig->info);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Setup sigaltstack */
56662306a36Sopenharmony_ci	err |= __compat_save_altstack(&sf->stack, regs->u_regs[UREG_FP]);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	err |= put_compat_sigset(&sf->mask, oldset, sizeof(compat_sigset_t));
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (!wsaved) {
57162306a36Sopenharmony_ci		err |= raw_copy_in_user((u32 __user *)sf,
57262306a36Sopenharmony_ci					(u32 __user *)(regs->u_regs[UREG_FP]),
57362306a36Sopenharmony_ci					sizeof(struct reg_window32));
57462306a36Sopenharmony_ci	} else {
57562306a36Sopenharmony_ci		struct reg_window *rp;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		rp = &current_thread_info()->reg_window[wsaved - 1];
57862306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
57962306a36Sopenharmony_ci			err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
58062306a36Sopenharmony_ci		for (i = 0; i < 6; i++)
58162306a36Sopenharmony_ci			err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
58262306a36Sopenharmony_ci		err |= __put_user(rp->ins[6], &sf->ss.fp);
58362306a36Sopenharmony_ci		err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci	if (err)
58662306a36Sopenharmony_ci		return err;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* 3. signal handler back-trampoline and parameters */
58962306a36Sopenharmony_ci	regs->u_regs[UREG_FP] = (unsigned long) sf;
59062306a36Sopenharmony_ci	regs->u_regs[UREG_I0] = ksig->sig;
59162306a36Sopenharmony_ci	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
59262306a36Sopenharmony_ci	regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* 4. signal handler */
59562306a36Sopenharmony_ci	regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;
59662306a36Sopenharmony_ci	regs->tnpc = (regs->tpc + 4);
59762306a36Sopenharmony_ci	if (test_thread_flag(TIF_32BIT)) {
59862306a36Sopenharmony_ci		regs->tpc &= 0xffffffff;
59962306a36Sopenharmony_ci		regs->tnpc &= 0xffffffff;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* 5. return to kernel instructions */
60362306a36Sopenharmony_ci	if (ksig->ka.ka_restorer)
60462306a36Sopenharmony_ci		regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
60562306a36Sopenharmony_ci	else {
60662306a36Sopenharmony_ci		unsigned long address = ((unsigned long)&(sf->insns[0]));
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		/* mov __NR_rt_sigreturn, %g1 */
61162306a36Sopenharmony_ci		err |= __put_user(0x82102065, &sf->insns[0]);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci		/* t 0x10 */
61462306a36Sopenharmony_ci		err |= __put_user(0x91d02010, &sf->insns[1]);
61562306a36Sopenharmony_ci		if (err)
61662306a36Sopenharmony_ci			return err;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci		flush_signal_insns(address);
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci	return 0;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic inline void handle_signal32(struct ksignal *ksig,
62462306a36Sopenharmony_ci				  struct pt_regs *regs)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	sigset_t *oldset = sigmask_to_save();
62762306a36Sopenharmony_ci	int err;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
63062306a36Sopenharmony_ci		err = setup_rt_frame32(ksig, regs, oldset);
63162306a36Sopenharmony_ci	else
63262306a36Sopenharmony_ci		err = setup_frame32(ksig, regs, oldset);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	signal_setup_done(err, ksig, 0);
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
63862306a36Sopenharmony_ci				     struct sigaction *sa)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	switch (regs->u_regs[UREG_I0]) {
64162306a36Sopenharmony_ci	case ERESTART_RESTARTBLOCK:
64262306a36Sopenharmony_ci	case ERESTARTNOHAND:
64362306a36Sopenharmony_ci	no_system_call_restart:
64462306a36Sopenharmony_ci		regs->u_regs[UREG_I0] = EINTR;
64562306a36Sopenharmony_ci		regs->tstate |= TSTATE_ICARRY;
64662306a36Sopenharmony_ci		break;
64762306a36Sopenharmony_ci	case ERESTARTSYS:
64862306a36Sopenharmony_ci		if (!(sa->sa_flags & SA_RESTART))
64962306a36Sopenharmony_ci			goto no_system_call_restart;
65062306a36Sopenharmony_ci		fallthrough;
65162306a36Sopenharmony_ci	case ERESTARTNOINTR:
65262306a36Sopenharmony_ci		regs->u_regs[UREG_I0] = orig_i0;
65362306a36Sopenharmony_ci		regs->tpc -= 4;
65462306a36Sopenharmony_ci		regs->tnpc -= 4;
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci/* Note that 'init' is a special process: it doesn't get signals it doesn't
65962306a36Sopenharmony_ci * want to handle. Thus you cannot kill init even with a SIGKILL even by
66062306a36Sopenharmony_ci * mistake.
66162306a36Sopenharmony_ci */
66262306a36Sopenharmony_civoid do_signal32(struct pt_regs * regs)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	struct ksignal ksig;
66562306a36Sopenharmony_ci	unsigned long orig_i0 = 0;
66662306a36Sopenharmony_ci	int restart_syscall = 0;
66762306a36Sopenharmony_ci	bool has_handler = get_signal(&ksig);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (pt_regs_is_syscall(regs) &&
67062306a36Sopenharmony_ci	    (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
67162306a36Sopenharmony_ci		restart_syscall = 1;
67262306a36Sopenharmony_ci		orig_i0 = regs->u_regs[UREG_G6];
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	if (has_handler) {
67662306a36Sopenharmony_ci		if (restart_syscall)
67762306a36Sopenharmony_ci			syscall_restart32(orig_i0, regs, &ksig.ka.sa);
67862306a36Sopenharmony_ci		handle_signal32(&ksig, regs);
67962306a36Sopenharmony_ci	} else {
68062306a36Sopenharmony_ci		if (restart_syscall) {
68162306a36Sopenharmony_ci			switch (regs->u_regs[UREG_I0]) {
68262306a36Sopenharmony_ci			case ERESTARTNOHAND:
68362306a36Sopenharmony_ci	     		case ERESTARTSYS:
68462306a36Sopenharmony_ci			case ERESTARTNOINTR:
68562306a36Sopenharmony_ci				/* replay the system call when we are done */
68662306a36Sopenharmony_ci				regs->u_regs[UREG_I0] = orig_i0;
68762306a36Sopenharmony_ci				regs->tpc -= 4;
68862306a36Sopenharmony_ci				regs->tnpc -= 4;
68962306a36Sopenharmony_ci				pt_regs_clear_syscall(regs);
69062306a36Sopenharmony_ci				fallthrough;
69162306a36Sopenharmony_ci			case ERESTART_RESTARTBLOCK:
69262306a36Sopenharmony_ci				regs->u_regs[UREG_G1] = __NR_restart_syscall;
69362306a36Sopenharmony_ci				regs->tpc -= 4;
69462306a36Sopenharmony_ci				regs->tnpc -= 4;
69562306a36Sopenharmony_ci				pt_regs_clear_syscall(regs);
69662306a36Sopenharmony_ci			}
69762306a36Sopenharmony_ci		}
69862306a36Sopenharmony_ci		restore_saved_sigmask();
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistruct sigstack32 {
70362306a36Sopenharmony_ci	u32 the_stack;
70462306a36Sopenharmony_ci	int cur_status;
70562306a36Sopenharmony_ci};
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ciasmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	struct sigstack32 __user *ssptr =
71062306a36Sopenharmony_ci		(struct sigstack32 __user *)((unsigned long)(u_ssptr));
71162306a36Sopenharmony_ci	struct sigstack32 __user *ossptr =
71262306a36Sopenharmony_ci		(struct sigstack32 __user *)((unsigned long)(u_ossptr));
71362306a36Sopenharmony_ci	int ret = -EFAULT;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/* First see if old state is wanted. */
71662306a36Sopenharmony_ci	if (ossptr) {
71762306a36Sopenharmony_ci		if (put_user(current->sas_ss_sp + current->sas_ss_size,
71862306a36Sopenharmony_ci			     &ossptr->the_stack) ||
71962306a36Sopenharmony_ci		    __put_user(on_sig_stack(sp), &ossptr->cur_status))
72062306a36Sopenharmony_ci			goto out;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/* Now see if we want to update the new state. */
72462306a36Sopenharmony_ci	if (ssptr) {
72562306a36Sopenharmony_ci		u32 ss_sp;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		if (get_user(ss_sp, &ssptr->the_stack))
72862306a36Sopenharmony_ci			goto out;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		/* If the current stack was set with sigaltstack, don't
73162306a36Sopenharmony_ci		 * swap stacks while we are on it.
73262306a36Sopenharmony_ci		 */
73362306a36Sopenharmony_ci		ret = -EPERM;
73462306a36Sopenharmony_ci		if (current->sas_ss_sp && on_sig_stack(sp))
73562306a36Sopenharmony_ci			goto out;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		/* Since we don't know the extent of the stack, and we don't
73862306a36Sopenharmony_ci		 * track onstack-ness, but rather calculate it, we must
73962306a36Sopenharmony_ci		 * presume a size.  Ho hum this interface is lossy.
74062306a36Sopenharmony_ci		 */
74162306a36Sopenharmony_ci		current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
74262306a36Sopenharmony_ci		current->sas_ss_size = SIGSTKSZ;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	ret = 0;
74662306a36Sopenharmony_ciout:
74762306a36Sopenharmony_ci	return ret;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/*
75162306a36Sopenharmony_ci * Compile-time assertions for siginfo_t offsets. Check NSIG* as well, as
75262306a36Sopenharmony_ci * changes likely come with new fields that should be added below.
75362306a36Sopenharmony_ci */
75462306a36Sopenharmony_cistatic_assert(NSIGILL	== 11);
75562306a36Sopenharmony_cistatic_assert(NSIGFPE	== 15);
75662306a36Sopenharmony_cistatic_assert(NSIGSEGV	== 10);
75762306a36Sopenharmony_cistatic_assert(NSIGBUS	== 5);
75862306a36Sopenharmony_cistatic_assert(NSIGTRAP	== 6);
75962306a36Sopenharmony_cistatic_assert(NSIGCHLD	== 6);
76062306a36Sopenharmony_cistatic_assert(NSIGSYS	== 2);
76162306a36Sopenharmony_cistatic_assert(sizeof(compat_siginfo_t) == 128);
76262306a36Sopenharmony_cistatic_assert(__alignof__(compat_siginfo_t) == 4);
76362306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_signo)	== 0x00);
76462306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_errno)	== 0x04);
76562306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_code)	== 0x08);
76662306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_pid)	== 0x0c);
76762306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_uid)	== 0x10);
76862306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_tid)	== 0x0c);
76962306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_overrun)	== 0x10);
77062306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_status)	== 0x14);
77162306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_utime)	== 0x18);
77262306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_stime)	== 0x1c);
77362306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_value)	== 0x14);
77462306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_int)	== 0x14);
77562306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_ptr)	== 0x14);
77662306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_addr)	== 0x0c);
77762306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_trapno)	== 0x10);
77862306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_addr_lsb)	== 0x10);
77962306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_lower)	== 0x14);
78062306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_upper)	== 0x18);
78162306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_pkey)	== 0x14);
78262306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_perf_data)	== 0x10);
78362306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_perf_type)	== 0x14);
78462306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_perf_flags)	== 0x18);
78562306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_band)	== 0x0c);
78662306a36Sopenharmony_cistatic_assert(offsetof(compat_siginfo_t, si_fd)		== 0x10);
787