]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/freebsd32_machdep.c
MFV 354917, 354918, 354919
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / freebsd32_machdep.c
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
120
121 #ifdef VFP
122 static void
123 get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp)
124 {
125         struct pcb *curpcb;
126         int i;
127
128         critical_enter();
129         curpcb = curthread->td_pcb;
130
131         if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
132                 /*
133                  * If we have just been running VFP instructions we will
134                  * need to save the state to memcpy it below.
135                  */
136                 vfp_save_state(td, curpcb);
137
138                 KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate,
139                                 ("Called get_fpcontext while the kernel is using the VFP"));
140                 KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
141                                 ("Non-userspace FPU flags set in get_fpcontext"));
142                 for (i = 0; i < 32; i++)
143                         mcp->mcv_reg[i] = (uint64_t)curpcb->pcb_fpustate.vfp_regs[i];
144                 mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(curpcb->pcb_fpustate.vfp_fpcr,
145                                 curpcb->pcb_fpustate.vfp_fpsr);
146         }
147  critical_exit();
148 }
149
150 static void
151 set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp)
152 {
153         struct pcb *pcb;
154         int i;
155
156         critical_enter();
157         pcb = td->td_pcb;
158         if (td == curthread)
159                 vfp_discard(td);
160         for (i = 0; i < 32; i++)
161                 pcb->pcb_fpustate.vfp_regs[i] = mcp->mcv_reg[i];
162         pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr);
163         pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr);
164         critical_exit();
165 }
166 #endif
167 static void
168 get_mcontext32(struct thread *td, mcontext32_t *mcp, int flags)
169 {
170         struct pcb *pcb;
171         struct trapframe *tf;
172         int i;
173
174         pcb = td->td_pcb;
175         tf = td->td_frame;
176
177         if ((flags & GET_MC_CLEAR_RET) != 0) {
178                 mcp->mc_gregset[0] = 0;
179                 mcp->mc_gregset[16] = tf->tf_spsr & ~PSR_C;
180         } else {
181                 mcp->mc_gregset[0] = tf->tf_x[0];
182                 mcp->mc_gregset[16] = tf->tf_spsr;
183         }
184         for (i = 1; i < 15; i++)
185                 mcp->mc_gregset[i] = tf->tf_x[i];
186         mcp->mc_gregset[15] = tf->tf_elr;
187
188         mcp->mc_vfp_size = 0;
189         mcp->mc_vfp_ptr = 0;
190
191         memset(mcp->mc_spare, 0, sizeof(mcp->mc_spare));
192 }
193
194 static int
195 set_mcontext32(struct thread *td, mcontext32_t *mcp)
196 {
197         struct trapframe *tf;
198         mcontext32_vfp_t mc_vfp;
199         int i;
200
201         tf = td->td_frame;
202
203         for (i = 0; i < 15; i++)
204                 tf->tf_x[i] = mcp->mc_gregset[i];
205         tf->tf_elr = mcp->mc_gregset[15];
206         tf->tf_spsr = mcp->mc_gregset[16];
207 #ifdef VFP
208         if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) {
209                 if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp,
210                                         sizeof(mc_vfp)) != 0)
211                         return (EFAULT);
212                 set_fpcontext32(td, &mc_vfp);
213         }
214 #endif
215
216         return (0);
217 }
218
219 #define UC_COPY_SIZE    offsetof(ucontext32_t, uc_link)
220
221 int
222 freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap)
223 {
224         ucontext32_t uc;
225         int ret;
226
227         if (uap->ucp == NULL)
228                 ret = EINVAL;
229         else {
230                 memset(&uc, 0, sizeof(uc));
231                 get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
232                 PROC_LOCK(td->td_proc);
233                 uc.uc_sigmask = td->td_sigmask;
234                 PROC_UNLOCK(td->td_proc);
235                 ret = copyout(&uc, uap->ucp, UC_COPY_SIZE);
236         }
237         return (ret);
238 }
239
240 int
241 freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap)
242 {
243         ucontext32_t uc;
244         int ret;
245
246         if (uap->ucp == NULL)
247                 ret = EINVAL;
248         else {
249                 ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
250                 if (ret == 0) {
251                         ret = set_mcontext32(td, &uc.uc_mcontext);
252                         if (ret == 0)
253                                 kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask,
254                                                 NULL, 0);
255                 }
256         }
257         return (ret);
258 }
259
260 int
261 freebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap)
262 {
263         ucontext32_t uc;
264         int error;
265
266         if (uap == NULL)
267                 return (EFAULT);
268         if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
269                 return (EFAULT);
270         error = set_mcontext32(td, &uc.uc_mcontext);
271         if (error != 0)
272                 return (0);
273
274         /* Restore signal mask. */
275         kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
276
277         return (EJUSTRETURN);
278
279 }
280
281 int
282 freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
283 {
284         ucontext32_t uc;
285         int ret;
286
287         if (uap->oucp == NULL || uap->ucp == NULL)
288                 ret = EINVAL;
289         else {
290                 bzero(&uc, sizeof(uc));
291                 get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
292                 PROC_LOCK(td->td_proc);
293                 uc.uc_sigmask = td->td_sigmask;
294                 PROC_UNLOCK(td->td_proc);
295                 ret = copyout(&uc, uap->oucp, UC32_COPY_SIZE);
296                 if (ret == 0) {
297                         ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE);
298                         if (ret == 0) {
299                                 ret = set_mcontext32(td, &uc.uc_mcontext);
300                                 kern_sigprocmask(td, SIG_SETMASK,
301                                                 &uc.uc_sigmask, NULL, 0);
302                         }
303                 }
304         }
305         return (ret);
306 }
307
308 void
309 freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
310 {
311         struct thread *td;
312         struct proc *p;
313         struct trapframe *tf;
314         struct sigframe32 *fp, frame;
315         struct sigacts *psp;
316         struct siginfo32 siginfo;
317         struct sysentvec *sysent;
318         int onstack;
319         int sig;
320         int code;
321
322         siginfo_to_siginfo32(&ksi->ksi_info, &siginfo);
323         td = curthread;
324         p = td->td_proc;
325         PROC_LOCK_ASSERT(p, MA_OWNED);
326         sig = ksi->ksi_signo;
327         code = ksi->ksi_code;
328         psp = p->p_sigacts;
329         mtx_assert(&psp->ps_mtx, MA_OWNED);
330         tf = td->td_frame;
331         onstack = sigonstack(tf->tf_x[13]);
332
333         CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
334             catcher, sig);
335
336         /* Allocate and validate space for the signal handler context. */
337         if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) &&
338             SIGISMEMBER(psp->ps_sigonstack, sig)) {
339                 fp = (struct sigframe32 *)((uintptr_t)td->td_sigstk.ss_sp +
340                     td->td_sigstk.ss_size);
341 #if defined(COMPAT_43)
342                 td->td_sigstk.ss_flags |= SS_ONSTACK;
343 #endif
344         } else
345                 fp = (struct sigframe32 *)td->td_frame->tf_x[13];
346
347         /* make room on the stack */
348         fp--;
349
350         /* make the stack aligned */
351         fp = (struct sigframe32 *)((unsigned long)(fp) &~ (8 - 1));
352         /* Populate the siginfo frame. */
353         get_mcontext32(td, &frame.sf_uc.uc_mcontext, 0);
354 #ifdef VFP
355         get_fpcontext32(td, &frame.sf_vfp);
356         frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp);
357         frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)(uintptr_t)&fp->sf_vfp;
358 #else
359         frame.sf_uc.uc_mcontext.mc_vfp_size = 0;
360         frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)NULL;
361 #endif
362         frame.sf_si = siginfo;
363         frame.sf_uc.uc_sigmask = *mask;
364         frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK )
365             ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE;
366         frame.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp;
367         frame.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size;
368
369         mtx_unlock(&psp->ps_mtx);
370         PROC_UNLOCK(td->td_proc);
371
372         /* Copy the sigframe out to the user's stack. */
373         if (copyout(&frame, fp, sizeof(*fp)) != 0) {
374                 /* Process has trashed its stack. Kill it. */
375                 CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
376                 PROC_LOCK(p);
377                 sigexit(td, SIGILL);
378         }
379
380         /*
381          * Build context to run handler in.  We invoke the handler
382          * directly, only returning via the trampoline.  Note the
383          * trampoline version numbers are coordinated with machine-
384          * dependent code in libc.
385          */
386
387         tf->tf_x[0] = sig;
388         tf->tf_x[1] = (register_t)&fp->sf_si;
389         tf->tf_x[2] = (register_t)&fp->sf_uc;
390
391         /* the trampoline uses r5 as the uc address */
392         tf->tf_x[5] = (register_t)&fp->sf_uc;
393         tf->tf_elr = (register_t)catcher;
394         tf->tf_x[13] = (register_t)fp;
395         sysent = p->p_sysent;
396         if (sysent->sv_sigcode_base != 0)
397                 tf->tf_x[14] = (register_t)sysent->sv_sigcode_base;
398         else
399                 tf->tf_x[14] = (register_t)(sysent->sv_psstrings -
400                     *(sysent->sv_szsigcode));
401         /* Set the mode to enter in the signal handler */
402         if ((register_t)catcher & 1)
403                 tf->tf_spsr |= PSR_T;
404         else
405                 tf->tf_spsr &= ~PSR_T;
406
407         CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_x[14],
408             tf->tf_x[13]);
409
410         PROC_LOCK(p);
411         mtx_lock(&psp->ps_mtx);
412
413 }
414
415 #ifdef COMPAT_43
416 /*
417  * COMPAT_FREEBSD32 assumes we have this system call when COMPAT_43 is defined.
418  * FreeBSD/arm provies a similar getpagesize() syscall.
419  */
420 #define ARM32_PAGE_SIZE 4096
421 int
422 ofreebsd32_getpagesize(struct thread *td,
423     struct ofreebsd32_getpagesize_args *uap)
424 {
425
426         td->td_retval[0] = ARM32_PAGE_SIZE;
427         return (0);
428 }
429
430 /*
431  * Mirror the osigreturn definition in kern_sig.c for !i386 platforms. This
432  * mirrors what's connected to the FreeBSD/arm syscall.
433  */
434 int
435 ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap)
436 {
437
438         return (nosys(td, (struct nosys_args *)uap));
439 }
440 #endif