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