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
69extern const char *freebsd32_syscallnames[];
70
71extern char aarch32_sigcode[];
72extern int sz_aarch32_sigcode;
73
74static int freebsd32_fetch_syscall_args(struct thread *td);
75static void freebsd32_setregs(struct thread *td, struct image_params *imgp,
76    u_long stack);
77static void freebsd32_set_syscall_retval(struct thread *, int);
78
79static bool elf32_arm_abi_supported(const struct image_params *,
80    const int32_t *, const uint32_t *);
81static void elf32_fixlimit(struct rlimit *rl, int which);
82
83extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
84
85u_long __read_frequently elf32_hwcap;
86u_long __read_frequently elf32_hwcap2;
87
88static SYSCTL_NODE(_compat, OID_AUTO, aarch32, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
89    "aarch32 mode");
90
91static u_long aarch32_maxdsiz = AARCH32_MAXDSIZ;
92SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxdsiz, CTLFLAG_RWTUN,
93    &aarch32_maxdsiz, 0, "");
94u_long aarch32_maxssiz = AARCH32_MAXSSIZ;
95SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxssiz, CTLFLAG_RWTUN,
96    &aarch32_maxssiz, 0, "");
97static u_long aarch32_maxvmem = AARCH32_MAXVMEM;
98SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxvmem, CTLFLAG_RWTUN,
99    &aarch32_maxvmem, 0, "");
100
101static 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};
142INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
143
144static 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
156static void
157register_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}
167SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, register_elf32_brand, NULL);
168
169static bool
170elf32_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
189static int
190freebsd32_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
241static void
242freebsd32_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
272static void
273freebsd32_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
306void
307elf32_dump_thread(struct thread *td, void *dst, size_t *off)
308{
309}
310
311static void
312elf32_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}
342