]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/elf32_machdep.c
arm64: Mask non-debug exceptions when single stepping
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / elf32_machdep.c
1 /*-
2  * Copyright (c) 2014, 2015 The FreeBSD Foundation.
3  * Copyright (c) 2014, 2017 Andrew Turner.
4  * Copyright (c) 2018 Olivier Houchard
5  * All rights reserved.
6  *
7  * This software was developed by Andrew Turner under
8  * sponsorship from the FreeBSD Foundation.
9  *
10  * Portions of this software were developed by Konstantin Belousov
11  * under sponsorship from the FreeBSD Foundation.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/cdefs.h>
36 #define __ELF_WORD_SIZE 32
37
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
41 #include <sys/exec.h>
42 #include <sys/imgact.h>
43 #include <sys/linker.h>
44 #include <sys/proc.h>
45 #include <sys/reg.h>
46 #include <sys/sysctl.h>
47 #include <sys/sysent.h>
48 #include <sys/imgact_elf.h>
49 #include <sys/syscall.h>
50 #include <sys/signalvar.h>
51 #include <sys/vnode.h>
52
53 #include <machine/elf.h>
54 #include <machine/pcb.h>
55 #ifdef VFP
56 #include <machine/vfp.h>
57 #endif
58
59 #include <compat/freebsd32/freebsd32_util.h>
60
61 #define FREEBSD32_MINUSER       0x00001000
62 #define FREEBSD32_MAXUSER       ((1ul << 32) - PAGE_SIZE)
63 #define FREEBSD32_SHAREDPAGE    (FREEBSD32_MAXUSER - PAGE_SIZE)
64 #define FREEBSD32_USRSTACK      FREEBSD32_SHAREDPAGE
65 #define AARCH32_MAXDSIZ         (512 * 1024 * 1024)
66 #define AARCH32_MAXSSIZ         (64 * 1024 * 1024)
67 #define AARCH32_MAXVMEM         0
68
69 extern const char *freebsd32_syscallnames[];
70
71 extern char aarch32_sigcode[];
72 extern int sz_aarch32_sigcode;
73
74 static int freebsd32_fetch_syscall_args(struct thread *td);
75 static void freebsd32_setregs(struct thread *td, struct image_params *imgp,
76     u_long stack);
77 static void freebsd32_set_syscall_retval(struct thread *, int);
78
79 static bool elf32_arm_abi_supported(const struct image_params *,
80     const int32_t *, const uint32_t *);
81 static void elf32_fixlimit(struct rlimit *rl, int which);
82
83 extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
84
85 u_long __read_frequently elf32_hwcap;
86 u_long __read_frequently elf32_hwcap2;
87
88 static SYSCTL_NODE(_compat, OID_AUTO, aarch32, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
89     "aarch32 mode");
90
91 static u_long aarch32_maxdsiz = AARCH32_MAXDSIZ;
92 SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxdsiz, CTLFLAG_RWTUN,
93     &aarch32_maxdsiz, 0, "");
94 u_long aarch32_maxssiz = AARCH32_MAXSSIZ;
95 SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxssiz, CTLFLAG_RWTUN,
96     &aarch32_maxssiz, 0, "");
97 static u_long aarch32_maxvmem = AARCH32_MAXVMEM;
98 SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxvmem, CTLFLAG_RWTUN,
99     &aarch32_maxvmem, 0, "");
100
101 static struct sysentvec elf32_freebsd_sysvec = {
102         .sv_size        = SYS_MAXSYSCALL,
103         .sv_table       = freebsd32_sysent,
104         .sv_fixup       = elf32_freebsd_fixup,
105         .sv_sendsig     = freebsd32_sendsig,
106         .sv_sigcode     = aarch32_sigcode,
107         .sv_szsigcode   = &sz_aarch32_sigcode,
108         .sv_name        = "FreeBSD ELF32",
109         .sv_coredump    = elf32_coredump,
110         .sv_elf_core_osabi = ELFOSABI_FREEBSD,
111         .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR,
112         .sv_elf_core_prepare_notes = elf32_prepare_notes,
113         .sv_minsigstksz = MINSIGSTKSZ,
114         .sv_minuser     = FREEBSD32_MINUSER,
115         .sv_maxuser     = FREEBSD32_MAXUSER,
116         .sv_usrstack    = FREEBSD32_USRSTACK,
117         .sv_psstrings   = FREEBSD32_PS_STRINGS,
118         .sv_psstringssz = sizeof(struct freebsd32_ps_strings),
119         .sv_stackprot   = VM_PROT_READ | VM_PROT_WRITE,
120         .sv_copyout_auxargs = elf32_freebsd_copyout_auxargs,
121         .sv_copyout_strings = freebsd32_copyout_strings,
122         .sv_setregs     = freebsd32_setregs,
123         .sv_fixlimit    = elf32_fixlimit,
124         .sv_maxssiz     = &aarch32_maxssiz,
125         .sv_flags       = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP | SV_TIMEKEEP |
126             SV_RNG_SEED_VER | SV_SIGSYS,
127         .sv_set_syscall_retval = freebsd32_set_syscall_retval,
128         .sv_fetch_syscall_args = freebsd32_fetch_syscall_args,
129         .sv_syscallnames = freebsd32_syscallnames,
130         .sv_shared_page_base = FREEBSD32_SHAREDPAGE,
131         .sv_shared_page_len = PAGE_SIZE,
132         .sv_schedtail   = NULL,
133         .sv_thread_detach = NULL,
134         .sv_trap        = NULL,
135         .sv_hwcap       = &elf32_hwcap,
136         .sv_hwcap2      = &elf32_hwcap2,
137         .sv_onexec_old  = exec_onexec_old,
138         .sv_onexit      = exit_onexit,
139         .sv_regset_begin = SET_BEGIN(__elfN(regset)),
140         .sv_regset_end  = SET_LIMIT(__elfN(regset)),
141 };
142 INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
143
144 static Elf32_Brandinfo freebsd32_brand_info = {
145         .brand          = ELFOSABI_FREEBSD,
146         .machine        = EM_ARM,
147         .compat_3_brand = "FreeBSD",
148         .interp_path    = "/libexec/ld-elf.so.1",
149         .sysvec         = &elf32_freebsd_sysvec,
150         .interp_newpath = "/libexec/ld-elf32.so.1",
151         .brand_note     = &elf32_freebsd_brandnote,
152         .flags          = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
153         .header_supported= elf32_arm_abi_supported,
154 };
155
156 static void
157 register_elf32_brand(void *arg)
158 {
159         /* Check if we support AArch32 */
160         if (ID_AA64PFR0_EL0_VAL(READ_SPECIALREG(id_aa64pfr0_el1)) ==
161             ID_AA64PFR0_EL0_64_32) {
162                 elf32_insert_brand_entry(&freebsd32_brand_info);
163         } else {
164                 compat_freebsd_32bit = 0;
165         }
166 }
167 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, register_elf32_brand, NULL);
168
169 static bool
170 elf32_arm_abi_supported(const struct image_params *imgp,
171     const int32_t *osrel __unused, const uint32_t *fctl0 __unused)
172 {
173         const Elf32_Ehdr *hdr;
174
175 #define EF_ARM_EABI_FREEBSD_MIN EF_ARM_EABI_VER4
176         hdr = (const Elf32_Ehdr *)imgp->image_header;
177         if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) {
178                 if (bootverbose)
179                         uprintf("Attempting to execute non EABI binary "
180                             "(rev %d) image %s",
181                             EF_ARM_EABI_VERSION(hdr->e_flags),
182                             imgp->args->fname);
183                 return (false);
184         }
185
186         return (true);
187 }
188
189 static int
190 freebsd32_fetch_syscall_args(struct thread *td)
191 {
192         struct proc *p;
193         register_t *ap;
194         struct syscall_args *sa;
195         int error, i, nap, narg;
196         unsigned int args[4];
197
198         nap = 4;
199         p = td->td_proc;
200         ap = td->td_frame->tf_x;
201         sa = &td->td_sa;
202
203         /* r7 is the syscall id */
204         sa->code = td->td_frame->tf_x[7];
205         sa->original_code = sa->code;
206
207         if (sa->code == SYS_syscall) {
208                 sa->code = *ap++;
209                 nap--;
210         } else if (sa->code == SYS___syscall) {
211                 sa->code = ap[1];
212                 nap -= 2;
213                 ap += 2;
214         }
215
216         if (sa->code >= p->p_sysent->sv_size)
217                 sa->callp = &nosys_sysent;
218         else
219                 sa->callp = &p->p_sysent->sv_table[sa->code];
220
221         narg = sa->callp->sy_narg;
222         for (i = 0; i < nap; i++)
223                 sa->args[i] = ap[i];
224         if (narg > nap) {
225                 if (narg - nap > nitems(args))
226                         panic("Too many system call arguiments");
227                 error = copyin((void *)td->td_frame->tf_x[13], args,
228                     (narg - nap) * sizeof(int));
229                 if (error != 0)
230                         return (error);
231                 for (i = 0; i < (narg - nap); i++)
232                         sa->args[i + nap] = args[i];
233         }
234
235         td->td_retval[0] = 0;
236         td->td_retval[1] = 0;
237
238         return (0);
239 }
240
241 static void
242 freebsd32_set_syscall_retval(struct thread *td, int error)
243 {
244         struct trapframe *frame;
245
246         frame = td->td_frame;
247         switch (error) {
248         case 0:
249                 frame->tf_x[0] = td->td_retval[0];
250                 frame->tf_x[1] = td->td_retval[1];
251                 frame->tf_spsr &= ~PSR_C;
252                 break;
253         case ERESTART:
254                 /*
255                  * Reconstruct the pc to point at the swi.
256                  */
257                 if ((frame->tf_spsr & PSR_T) != 0)
258                         frame->tf_elr -= 2; //THUMB_INSN_SIZE;
259                 else
260                         frame->tf_elr -= 4; //INSN_SIZE;
261                 break;
262         case EJUSTRETURN:
263                 /* nothing to do */
264                 break;
265         default:
266                 frame->tf_x[0] = error;
267                 frame->tf_spsr |= PSR_C;
268                 break;
269         }
270 }
271
272 static void
273 freebsd32_setregs(struct thread *td, struct image_params *imgp,
274    uintptr_t stack)
275 {
276         struct trapframe *tf = td->td_frame;
277         struct pcb *pcb = td->td_pcb;
278
279         memset(tf, 0, sizeof(struct trapframe));
280
281         /*
282          * We need to set x0 for init as it doesn't call
283          * cpu_set_syscall_retval to copy the value. We also
284          * need to set td_retval for the cases where we do.
285          */
286         tf->tf_x[0] = stack;
287         /* SP_usr is mapped to x13 */
288         tf->tf_x[13] = stack;
289         /* LR_usr is mapped to x14 */
290         tf->tf_x[14] = imgp->entry_addr;
291         tf->tf_elr = imgp->entry_addr;
292         tf->tf_spsr = PSR_M_32;
293         if ((uint32_t)imgp->entry_addr & 1)
294                 tf->tf_spsr |= PSR_T;
295
296 #ifdef VFP
297         vfp_reset_state(td, pcb);
298 #endif
299
300         /*
301          * Clear debug register state. It is not applicable to the new process.
302          */
303         bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs));
304 }
305
306 void
307 elf32_dump_thread(struct thread *td, void *dst, size_t *off)
308 {
309 }
310
311 static void
312 elf32_fixlimit(struct rlimit *rl, int which)
313 {
314
315         switch (which) {
316         case RLIMIT_DATA:
317                 if (aarch32_maxdsiz != 0) {
318                         if (rl->rlim_cur > aarch32_maxdsiz)
319                                 rl->rlim_cur = aarch32_maxdsiz;
320                         if (rl->rlim_max > aarch32_maxdsiz)
321                                 rl->rlim_max = aarch32_maxdsiz;
322                 }
323                 break;
324         case RLIMIT_STACK:
325                 if (aarch32_maxssiz != 0) {
326                         if (rl->rlim_cur > aarch32_maxssiz)
327                                 rl->rlim_cur = aarch32_maxssiz;
328                         if (rl->rlim_max > aarch32_maxssiz)
329                                 rl->rlim_max = aarch32_maxssiz;
330                 }
331                 break;
332         case RLIMIT_VMEM:
333                 if (aarch32_maxvmem != 0) {
334                         if (rl->rlim_cur > aarch32_maxvmem)
335                                 rl->rlim_cur = aarch32_maxvmem;
336                         if (rl->rlim_max > aarch32_maxvmem)
337                                 rl->rlim_max = aarch32_maxvmem;
338                 }
339                 break;
340         }
341 }