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