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