]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/elf32_machdep.c
MFV r365599: import fix for a libexecinfo warning at higher WARNS
[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 __FBSDID("$FreeBSD$");
37
38 #define __ELF_WORD_SIZE 32
39
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/systm.h>
43 #include <sys/exec.h>
44 #include <sys/imgact.h>
45 #include <sys/linker.h>
46 #include <sys/proc.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
55 #include <compat/freebsd32/freebsd32_util.h>
56
57 #define FREEBSD32_MINUSER       0x00001000
58 #define FREEBSD32_MAXUSER       ((1ul << 32) - PAGE_SIZE)
59 #define FREEBSD32_SHAREDPAGE    (FREEBSD32_MAXUSER - PAGE_SIZE)
60 #define FREEBSD32_USRSTACK      FREEBSD32_SHAREDPAGE
61
62 extern const char *freebsd32_syscallnames[];
63
64 extern char aarch32_sigcode[];
65 extern int sz_aarch32_sigcode;
66
67 static int freebsd32_fetch_syscall_args(struct thread *td);
68 static void freebsd32_setregs(struct thread *td, struct image_params *imgp,
69     u_long stack);
70 static void freebsd32_set_syscall_retval(struct thread *, int);
71
72 static boolean_t elf32_arm_abi_supported(struct image_params *, int32_t *,
73     uint32_t *);
74
75 extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
76
77 static struct sysentvec elf32_freebsd_sysvec = {
78         .sv_size        = SYS_MAXSYSCALL,
79         .sv_table       = freebsd32_sysent,
80         .sv_errsize     = 0,
81         .sv_errtbl      = NULL,
82         .sv_transtrap   = NULL,
83         .sv_fixup       = elf32_freebsd_fixup,
84         .sv_sendsig     = freebsd32_sendsig,
85         .sv_sigcode     = aarch32_sigcode,
86         .sv_szsigcode   = &sz_aarch32_sigcode,
87         .sv_name        = "FreeBSD ELF32",
88         .sv_coredump    = elf32_coredump,
89         .sv_imgact_try  = NULL,
90         .sv_minsigstksz = MINSIGSTKSZ,
91         .sv_minuser     = FREEBSD32_MINUSER,
92         .sv_maxuser     = FREEBSD32_MAXUSER,
93         .sv_usrstack    = FREEBSD32_USRSTACK,
94         .sv_psstrings   = FREEBSD32_PS_STRINGS,
95         .sv_stackprot   = VM_PROT_READ | VM_PROT_WRITE,
96         .sv_copyout_auxargs = elf32_freebsd_copyout_auxargs,
97         .sv_copyout_strings = freebsd32_copyout_strings,
98         .sv_setregs     = freebsd32_setregs,
99         .sv_fixlimit    = NULL, // XXX
100         .sv_maxssiz     = NULL,
101         .sv_flags       = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP | SV_TIMEKEEP,
102         .sv_set_syscall_retval = freebsd32_set_syscall_retval,
103         .sv_fetch_syscall_args = freebsd32_fetch_syscall_args,
104         .sv_syscallnames = freebsd32_syscallnames,
105         .sv_shared_page_base = FREEBSD32_SHAREDPAGE,
106         .sv_shared_page_len = PAGE_SIZE,
107         .sv_schedtail   = NULL,
108         .sv_thread_detach = NULL,
109         .sv_trap        = NULL,
110 };
111 INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
112
113 static Elf32_Brandinfo freebsd32_brand_info = {
114         .brand          = ELFOSABI_FREEBSD,
115         .machine        = EM_ARM,
116         .compat_3_brand = "FreeBSD",
117         .emul_path      = NULL,
118         .interp_path    = "/libexec/ld-elf.so.1",
119         .sysvec         = &elf32_freebsd_sysvec,
120         .interp_newpath = "/libexec/ld-elf32.so.1",
121         .brand_note     = &elf32_freebsd_brandnote,
122         .flags          = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
123         .header_supported= elf32_arm_abi_supported,
124 };
125
126 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST,
127     (sysinit_cfunc_t)elf32_insert_brand_entry, &freebsd32_brand_info);
128
129 static boolean_t
130 elf32_arm_abi_supported(struct image_params *imgp, int32_t *osrel __unused,
131     uint32_t *fctl0 __unused)
132 {
133         const Elf32_Ehdr *hdr;
134
135         /* Check if we support AArch32 */
136         if (ID_AA64PFR0_EL0_VAL(READ_SPECIALREG(id_aa64pfr0_el1)) !=
137             ID_AA64PFR0_EL0_64_32)
138                 return (FALSE);
139
140 #define EF_ARM_EABI_VERSION(x)  (((x) & EF_ARM_EABIMASK) >> 24)
141 #define EF_ARM_EABI_FREEBSD_MIN 4
142         hdr = (const Elf32_Ehdr *)imgp->image_header;
143         if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) {
144                 if (bootverbose)
145                         uprintf("Attempting to execute non EABI binary "
146                             "(rev %d) image %s",
147                             EF_ARM_EABI_VERSION(hdr->e_flags),
148                             imgp->args->fname);
149                 return (FALSE);
150         }
151
152         return (TRUE);
153 }
154
155 static int
156 freebsd32_fetch_syscall_args(struct thread *td)
157 {
158         struct proc *p;
159         register_t *ap;
160         struct syscall_args *sa;
161         int error, i, nap;
162         unsigned int args[4];
163
164         nap = 4;
165         p = td->td_proc;
166         ap = td->td_frame->tf_x;
167         sa = &td->td_sa;
168
169         /* r7 is the syscall id */
170         sa->code = td->td_frame->tf_x[7];
171
172         if (sa->code == SYS_syscall) {
173                 sa->code = *ap++;
174                 nap--;
175         } else if (sa->code == SYS___syscall) {
176                 sa->code = ap[1];
177                 nap -= 2;
178                 ap += 2;
179         }
180
181         if (sa->code >= p->p_sysent->sv_size)
182                 sa->callp = &p->p_sysent->sv_table[0];
183         else
184                 sa->callp = &p->p_sysent->sv_table[sa->code];
185
186         sa->narg = sa->callp->sy_narg;
187         for (i = 0; i < nap; i++)
188                 sa->args[i] = ap[i];
189         if (sa->narg > nap) {
190                 if ((sa->narg - nap) > nitems(args))
191                         panic("Too many system call arguiments");
192                 error = copyin((void *)td->td_frame->tf_x[13], args,
193                     (sa->narg - nap) * sizeof(int));
194                 for (i = 0; i < (sa->narg - nap); i++)
195                         sa->args[i + nap] = args[i];
196         }
197
198         td->td_retval[0] = 0;
199         td->td_retval[1] = 0;
200
201         return (0);
202 }
203
204 static void
205 freebsd32_set_syscall_retval(struct thread *td, int error)
206 {
207         struct trapframe *frame;
208
209         frame = td->td_frame;
210         switch (error) {
211         case 0:
212                 frame->tf_x[0] = td->td_retval[0];
213                 frame->tf_x[1] = td->td_retval[1];
214                 frame->tf_spsr &= ~PSR_C;
215                 break;
216         case ERESTART:
217                 /*
218                  * Reconstruct the pc to point at the swi.
219                  */
220                 if ((frame->tf_spsr & PSR_T) != 0)
221                         frame->tf_elr -= 2; //THUMB_INSN_SIZE;
222                 else
223                         frame->tf_elr -= 4; //INSN_SIZE;
224                 break;
225         case EJUSTRETURN:
226                 /* nothing to do */
227                 break;
228         default:
229                 frame->tf_x[0] = error;
230                 frame->tf_spsr |= PSR_C;
231                 break;
232         }
233 }
234
235 static void
236 freebsd32_setregs(struct thread *td, struct image_params *imgp,
237    uintptr_t stack)
238 {
239         struct trapframe *tf = td->td_frame;
240
241         memset(tf, 0, sizeof(struct trapframe));
242
243         /*
244          * We need to set x0 for init as it doesn't call
245          * cpu_set_syscall_retval to copy the value. We also
246          * need to set td_retval for the cases where we do.
247          */
248         tf->tf_x[0] = stack;
249         /* SP_usr is mapped to x13 */
250         tf->tf_x[13] = stack;
251         /* LR_usr is mapped to x14 */
252         tf->tf_x[14] = imgp->entry_addr;
253         tf->tf_elr = imgp->entry_addr;
254         tf->tf_spsr = PSR_M_32;
255 }
256
257 void
258 elf32_dump_thread(struct thread *td, void *dst, size_t *off)
259 {
260         /* XXX: VFP */
261 }