1/*-
2 * Copyright (c) 2018 Olivier Houchard
3 * Copyright (c) 2017 Nuxi, https://nuxi.nl/
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/param.h>
28#include <sys/exec.h>
29#include <sys/proc.h>
30#include <sys/lock.h>
31#include <sys/mutex.h>
32#include <sys/syscallsubr.h>
33#include <sys/ktr.h>
34#include <sys/sysctl.h>
35#include <sys/sysent.h>
36#include <sys/sysproto.h>
37#include <machine/armreg.h>
38#include <machine/pcb.h>
39#ifdef VFP
40#include <machine/vfp.h>
41#endif
42#include <compat/freebsd32/freebsd32_proto.h>
43#include <compat/freebsd32/freebsd32_signal.h>
44
45#include <vm/vm.h>
46#include <vm/vm_param.h>
47#include <vm/pmap.h>
48#include <vm/vm_map.h>
49
50_Static_assert(sizeof(mcontext32_t) == 208, "mcontext32_t size incorrect");
51_Static_assert(sizeof(ucontext32_t) == 260, "ucontext32_t size incorrect");
52_Static_assert(sizeof(struct __siginfo32) == 64,
53    "struct __siginfo32 size incorrect");
54
55extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
56
57SYSCTL_NODE(_compat, OID_AUTO, arm, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
58    "32-bit mode");
59
60/*
61 * The first two fields of a ucontext_t are the signal mask and the machine
62 * context.  The next field is uc_link; we want to avoid destroying the link
63 * when copying out contexts.
64 */
65#define UC32_COPY_SIZE  offsetof(ucontext32_t, uc_link)
66
67/*
68 * Stubs for machine dependent 32-bits system calls.
69 */
70
71int
72freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap)
73{
74	int error;
75
76#define ARM_SYNC_ICACHE		0
77#define ARM_DRAIN_WRITEBUF	1
78#define ARM_SET_TP		2
79#define ARM_GET_TP		3
80#define ARM_GET_VFPSTATE	4
81
82	switch(uap->op) {
83	case ARM_SET_TP:
84		WRITE_SPECIALREG(tpidr_el0, uap->parms);
85		WRITE_SPECIALREG(tpidrro_el0, uap->parms);
86		return 0;
87	case ARM_SYNC_ICACHE:
88		{
89			struct {
90				uint32_t addr;
91				uint32_t size;
92			} args;
93
94			if ((error = copyin(uap->parms, &args, sizeof(args))) != 0)
95				return (error);
96			if ((uint64_t)args.addr + (uint64_t)args.size > 0xffffffff)
97				return (EINVAL);
98			cpu_icache_sync_range_checked(
99			    (void *)(uintptr_t)args.addr, args.size);
100			return 0;
101		}
102	case ARM_GET_VFPSTATE:
103		{
104			mcontext32_vfp_t mcontext_vfp;
105
106			struct {
107				uint32_t mc_vfp_size;
108				uint32_t mc_vfp;
109			} args;
110			if ((error = copyin(uap->parms, &args, sizeof(args))) != 0)
111				return (error);
112			if (args.mc_vfp_size != sizeof(mcontext_vfp))
113				return (EINVAL);
114#ifdef VFP
115			get_fpcontext32(td, &mcontext_vfp);
116#else
117			bzero(&mcontext_vfp, sizeof(mcontext_vfp));
118#endif
119			error = copyout(&mcontext_vfp,
120				(void *)(uintptr_t)args.mc_vfp,
121				sizeof(mcontext_vfp));
122			return error;
123		}
124	}
125
126	return (EINVAL);
127}
128
129#ifdef VFP
130void
131get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp)
132{
133	struct pcb *pcb;
134	int i;
135
136	KASSERT(td == curthread || TD_IS_SUSPENDED(td) ||
137	    P_SHOULDSTOP(td->td_proc),
138	    ("not suspended thread %p", td));
139
140	memset(mcp, 0, sizeof(*mcp));
141	pcb = td->td_pcb;
142
143	if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
144		/*
145		 * If we have just been running VFP instructions we will
146		 * need to save the state to memcpy it below.
147		 */
148		if (td == curthread)
149			vfp_save_state(td, pcb);
150
151		KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
152		    ("Called get_fpcontext32 while the kernel is using the VFP"));
153		KASSERT((pcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
154		    ("Non-userspace FPU flags set in get_fpcontext32"));
155		for (i = 0; i < 16; i++) {
156			uint64_t *tmpreg = (uint64_t *)&pcb->pcb_fpustate.vfp_regs[i];
157
158			mcp->mcv_reg[i * 2] = tmpreg[0];
159			mcp->mcv_reg[i * 2 + 1] = tmpreg[1];
160		}
161		mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(pcb->pcb_fpustate.vfp_fpcr,
162		    pcb->pcb_fpustate.vfp_fpsr);
163	}
164}
165
166void
167set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp)
168{
169	struct pcb *pcb;
170	int i;
171
172	critical_enter();
173	pcb = td->td_pcb;
174	if (td == curthread)
175		vfp_discard(td);
176	for (i = 0; i < 16; i++) {
177		uint64_t *tmpreg = (uint64_t *)&pcb->pcb_fpustate.vfp_regs[i];
178
179		tmpreg[0] = mcp->mcv_reg[i * 2];
180		tmpreg[1] = mcp->mcv_reg[i * 2 + 1];
181	}
182	pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr);
183	pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr);
184	critical_exit();
185}
186#endif
187
188static void
189get_mcontext32(struct thread *td, mcontext32_t *mcp, int flags)
190{
191	struct trapframe *tf;
192	int i;
193
194	tf = td->td_frame;
195
196	if ((flags & GET_MC_CLEAR_RET) != 0) {
197		mcp->mc_gregset[0] = 0;
198		mcp->mc_gregset[16] = tf->tf_spsr & ~PSR_C;
199	} else {
200		mcp->mc_gregset[0] = tf->tf_x[0];
201		mcp->mc_gregset[16] = tf->tf_spsr;
202	}
203	for (i = 1; i < 15; i++)
204		mcp->mc_gregset[i] = tf->tf_x[i];
205	mcp->mc_gregset[15] = tf->tf_elr;
206
207	mcp->mc_vfp_size = 0;
208	mcp->mc_vfp_ptr = 0;
209
210	memset(mcp->mc_spare, 0, sizeof(mcp->mc_spare));
211}
212
213static int
214set_mcontext32(struct thread *td, mcontext32_t *mcp)
215{
216	struct trapframe *tf;
217	mcontext32_vfp_t mc_vfp;
218	uint32_t spsr;
219	int i;
220
221	tf = td->td_frame;
222
223	spsr = mcp->mc_gregset[16];
224	/*
225	 * There is no PSR_SS in the 32-bit kernel so ignore it if it's set
226	 * as we will set it later if needed.
227	 */
228	if ((spsr & ~(PSR_SETTABLE_32 | PSR_SS)) !=
229	    (tf->tf_spsr & ~(PSR_SETTABLE_32 | PSR_SS)))
230		return (EINVAL);
231
232	spsr &= PSR_SETTABLE_32;
233	spsr |= tf->tf_spsr & ~PSR_SETTABLE_32;
234
235	if ((td->td_dbgflags & TDB_STEP) != 0) {
236		spsr |= PSR_SS;
237		td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
238		WRITE_SPECIALREG(mdscr_el1,
239		    READ_SPECIALREG(mdscr_el1) | MDSCR_SS);
240	}
241
242	for (i = 0; i < 15; i++)
243		tf->tf_x[i] = mcp->mc_gregset[i];
244	tf->tf_elr = mcp->mc_gregset[15];
245	tf->tf_spsr = spsr;
246#ifdef VFP
247	if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) {
248		if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp,
249					sizeof(mc_vfp)) != 0)
250			return (EFAULT);
251		set_fpcontext32(td, &mc_vfp);
252	}
253#endif
254
255	return (0);
256}
257
258#define UC_COPY_SIZE	offsetof(ucontext32_t, uc_link)
259
260int
261freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap)
262{
263	ucontext32_t uc;
264	int ret;
265
266	if (uap->ucp == NULL)
267		ret = EINVAL;
268	else {
269		memset(&uc, 0, sizeof(uc));
270		get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
271		PROC_LOCK(td->td_proc);
272		uc.uc_sigmask = td->td_sigmask;
273		PROC_UNLOCK(td->td_proc);
274		ret = copyout(&uc, uap->ucp, UC_COPY_SIZE);
275	}
276	return (ret);
277}
278
279int
280freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap)
281{
282	ucontext32_t uc;
283	int ret;
284
285	if (uap->ucp == NULL)
286		ret = EINVAL;
287	else {
288		ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
289		if (ret == 0) {
290			ret = set_mcontext32(td, &uc.uc_mcontext);
291			if (ret == 0)
292				kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask,
293						NULL, 0);
294		}
295	}
296	return (ret);
297}
298
299int
300freebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap)
301{
302	ucontext32_t uc;
303	int error;
304
305	if (uap == NULL)
306		return (EFAULT);
307	if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
308		return (EFAULT);
309	error = set_mcontext32(td, &uc.uc_mcontext);
310	if (error != 0)
311		return (0);
312
313	/* Restore signal mask. */
314	kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
315
316	return (EJUSTRETURN);
317
318}
319
320int
321freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
322{
323	ucontext32_t uc;
324	int ret;
325
326	if (uap->oucp == NULL || uap->ucp == NULL)
327		ret = EINVAL;
328	else {
329		bzero(&uc, sizeof(uc));
330		get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
331		PROC_LOCK(td->td_proc);
332		uc.uc_sigmask = td->td_sigmask;
333		PROC_UNLOCK(td->td_proc);
334		ret = copyout(&uc, uap->oucp, UC32_COPY_SIZE);
335		if (ret == 0) {
336			ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE);
337			if (ret == 0) {
338				ret = set_mcontext32(td, &uc.uc_mcontext);
339				kern_sigprocmask(td, SIG_SETMASK,
340						&uc.uc_sigmask, NULL, 0);
341			}
342		}
343	}
344	return (ret);
345}
346
347void
348freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
349{
350	struct thread *td;
351	struct proc *p;
352	struct trapframe *tf;
353	struct sigframe32 *fp, frame;
354	struct sigacts *psp;
355	struct __siginfo32 siginfo;
356	struct sysentvec *sysent;
357	int onstack;
358	int sig;
359
360	siginfo_to_siginfo32(&ksi->ksi_info, &siginfo);
361	td = curthread;
362	p = td->td_proc;
363	PROC_LOCK_ASSERT(p, MA_OWNED);
364	sig = ksi->ksi_signo;
365	psp = p->p_sigacts;
366	mtx_assert(&psp->ps_mtx, MA_OWNED);
367	tf = td->td_frame;
368	onstack = sigonstack(tf->tf_x[13]);
369
370	CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
371	    catcher, sig);
372
373	/* Allocate and validate space for the signal handler context. */
374	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) &&
375	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
376		fp = (struct sigframe32 *)((uintptr_t)td->td_sigstk.ss_sp +
377		    td->td_sigstk.ss_size);
378#if defined(COMPAT_43)
379		td->td_sigstk.ss_flags |= SS_ONSTACK;
380#endif
381	} else
382		fp = (struct sigframe32 *)td->td_frame->tf_x[13];
383
384	/* make room on the stack */
385	fp--;
386
387	/* make the stack aligned */
388	fp = (struct sigframe32 *)((unsigned long)(fp) &~ (8 - 1));
389	/* Populate the siginfo frame. */
390	get_mcontext32(td, &frame.sf_uc.uc_mcontext, 0);
391#ifdef VFP
392	get_fpcontext32(td, &frame.sf_vfp);
393	frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp);
394	frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)(uintptr_t)&fp->sf_vfp;
395#else
396	frame.sf_uc.uc_mcontext.mc_vfp_size = 0;
397	frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)NULL;
398#endif
399	frame.sf_si = siginfo;
400	frame.sf_uc.uc_sigmask = *mask;
401	frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK )
402	    ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE;
403	frame.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp;
404	frame.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size;
405
406	mtx_unlock(&psp->ps_mtx);
407	PROC_UNLOCK(td->td_proc);
408
409	/* Copy the sigframe out to the user's stack. */
410	if (copyout(&frame, fp, sizeof(*fp)) != 0) {
411		/* Process has trashed its stack. Kill it. */
412		CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
413		PROC_LOCK(p);
414		sigexit(td, SIGILL);
415	}
416
417	/*
418	 * Build context to run handler in.  We invoke the handler
419	 * directly, only returning via the trampoline.  Note the
420	 * trampoline version numbers are coordinated with machine-
421	 * dependent code in libc.
422	 */
423
424	tf->tf_x[0] = sig;
425	tf->tf_x[1] = (register_t)&fp->sf_si;
426	tf->tf_x[2] = (register_t)&fp->sf_uc;
427
428	/* the trampoline uses r5 as the uc address */
429	tf->tf_x[5] = (register_t)&fp->sf_uc;
430	tf->tf_elr = (register_t)catcher;
431	tf->tf_x[13] = (register_t)fp;
432	sysent = p->p_sysent;
433	if (PROC_HAS_SHP(p))
434		tf->tf_x[14] = (register_t)PROC_SIGCODE(p);
435	else
436		tf->tf_x[14] = (register_t)(PROC_PS_STRINGS(p) -
437		    *(sysent->sv_szsigcode));
438	/* Set the mode to enter in the signal handler */
439	if ((register_t)catcher & 1)
440		tf->tf_spsr |= PSR_T;
441	else
442		tf->tf_spsr &= ~PSR_T;
443
444	/* Clear the single step flag while in the signal handler */
445	if ((td->td_pcb->pcb_flags & PCB_SINGLE_STEP) != 0) {
446		td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
447		WRITE_SPECIALREG(mdscr_el1,
448		    READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS);
449		isb();
450	}
451
452	CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_x[14],
453	    tf->tf_x[13]);
454
455	PROC_LOCK(p);
456	mtx_lock(&psp->ps_mtx);
457
458}
459
460#ifdef COMPAT_43
461/*
462 * Mirror the osigreturn definition in kern_sig.c for !i386 platforms. This
463 * mirrors what's connected to the FreeBSD/arm syscall.
464 */
465int
466ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap)
467{
468
469	return (nosys(td, (struct nosys_args *)uap));
470}
471#endif
472