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