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