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