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