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