xref: /freebsd/sys/arm64/arm64/freebsd32_machdep.c (revision d060b420)
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 
55 extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
56 
57 SYSCTL_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 
71 int
freebsd32_sysarch(struct thread * td,struct freebsd32_sysarch_args * uap)72 freebsd32_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
130 void
get_fpcontext32(struct thread * td,mcontext32_vfp_t * mcp)131 get_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 
166 void
set_fpcontext32(struct thread * td,mcontext32_vfp_t * mcp)167 set_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 
188 static void
get_mcontext32(struct thread * td,mcontext32_t * mcp,int flags)189 get_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 
213 static int
set_mcontext32(struct thread * td,mcontext32_t * mcp)214 set_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 
260 int
freebsd32_getcontext(struct thread * td,struct freebsd32_getcontext_args * uap)261 freebsd32_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 
279 int
freebsd32_setcontext(struct thread * td,struct freebsd32_setcontext_args * uap)280 freebsd32_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 
299 int
freebsd32_sigreturn(struct thread * td,struct freebsd32_sigreturn_args * uap)300 freebsd32_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 
320 int
freebsd32_swapcontext(struct thread * td,struct freebsd32_swapcontext_args * uap)321 freebsd32_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 
347 void
freebsd32_sendsig(sig_t catcher,ksiginfo_t * ksi,sigset_t * mask)348 freebsd32_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  */
465 int
ofreebsd32_sigreturn(struct thread * td,struct ofreebsd32_sigreturn_args * uap)466 ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap)
467 {
468 
469 	return (nosys(td, (struct nosys_args *)uap));
470 }
471 #endif
472