xref: /freebsd/sys/arm64/arm64/elf32_machdep.c (revision 85007872d1227006adf2ce119fe30de856cbe12d)
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_hwcap3	= NULL,
138 	.sv_hwcap4	= NULL,
139 	.sv_onexec_old	= exec_onexec_old,
140 	.sv_onexit	= exit_onexit,
141 	.sv_regset_begin = SET_BEGIN(__elfN(regset)),
142 	.sv_regset_end	= SET_LIMIT(__elfN(regset)),
143 };
144 INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
145 
146 static Elf32_Brandinfo freebsd32_brand_info = {
147 	.brand		= ELFOSABI_FREEBSD,
148 	.machine	= EM_ARM,
149 	.compat_3_brand	= "FreeBSD",
150 	.interp_path	= "/libexec/ld-elf.so.1",
151 	.sysvec		= &elf32_freebsd_sysvec,
152 	.interp_newpath	= "/libexec/ld-elf32.so.1",
153 	.brand_note	= &elf32_freebsd_brandnote,
154 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
155 	.header_supported= elf32_arm_abi_supported,
156 };
157 
158 static void
register_elf32_brand(void * arg)159 register_elf32_brand(void *arg)
160 {
161 	/* Check if we support AArch32 */
162 	if (ID_AA64PFR0_EL0_VAL(READ_SPECIALREG(id_aa64pfr0_el1)) ==
163 	    ID_AA64PFR0_EL0_64_32) {
164 		elf32_insert_brand_entry(&freebsd32_brand_info);
165 	} else {
166 		compat_freebsd_32bit = 0;
167 	}
168 }
169 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, register_elf32_brand, NULL);
170 
171 static bool
elf32_arm_abi_supported(const struct image_params * imgp,const int32_t * osrel __unused,const uint32_t * fctl0 __unused)172 elf32_arm_abi_supported(const struct image_params *imgp,
173     const int32_t *osrel __unused, const uint32_t *fctl0 __unused)
174 {
175 	const Elf32_Ehdr *hdr;
176 
177 #define	EF_ARM_EABI_FREEBSD_MIN	EF_ARM_EABI_VER4
178 	hdr = (const Elf32_Ehdr *)imgp->image_header;
179 	if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) {
180 		if (bootverbose)
181 			uprintf("Attempting to execute non EABI binary "
182 			    "(rev %d) image %s",
183 			    EF_ARM_EABI_VERSION(hdr->e_flags),
184 			    imgp->args->fname);
185 		return (false);
186         }
187 
188 	return (true);
189 }
190 
191 static int
freebsd32_fetch_syscall_args(struct thread * td)192 freebsd32_fetch_syscall_args(struct thread *td)
193 {
194 	struct proc *p;
195 	register_t *ap;
196 	struct syscall_args *sa;
197 	int error, i, nap, narg;
198 	unsigned int args[4];
199 
200 	nap = 4;
201 	p = td->td_proc;
202 	ap = td->td_frame->tf_x;
203 	sa = &td->td_sa;
204 
205 	/* r7 is the syscall id */
206 	sa->code = td->td_frame->tf_x[7];
207 	sa->original_code = sa->code;
208 
209 	if (sa->code == SYS_syscall) {
210 		sa->code = *ap++;
211 		nap--;
212 	} else if (sa->code == SYS___syscall) {
213 		sa->code = ap[1];
214 		nap -= 2;
215 		ap += 2;
216 	}
217 
218 	if (sa->code >= p->p_sysent->sv_size)
219 		sa->callp = &nosys_sysent;
220 	else
221 		sa->callp = &p->p_sysent->sv_table[sa->code];
222 
223 	narg = sa->callp->sy_narg;
224 	for (i = 0; i < nap; i++)
225 		sa->args[i] = ap[i];
226 	if (narg > nap) {
227 		if (narg - nap > nitems(args))
228 			panic("Too many system call arguiments");
229 		error = copyin((void *)td->td_frame->tf_x[13], args,
230 		    (narg - nap) * sizeof(int));
231 		if (error != 0)
232 			return (error);
233 		for (i = 0; i < (narg - nap); i++)
234 			sa->args[i + nap] = args[i];
235 	}
236 
237 	td->td_retval[0] = 0;
238 	td->td_retval[1] = 0;
239 
240 	return (0);
241 }
242 
243 static void
freebsd32_set_syscall_retval(struct thread * td,int error)244 freebsd32_set_syscall_retval(struct thread *td, int error)
245 {
246 	struct trapframe *frame;
247 
248 	frame = td->td_frame;
249 	switch (error) {
250 	case 0:
251 		frame->tf_x[0] = td->td_retval[0];
252 		frame->tf_x[1] = td->td_retval[1];
253 		frame->tf_spsr &= ~PSR_C;
254 		break;
255 	case ERESTART:
256 		/*
257 		 * Reconstruct the pc to point at the swi.
258 		 */
259 		if ((frame->tf_spsr & PSR_T) != 0)
260 			frame->tf_elr -= 2; //THUMB_INSN_SIZE;
261 		else
262 			frame->tf_elr -= 4; //INSN_SIZE;
263 		break;
264 	case EJUSTRETURN:
265 		/* nothing to do */
266 		break;
267 	default:
268 		frame->tf_x[0] = error;
269 		frame->tf_spsr |= PSR_C;
270 		break;
271 	}
272 }
273 
274 static void
freebsd32_setregs(struct thread * td,struct image_params * imgp,uintptr_t stack)275 freebsd32_setregs(struct thread *td, struct image_params *imgp,
276    uintptr_t stack)
277 {
278 	struct trapframe *tf = td->td_frame;
279 	struct pcb *pcb = td->td_pcb;
280 
281 	memset(tf, 0, sizeof(struct trapframe));
282 
283 	/*
284 	 * We need to set x0 for init as it doesn't call
285 	 * cpu_set_syscall_retval to copy the value. We also
286 	 * need to set td_retval for the cases where we do.
287 	 */
288 	tf->tf_x[0] = stack;
289 	/* SP_usr is mapped to x13 */
290 	tf->tf_x[13] = stack;
291 	/* LR_usr is mapped to x14 */
292 	tf->tf_x[14] = imgp->entry_addr;
293 	tf->tf_elr = imgp->entry_addr;
294 	tf->tf_spsr = PSR_M_32;
295 	if ((uint32_t)imgp->entry_addr & 1)
296 		tf->tf_spsr |= PSR_T;
297 
298 #ifdef VFP
299 	vfp_reset_state(td, pcb);
300 #endif
301 
302 	/*
303 	 * Clear debug register state. It is not applicable to the new process.
304 	 */
305 	bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs));
306 }
307 
308 void
elf32_dump_thread(struct thread * td,void * dst,size_t * off)309 elf32_dump_thread(struct thread *td, void *dst, size_t *off)
310 {
311 }
312 
313 static void
elf32_fixlimit(struct rlimit * rl,int which)314 elf32_fixlimit(struct rlimit *rl, int which)
315 {
316 
317 	switch (which) {
318 	case RLIMIT_DATA:
319 		if (aarch32_maxdsiz != 0) {
320 			if (rl->rlim_cur > aarch32_maxdsiz)
321 				rl->rlim_cur = aarch32_maxdsiz;
322 			if (rl->rlim_max > aarch32_maxdsiz)
323 				rl->rlim_max = aarch32_maxdsiz;
324 		}
325 		break;
326 	case RLIMIT_STACK:
327 		if (aarch32_maxssiz != 0) {
328 			if (rl->rlim_cur > aarch32_maxssiz)
329 				rl->rlim_cur = aarch32_maxssiz;
330 			if (rl->rlim_max > aarch32_maxssiz)
331 				rl->rlim_max = aarch32_maxssiz;
332 		}
333 		break;
334 	case RLIMIT_VMEM:
335 		if (aarch32_maxvmem != 0) {
336 			if (rl->rlim_cur > aarch32_maxvmem)
337 				rl->rlim_cur = aarch32_maxvmem;
338 			if (rl->rlim_max > aarch32_maxvmem)
339 				rl->rlim_max = aarch32_maxvmem;
340 		}
341 		break;
342 	}
343 }
344