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