xref: /freebsd/sys/arm64/arm64/freebsd32_machdep.c (revision d060b420)
19dcf90f8SEd Schouten /*-
28c9c3144SOlivier Houchard  * Copyright (c) 2018 Olivier Houchard
39dcf90f8SEd Schouten  * Copyright (c) 2017 Nuxi, https://nuxi.nl/
49dcf90f8SEd Schouten  *
59dcf90f8SEd Schouten  * Redistribution and use in source and binary forms, with or without
69dcf90f8SEd Schouten  * modification, are permitted provided that the following conditions
79dcf90f8SEd Schouten  * are met:
89dcf90f8SEd Schouten  * 1. Redistributions of source code must retain the above copyright
99dcf90f8SEd Schouten  *    notice, this list of conditions and the following disclaimer.
109dcf90f8SEd Schouten  * 2. Redistributions in binary form must reproduce the above copyright
119dcf90f8SEd Schouten  *    notice, this list of conditions and the following disclaimer in the
129dcf90f8SEd Schouten  *    documentation and/or other materials provided with the distribution.
139dcf90f8SEd Schouten  *
149dcf90f8SEd Schouten  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
159dcf90f8SEd Schouten  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
169dcf90f8SEd Schouten  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
179dcf90f8SEd Schouten  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
189dcf90f8SEd Schouten  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199dcf90f8SEd Schouten  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
209dcf90f8SEd Schouten  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
219dcf90f8SEd Schouten  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
229dcf90f8SEd Schouten  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
239dcf90f8SEd Schouten  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
249dcf90f8SEd Schouten  * SUCH DAMAGE.
259dcf90f8SEd Schouten  */
269dcf90f8SEd Schouten 
27706f4a81SMark Johnston #include <sys/param.h>
28706f4a81SMark Johnston #include <sys/exec.h>
298c9c3144SOlivier Houchard #include <sys/proc.h>
308c9c3144SOlivier Houchard #include <sys/lock.h>
318c9c3144SOlivier Houchard #include <sys/mutex.h>
328c9c3144SOlivier Houchard #include <sys/syscallsubr.h>
338c9c3144SOlivier Houchard #include <sys/ktr.h>
344b500174SKyle Evans #include <sys/sysctl.h>
358c9c3144SOlivier Houchard #include <sys/sysent.h>
3683959d61SWarner Losh #include <sys/sysproto.h>
378c9c3144SOlivier Houchard #include <machine/armreg.h>
382555f175SKonstantin Belousov #include <machine/pcb.h>
398c9c3144SOlivier Houchard #ifdef VFP
408c9c3144SOlivier Houchard #include <machine/vfp.h>
418c9c3144SOlivier Houchard #endif
429dcf90f8SEd Schouten #include <compat/freebsd32/freebsd32_proto.h>
438c9c3144SOlivier Houchard #include <compat/freebsd32/freebsd32_signal.h>
448c9c3144SOlivier Houchard 
45706f4a81SMark Johnston #include <vm/vm.h>
46706f4a81SMark Johnston #include <vm/vm_param.h>
47706f4a81SMark Johnston #include <vm/pmap.h>
48706f4a81SMark Johnston #include <vm/vm_map.h>
49706f4a81SMark Johnston 
503988ca5aSWarner Losh _Static_assert(sizeof(mcontext32_t) == 208, "mcontext32_t size incorrect");
513988ca5aSWarner Losh _Static_assert(sizeof(ucontext32_t) == 260, "ucontext32_t size incorrect");
52d060b420SBrooks Davis _Static_assert(sizeof(struct __siginfo32) == 64,
53d060b420SBrooks Davis     "struct __siginfo32 size incorrect");
543988ca5aSWarner Losh 
558c9c3144SOlivier Houchard extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
568c9c3144SOlivier Houchard 
574b500174SKyle Evans SYSCTL_NODE(_compat, OID_AUTO, arm, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
584b500174SKyle Evans     "32-bit mode");
594b500174SKyle Evans 
608c9c3144SOlivier Houchard /*
618c9c3144SOlivier Houchard  * The first two fields of a ucontext_t are the signal mask and the machine
628c9c3144SOlivier Houchard  * context.  The next field is uc_link; we want to avoid destroying the link
638c9c3144SOlivier Houchard  * when copying out contexts.
648c9c3144SOlivier Houchard  */
658c9c3144SOlivier Houchard #define UC32_COPY_SIZE  offsetof(ucontext32_t, uc_link)
668c9c3144SOlivier Houchard 
679dcf90f8SEd Schouten /*
689dcf90f8SEd Schouten  * Stubs for machine dependent 32-bits system calls.
699dcf90f8SEd Schouten  */
709dcf90f8SEd Schouten 
719dcf90f8SEd Schouten int
freebsd32_sysarch(struct thread * td,struct freebsd32_sysarch_args * uap)728c9c3144SOlivier Houchard freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap)
738c9c3144SOlivier Houchard {
748c9c3144SOlivier Houchard 	int error;
758c9c3144SOlivier Houchard 
768c9c3144SOlivier Houchard #define ARM_SYNC_ICACHE		0
778c9c3144SOlivier Houchard #define ARM_DRAIN_WRITEBUF	1
788c9c3144SOlivier Houchard #define ARM_SET_TP		2
798c9c3144SOlivier Houchard #define ARM_GET_TP		3
808c9c3144SOlivier Houchard #define ARM_GET_VFPSTATE	4
818c9c3144SOlivier Houchard 
828c9c3144SOlivier Houchard 	switch(uap->op) {
838c9c3144SOlivier Houchard 	case ARM_SET_TP:
84fc232b89SAndrew Turner 		WRITE_SPECIALREG(tpidr_el0, uap->parms);
85fc232b89SAndrew Turner 		WRITE_SPECIALREG(tpidrro_el0, uap->parms);
868c9c3144SOlivier Houchard 		return 0;
878c9c3144SOlivier Houchard 	case ARM_SYNC_ICACHE:
888c9c3144SOlivier Houchard 		{
898c9c3144SOlivier Houchard 			struct {
908c9c3144SOlivier Houchard 				uint32_t addr;
918c9c3144SOlivier Houchard 				uint32_t size;
928c9c3144SOlivier Houchard 			} args;
938c9c3144SOlivier Houchard 
948c9c3144SOlivier Houchard 			if ((error = copyin(uap->parms, &args, sizeof(args))) != 0)
958c9c3144SOlivier Houchard 				return (error);
968c9c3144SOlivier Houchard 			if ((uint64_t)args.addr + (uint64_t)args.size > 0xffffffff)
978c9c3144SOlivier Houchard 				return (EINVAL);
981e3f42b6SJohn Baldwin 			cpu_icache_sync_range_checked(
991e3f42b6SJohn Baldwin 			    (void *)(uintptr_t)args.addr, args.size);
1008c9c3144SOlivier Houchard 			return 0;
1018c9c3144SOlivier Houchard 		}
1028c9c3144SOlivier Houchard 	case ARM_GET_VFPSTATE:
1038c9c3144SOlivier Houchard 		{
1048c9c3144SOlivier Houchard 			mcontext32_vfp_t mcontext_vfp;
1058c9c3144SOlivier Houchard 
1068c9c3144SOlivier Houchard 			struct {
1078c9c3144SOlivier Houchard 				uint32_t mc_vfp_size;
1088c9c3144SOlivier Houchard 				uint32_t mc_vfp;
1098c9c3144SOlivier Houchard 			} args;
1108c9c3144SOlivier Houchard 			if ((error = copyin(uap->parms, &args, sizeof(args))) != 0)
1118c9c3144SOlivier Houchard 				return (error);
1128c9c3144SOlivier Houchard 			if (args.mc_vfp_size != sizeof(mcontext_vfp))
1138c9c3144SOlivier Houchard 				return (EINVAL);
1148c9c3144SOlivier Houchard #ifdef VFP
1158c9c3144SOlivier Houchard 			get_fpcontext32(td, &mcontext_vfp);
1168c9c3144SOlivier Houchard #else
1178c9c3144SOlivier Houchard 			bzero(&mcontext_vfp, sizeof(mcontext_vfp));
1188c9c3144SOlivier Houchard #endif
1198c9c3144SOlivier Houchard 			error = copyout(&mcontext_vfp,
1208c9c3144SOlivier Houchard 				(void *)(uintptr_t)args.mc_vfp,
1218c9c3144SOlivier Houchard 				sizeof(mcontext_vfp));
1228c9c3144SOlivier Houchard 			return error;
1238c9c3144SOlivier Houchard 		}
1248c9c3144SOlivier Houchard 	}
1258c9c3144SOlivier Houchard 
1268c9c3144SOlivier Houchard 	return (EINVAL);
1278c9c3144SOlivier Houchard }
1288c9c3144SOlivier Houchard 
1298c9c3144SOlivier Houchard #ifdef VFP
130add00c38SJohn Baldwin void
get_fpcontext32(struct thread * td,mcontext32_vfp_t * mcp)1318c9c3144SOlivier Houchard get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp)
1328c9c3144SOlivier Houchard {
133a47fd692SJohn Baldwin 	struct pcb *pcb;
13484322e3eSOlivier Houchard 	int i;
1358c9c3144SOlivier Houchard 
136a47fd692SJohn Baldwin 	KASSERT(td == curthread || TD_IS_SUSPENDED(td) ||
137a47fd692SJohn Baldwin 	    P_SHOULDSTOP(td->td_proc),
138a47fd692SJohn Baldwin 	    ("not suspended thread %p", td));
1398c9c3144SOlivier Houchard 
140a47fd692SJohn Baldwin 	memset(mcp, 0, sizeof(*mcp));
141a47fd692SJohn Baldwin 	pcb = td->td_pcb;
142a47fd692SJohn Baldwin 
143a47fd692SJohn Baldwin 	if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
1448c9c3144SOlivier Houchard 		/*
1458c9c3144SOlivier Houchard 		 * If we have just been running VFP instructions we will
1468c9c3144SOlivier Houchard 		 * need to save the state to memcpy it below.
1478c9c3144SOlivier Houchard 		 */
148a47fd692SJohn Baldwin 		if (td == curthread)
149a47fd692SJohn Baldwin 			vfp_save_state(td, pcb);
1508c9c3144SOlivier Houchard 
151a47fd692SJohn Baldwin 		KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
152a47fd692SJohn Baldwin 		    ("Called get_fpcontext32 while the kernel is using the VFP"));
153a47fd692SJohn Baldwin 		KASSERT((pcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
154a47fd692SJohn Baldwin 		    ("Non-userspace FPU flags set in get_fpcontext32"));
155ccd0f34dSOlivier Houchard 		for (i = 0; i < 16; i++) {
156ccd0f34dSOlivier Houchard 			uint64_t *tmpreg = (uint64_t *)&pcb->pcb_fpustate.vfp_regs[i];
157ccd0f34dSOlivier Houchard 
158ccd0f34dSOlivier Houchard 			mcp->mcv_reg[i * 2] = tmpreg[0];
159ccd0f34dSOlivier Houchard 			mcp->mcv_reg[i * 2 + 1] = tmpreg[1];
160ccd0f34dSOlivier Houchard 		}
161a47fd692SJohn Baldwin 		mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(pcb->pcb_fpustate.vfp_fpcr,
162a47fd692SJohn Baldwin 		    pcb->pcb_fpustate.vfp_fpsr);
1638c9c3144SOlivier Houchard 	}
1648c9c3144SOlivier Houchard }
1658c9c3144SOlivier Houchard 
166add00c38SJohn Baldwin void
set_fpcontext32(struct thread * td,mcontext32_vfp_t * mcp)1678c9c3144SOlivier Houchard set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp)
1688c9c3144SOlivier Houchard {
1698c9c3144SOlivier Houchard 	struct pcb *pcb;
17084322e3eSOlivier Houchard 	int i;
1718c9c3144SOlivier Houchard 
1728c9c3144SOlivier Houchard 	critical_enter();
1738c9c3144SOlivier Houchard 	pcb = td->td_pcb;
1748c9c3144SOlivier Houchard 	if (td == curthread)
1758c9c3144SOlivier Houchard 		vfp_discard(td);
176ccd0f34dSOlivier Houchard 	for (i = 0; i < 16; i++) {
177ccd0f34dSOlivier Houchard 		uint64_t *tmpreg = (uint64_t *)&pcb->pcb_fpustate.vfp_regs[i];
178ccd0f34dSOlivier Houchard 
179ccd0f34dSOlivier Houchard 		tmpreg[0] = mcp->mcv_reg[i * 2];
180ccd0f34dSOlivier Houchard 		tmpreg[1] = mcp->mcv_reg[i * 2 + 1];
181ccd0f34dSOlivier Houchard 	}
1828c9c3144SOlivier Houchard 	pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr);
1838c9c3144SOlivier Houchard 	pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr);
1848c9c3144SOlivier Houchard 	critical_exit();
1858c9c3144SOlivier Houchard }
1868c9c3144SOlivier Houchard #endif
187add00c38SJohn Baldwin 
1888c9c3144SOlivier Houchard static void
get_mcontext32(struct thread * td,mcontext32_t * mcp,int flags)1898c9c3144SOlivier Houchard get_mcontext32(struct thread *td, mcontext32_t *mcp, int flags)
1908c9c3144SOlivier Houchard {
1918c9c3144SOlivier Houchard 	struct trapframe *tf;
1928c9c3144SOlivier Houchard 	int i;
1938c9c3144SOlivier Houchard 
1948c9c3144SOlivier Houchard 	tf = td->td_frame;
1958c9c3144SOlivier Houchard 
1968c9c3144SOlivier Houchard 	if ((flags & GET_MC_CLEAR_RET) != 0) {
1978c9c3144SOlivier Houchard 		mcp->mc_gregset[0] = 0;
1988c9c3144SOlivier Houchard 		mcp->mc_gregset[16] = tf->tf_spsr & ~PSR_C;
1998c9c3144SOlivier Houchard 	} else {
2008c9c3144SOlivier Houchard 		mcp->mc_gregset[0] = tf->tf_x[0];
2018c9c3144SOlivier Houchard 		mcp->mc_gregset[16] = tf->tf_spsr;
2028c9c3144SOlivier Houchard 	}
2038c9c3144SOlivier Houchard 	for (i = 1; i < 15; i++)
2048c9c3144SOlivier Houchard 		mcp->mc_gregset[i] = tf->tf_x[i];
2058c9c3144SOlivier Houchard 	mcp->mc_gregset[15] = tf->tf_elr;
2068c9c3144SOlivier Houchard 
2078c9c3144SOlivier Houchard 	mcp->mc_vfp_size = 0;
2088c9c3144SOlivier Houchard 	mcp->mc_vfp_ptr = 0;
2098c9c3144SOlivier Houchard 
2108c9c3144SOlivier Houchard 	memset(mcp->mc_spare, 0, sizeof(mcp->mc_spare));
2118c9c3144SOlivier Houchard }
2128c9c3144SOlivier Houchard 
2138c9c3144SOlivier Houchard static int
set_mcontext32(struct thread * td,mcontext32_t * mcp)2148c9c3144SOlivier Houchard set_mcontext32(struct thread *td, mcontext32_t *mcp)
2158c9c3144SOlivier Houchard {
2168c9c3144SOlivier Houchard 	struct trapframe *tf;
2178c9c3144SOlivier Houchard 	mcontext32_vfp_t mc_vfp;
21831cf95ceSAndrew Turner 	uint32_t spsr;
2198c9c3144SOlivier Houchard 	int i;
2208c9c3144SOlivier Houchard 
2218c9c3144SOlivier Houchard 	tf = td->td_frame;
2228c9c3144SOlivier Houchard 
22331cf95ceSAndrew Turner 	spsr = mcp->mc_gregset[16];
22431cf95ceSAndrew Turner 	/*
22531cf95ceSAndrew Turner 	 * There is no PSR_SS in the 32-bit kernel so ignore it if it's set
22631cf95ceSAndrew Turner 	 * as we will set it later if needed.
22731cf95ceSAndrew Turner 	 */
22831cf95ceSAndrew Turner 	if ((spsr & ~(PSR_SETTABLE_32 | PSR_SS)) !=
22931cf95ceSAndrew Turner 	    (tf->tf_spsr & ~(PSR_SETTABLE_32 | PSR_SS)))
23031cf95ceSAndrew Turner 		return (EINVAL);
23131cf95ceSAndrew Turner 
23231cf95ceSAndrew Turner 	spsr &= PSR_SETTABLE_32;
23331cf95ceSAndrew Turner 	spsr |= tf->tf_spsr & ~PSR_SETTABLE_32;
23431cf95ceSAndrew Turner 
23531cf95ceSAndrew Turner 	if ((td->td_dbgflags & TDB_STEP) != 0) {
23631cf95ceSAndrew Turner 		spsr |= PSR_SS;
23731cf95ceSAndrew Turner 		td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
23831cf95ceSAndrew Turner 		WRITE_SPECIALREG(mdscr_el1,
23931cf95ceSAndrew Turner 		    READ_SPECIALREG(mdscr_el1) | MDSCR_SS);
24031cf95ceSAndrew Turner 	}
24131cf95ceSAndrew Turner 
2428c9c3144SOlivier Houchard 	for (i = 0; i < 15; i++)
2438c9c3144SOlivier Houchard 		tf->tf_x[i] = mcp->mc_gregset[i];
2448c9c3144SOlivier Houchard 	tf->tf_elr = mcp->mc_gregset[15];
24531cf95ceSAndrew Turner 	tf->tf_spsr = spsr;
2468c9c3144SOlivier Houchard #ifdef VFP
2478c9c3144SOlivier Houchard 	if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) {
2488c9c3144SOlivier Houchard 		if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp,
2498c9c3144SOlivier Houchard 					sizeof(mc_vfp)) != 0)
2508c9c3144SOlivier Houchard 			return (EFAULT);
2518c9c3144SOlivier Houchard 		set_fpcontext32(td, &mc_vfp);
2528c9c3144SOlivier Houchard 	}
2538c9c3144SOlivier Houchard #endif
2548c9c3144SOlivier Houchard 
2558c9c3144SOlivier Houchard 	return (0);
2568c9c3144SOlivier Houchard }
2578c9c3144SOlivier Houchard 
2588c9c3144SOlivier Houchard #define UC_COPY_SIZE	offsetof(ucontext32_t, uc_link)
2598c9c3144SOlivier Houchard 
2608c9c3144SOlivier Houchard int
freebsd32_getcontext(struct thread * td,struct freebsd32_getcontext_args * uap)2619dcf90f8SEd Schouten freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap)
2629dcf90f8SEd Schouten {
2638c9c3144SOlivier Houchard 	ucontext32_t uc;
2648c9c3144SOlivier Houchard 	int ret;
2659dcf90f8SEd Schouten 
2668c9c3144SOlivier Houchard 	if (uap->ucp == NULL)
2678c9c3144SOlivier Houchard 		ret = EINVAL;
2688c9c3144SOlivier Houchard 	else {
2698c9c3144SOlivier Houchard 		memset(&uc, 0, sizeof(uc));
2708c9c3144SOlivier Houchard 		get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
2718c9c3144SOlivier Houchard 		PROC_LOCK(td->td_proc);
2728c9c3144SOlivier Houchard 		uc.uc_sigmask = td->td_sigmask;
2738c9c3144SOlivier Houchard 		PROC_UNLOCK(td->td_proc);
2748c9c3144SOlivier Houchard 		ret = copyout(&uc, uap->ucp, UC_COPY_SIZE);
2758c9c3144SOlivier Houchard 	}
2768c9c3144SOlivier Houchard 	return (ret);
2779dcf90f8SEd Schouten }
2789dcf90f8SEd Schouten 
2799dcf90f8SEd Schouten int
freebsd32_setcontext(struct thread * td,struct freebsd32_setcontext_args * uap)2809dcf90f8SEd Schouten freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap)
2819dcf90f8SEd Schouten {
2828c9c3144SOlivier Houchard 	ucontext32_t uc;
2838c9c3144SOlivier Houchard 	int ret;
2849dcf90f8SEd Schouten 
2858c9c3144SOlivier Houchard 	if (uap->ucp == NULL)
2868c9c3144SOlivier Houchard 		ret = EINVAL;
2878c9c3144SOlivier Houchard 	else {
2888c9c3144SOlivier Houchard 		ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
2898c9c3144SOlivier Houchard 		if (ret == 0) {
2908c9c3144SOlivier Houchard 			ret = set_mcontext32(td, &uc.uc_mcontext);
2918c9c3144SOlivier Houchard 			if (ret == 0)
2928c9c3144SOlivier Houchard 				kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask,
2938c9c3144SOlivier Houchard 						NULL, 0);
2948c9c3144SOlivier Houchard 		}
2958c9c3144SOlivier Houchard 	}
2968c9c3144SOlivier Houchard 	return (ret);
2979dcf90f8SEd Schouten }
2989dcf90f8SEd Schouten 
2999dcf90f8SEd Schouten int
freebsd32_sigreturn(struct thread * td,struct freebsd32_sigreturn_args * uap)3009dcf90f8SEd Schouten freebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap)
3019dcf90f8SEd Schouten {
3028c9c3144SOlivier Houchard 	ucontext32_t uc;
3038c9c3144SOlivier Houchard 	int error;
3049dcf90f8SEd Schouten 
3058c9c3144SOlivier Houchard 	if (uap == NULL)
3068c9c3144SOlivier Houchard 		return (EFAULT);
3078c9c3144SOlivier Houchard 	if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
3088c9c3144SOlivier Houchard 		return (EFAULT);
3098c9c3144SOlivier Houchard 	error = set_mcontext32(td, &uc.uc_mcontext);
3108c9c3144SOlivier Houchard 	if (error != 0)
3118c9c3144SOlivier Houchard 		return (0);
3128c9c3144SOlivier Houchard 
3138c9c3144SOlivier Houchard 	/* Restore signal mask. */
3148c9c3144SOlivier Houchard 	kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
3158c9c3144SOlivier Houchard 
3168c9c3144SOlivier Houchard 	return (EJUSTRETURN);
3178c9c3144SOlivier Houchard 
3189dcf90f8SEd Schouten }
3199dcf90f8SEd Schouten 
3209dcf90f8SEd Schouten int
freebsd32_swapcontext(struct thread * td,struct freebsd32_swapcontext_args * uap)3219dcf90f8SEd Schouten freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
3229dcf90f8SEd Schouten {
3238c9c3144SOlivier Houchard 	ucontext32_t uc;
3248c9c3144SOlivier Houchard 	int ret;
3259dcf90f8SEd Schouten 
3268c9c3144SOlivier Houchard 	if (uap->oucp == NULL || uap->ucp == NULL)
3278c9c3144SOlivier Houchard 		ret = EINVAL;
3288c9c3144SOlivier Houchard 	else {
32998fc918fSKonstantin Belousov 		bzero(&uc, sizeof(uc));
3308c9c3144SOlivier Houchard 		get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
3318c9c3144SOlivier Houchard 		PROC_LOCK(td->td_proc);
3328c9c3144SOlivier Houchard 		uc.uc_sigmask = td->td_sigmask;
3338c9c3144SOlivier Houchard 		PROC_UNLOCK(td->td_proc);
3348c9c3144SOlivier Houchard 		ret = copyout(&uc, uap->oucp, UC32_COPY_SIZE);
3358c9c3144SOlivier Houchard 		if (ret == 0) {
3368c9c3144SOlivier Houchard 			ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE);
3378c9c3144SOlivier Houchard 			if (ret == 0) {
3388c9c3144SOlivier Houchard 				ret = set_mcontext32(td, &uc.uc_mcontext);
3398c9c3144SOlivier Houchard 				kern_sigprocmask(td, SIG_SETMASK,
3408c9c3144SOlivier Houchard 						&uc.uc_sigmask, NULL, 0);
3418c9c3144SOlivier Houchard 			}
3428c9c3144SOlivier Houchard 		}
3438c9c3144SOlivier Houchard 	}
3448c9c3144SOlivier Houchard 	return (ret);
3459dcf90f8SEd Schouten }
3469dcf90f8SEd Schouten 
3478c9c3144SOlivier Houchard void
freebsd32_sendsig(sig_t catcher,ksiginfo_t * ksi,sigset_t * mask)3488c9c3144SOlivier Houchard freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
3499dcf90f8SEd Schouten {
3508c9c3144SOlivier Houchard 	struct thread *td;
3518c9c3144SOlivier Houchard 	struct proc *p;
3528c9c3144SOlivier Houchard 	struct trapframe *tf;
3538c9c3144SOlivier Houchard 	struct sigframe32 *fp, frame;
3548c9c3144SOlivier Houchard 	struct sigacts *psp;
355d060b420SBrooks Davis 	struct __siginfo32 siginfo;
3568c9c3144SOlivier Houchard 	struct sysentvec *sysent;
3578c9c3144SOlivier Houchard 	int onstack;
3588c9c3144SOlivier Houchard 	int sig;
3599dcf90f8SEd Schouten 
3608c9c3144SOlivier Houchard 	siginfo_to_siginfo32(&ksi->ksi_info, &siginfo);
3618c9c3144SOlivier Houchard 	td = curthread;
3628c9c3144SOlivier Houchard 	p = td->td_proc;
3638c9c3144SOlivier Houchard 	PROC_LOCK_ASSERT(p, MA_OWNED);
3648c9c3144SOlivier Houchard 	sig = ksi->ksi_signo;
3658c9c3144SOlivier Houchard 	psp = p->p_sigacts;
3668c9c3144SOlivier Houchard 	mtx_assert(&psp->ps_mtx, MA_OWNED);
3678c9c3144SOlivier Houchard 	tf = td->td_frame;
3688c9c3144SOlivier Houchard 	onstack = sigonstack(tf->tf_x[13]);
3698c9c3144SOlivier Houchard 
3708c9c3144SOlivier Houchard 	CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
3718c9c3144SOlivier Houchard 	    catcher, sig);
3728c9c3144SOlivier Houchard 
3738c9c3144SOlivier Houchard 	/* Allocate and validate space for the signal handler context. */
3748c9c3144SOlivier Houchard 	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) &&
3758c9c3144SOlivier Houchard 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
3768c9c3144SOlivier Houchard 		fp = (struct sigframe32 *)((uintptr_t)td->td_sigstk.ss_sp +
3778c9c3144SOlivier Houchard 		    td->td_sigstk.ss_size);
3788c9c3144SOlivier Houchard #if defined(COMPAT_43)
3798c9c3144SOlivier Houchard 		td->td_sigstk.ss_flags |= SS_ONSTACK;
3808c9c3144SOlivier Houchard #endif
3818c9c3144SOlivier Houchard 	} else
3828c9c3144SOlivier Houchard 		fp = (struct sigframe32 *)td->td_frame->tf_x[13];
3838c9c3144SOlivier Houchard 
3848c9c3144SOlivier Houchard 	/* make room on the stack */
3858c9c3144SOlivier Houchard 	fp--;
3868c9c3144SOlivier Houchard 
3878c9c3144SOlivier Houchard 	/* make the stack aligned */
3888c9c3144SOlivier Houchard 	fp = (struct sigframe32 *)((unsigned long)(fp) &~ (8 - 1));
3898c9c3144SOlivier Houchard 	/* Populate the siginfo frame. */
3908c9c3144SOlivier Houchard 	get_mcontext32(td, &frame.sf_uc.uc_mcontext, 0);
3918c9c3144SOlivier Houchard #ifdef VFP
3928c9c3144SOlivier Houchard 	get_fpcontext32(td, &frame.sf_vfp);
3938c9c3144SOlivier Houchard 	frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp);
3948c9c3144SOlivier Houchard 	frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)(uintptr_t)&fp->sf_vfp;
3958c9c3144SOlivier Houchard #else
3968c9c3144SOlivier Houchard 	frame.sf_uc.uc_mcontext.mc_vfp_size = 0;
3978c9c3144SOlivier Houchard 	frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)NULL;
3988c9c3144SOlivier Houchard #endif
3998c9c3144SOlivier Houchard 	frame.sf_si = siginfo;
4008c9c3144SOlivier Houchard 	frame.sf_uc.uc_sigmask = *mask;
4018c9c3144SOlivier Houchard 	frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK )
4028c9c3144SOlivier Houchard 	    ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE;
4038c9c3144SOlivier Houchard 	frame.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp;
4048c9c3144SOlivier Houchard 	frame.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size;
4058c9c3144SOlivier Houchard 
4068c9c3144SOlivier Houchard 	mtx_unlock(&psp->ps_mtx);
4078c9c3144SOlivier Houchard 	PROC_UNLOCK(td->td_proc);
4088c9c3144SOlivier Houchard 
4098c9c3144SOlivier Houchard 	/* Copy the sigframe out to the user's stack. */
4108c9c3144SOlivier Houchard 	if (copyout(&frame, fp, sizeof(*fp)) != 0) {
4118c9c3144SOlivier Houchard 		/* Process has trashed its stack. Kill it. */
4128c9c3144SOlivier Houchard 		CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
4138c9c3144SOlivier Houchard 		PROC_LOCK(p);
4148c9c3144SOlivier Houchard 		sigexit(td, SIGILL);
4158c9c3144SOlivier Houchard 	}
4168c9c3144SOlivier Houchard 
4178c9c3144SOlivier Houchard 	/*
4188c9c3144SOlivier Houchard 	 * Build context to run handler in.  We invoke the handler
4198c9c3144SOlivier Houchard 	 * directly, only returning via the trampoline.  Note the
4208c9c3144SOlivier Houchard 	 * trampoline version numbers are coordinated with machine-
4218c9c3144SOlivier Houchard 	 * dependent code in libc.
4228c9c3144SOlivier Houchard 	 */
4238c9c3144SOlivier Houchard 
4248c9c3144SOlivier Houchard 	tf->tf_x[0] = sig;
4258c9c3144SOlivier Houchard 	tf->tf_x[1] = (register_t)&fp->sf_si;
4268c9c3144SOlivier Houchard 	tf->tf_x[2] = (register_t)&fp->sf_uc;
4278c9c3144SOlivier Houchard 
4288c9c3144SOlivier Houchard 	/* the trampoline uses r5 as the uc address */
4298c9c3144SOlivier Houchard 	tf->tf_x[5] = (register_t)&fp->sf_uc;
4308c9c3144SOlivier Houchard 	tf->tf_elr = (register_t)catcher;
4318c9c3144SOlivier Houchard 	tf->tf_x[13] = (register_t)fp;
4328c9c3144SOlivier Houchard 	sysent = p->p_sysent;
433361971fbSKornel Dulęba 	if (PROC_HAS_SHP(p))
434f6ac79fbSKornel Dulęba 		tf->tf_x[14] = (register_t)PROC_SIGCODE(p);
4358c9c3144SOlivier Houchard 	else
436706f4a81SMark Johnston 		tf->tf_x[14] = (register_t)(PROC_PS_STRINGS(p) -
4378c9c3144SOlivier Houchard 		    *(sysent->sv_szsigcode));
4388c9c3144SOlivier Houchard 	/* Set the mode to enter in the signal handler */
4398c9c3144SOlivier Houchard 	if ((register_t)catcher & 1)
4408c9c3144SOlivier Houchard 		tf->tf_spsr |= PSR_T;
4418c9c3144SOlivier Houchard 	else
4428c9c3144SOlivier Houchard 		tf->tf_spsr &= ~PSR_T;
4438c9c3144SOlivier Houchard 
44431cf95ceSAndrew Turner 	/* Clear the single step flag while in the signal handler */
44531cf95ceSAndrew Turner 	if ((td->td_pcb->pcb_flags & PCB_SINGLE_STEP) != 0) {
44631cf95ceSAndrew Turner 		td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
44731cf95ceSAndrew Turner 		WRITE_SPECIALREG(mdscr_el1,
44831cf95ceSAndrew Turner 		    READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS);
44931cf95ceSAndrew Turner 		isb();
45031cf95ceSAndrew Turner 	}
45131cf95ceSAndrew Turner 
4528c9c3144SOlivier Houchard 	CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_x[14],
4538c9c3144SOlivier Houchard 	    tf->tf_x[13]);
4548c9c3144SOlivier Houchard 
4558c9c3144SOlivier Houchard 	PROC_LOCK(p);
4568c9c3144SOlivier Houchard 	mtx_lock(&psp->ps_mtx);
4578c9c3144SOlivier Houchard 
4589dcf90f8SEd Schouten }
45983959d61SWarner Losh 
46083959d61SWarner Losh #ifdef COMPAT_43
46183959d61SWarner Losh /*
46283959d61SWarner Losh  * Mirror the osigreturn definition in kern_sig.c for !i386 platforms. This
46383959d61SWarner Losh  * mirrors what's connected to the FreeBSD/arm syscall.
46483959d61SWarner Losh  */
46583959d61SWarner Losh int
ofreebsd32_sigreturn(struct thread * td,struct ofreebsd32_sigreturn_args * uap)46683959d61SWarner Losh ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap)
46783959d61SWarner Losh {
46883959d61SWarner Losh 
46983959d61SWarner Losh 	return (nosys(td, (struct nosys_args *)uap));
47083959d61SWarner Losh }
47183959d61SWarner Losh #endif
472