xref: /freebsd/sys/arm64/arm64/elf32_machdep.c (revision a2a8b582)
19dcf90f8SEd Schouten /*-
28c9c3144SOlivier Houchard  * Copyright (c) 2014, 2015 The FreeBSD Foundation.
38c9c3144SOlivier Houchard  * Copyright (c) 2014, 2017 Andrew Turner.
48c9c3144SOlivier Houchard  * Copyright (c) 2018 Olivier Houchard
58c9c3144SOlivier Houchard  * All rights reserved.
68c9c3144SOlivier Houchard  *
78c9c3144SOlivier Houchard  * This software was developed by Andrew Turner under
88c9c3144SOlivier Houchard  * sponsorship from the FreeBSD Foundation.
98c9c3144SOlivier Houchard  *
108c9c3144SOlivier Houchard  * Portions of this software were developed by Konstantin Belousov
118c9c3144SOlivier Houchard  * under sponsorship from the FreeBSD Foundation.
129dcf90f8SEd Schouten  *
139dcf90f8SEd Schouten  * Redistribution and use in source and binary forms, with or without
149dcf90f8SEd Schouten  * modification, are permitted provided that the following conditions
159dcf90f8SEd Schouten  * are met:
169dcf90f8SEd Schouten  * 1. Redistributions of source code must retain the above copyright
179dcf90f8SEd Schouten  *    notice, this list of conditions and the following disclaimer.
189dcf90f8SEd Schouten  * 2. Redistributions in binary form must reproduce the above copyright
199dcf90f8SEd Schouten  *    notice, this list of conditions and the following disclaimer in the
209dcf90f8SEd Schouten  *    documentation and/or other materials provided with the distribution.
219dcf90f8SEd Schouten  *
229dcf90f8SEd Schouten  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
239dcf90f8SEd Schouten  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249dcf90f8SEd Schouten  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259dcf90f8SEd Schouten  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
269dcf90f8SEd Schouten  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279dcf90f8SEd Schouten  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289dcf90f8SEd Schouten  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299dcf90f8SEd Schouten  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309dcf90f8SEd Schouten  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319dcf90f8SEd Schouten  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329dcf90f8SEd Schouten  * SUCH DAMAGE.
339dcf90f8SEd Schouten  */
349dcf90f8SEd Schouten 
359dcf90f8SEd Schouten #include <sys/cdefs.h>
369dcf90f8SEd Schouten __FBSDID("$FreeBSD$");
379dcf90f8SEd Schouten 
389dcf90f8SEd Schouten #define	__ELF_WORD_SIZE 32
398c9c3144SOlivier Houchard 
408c9c3144SOlivier Houchard #include <sys/param.h>
418c9c3144SOlivier Houchard #include <sys/kernel.h>
428c9c3144SOlivier Houchard #include <sys/systm.h>
438c9c3144SOlivier Houchard #include <sys/exec.h>
448c9c3144SOlivier Houchard #include <sys/imgact.h>
458c9c3144SOlivier Houchard #include <sys/linker.h>
468c9c3144SOlivier Houchard #include <sys/proc.h>
478c9c3144SOlivier Houchard #include <sys/sysent.h>
489dcf90f8SEd Schouten #include <sys/imgact_elf.h>
498c9c3144SOlivier Houchard #include <sys/syscall.h>
508c9c3144SOlivier Houchard #include <sys/signalvar.h>
518c9c3144SOlivier Houchard #include <sys/vnode.h>
528c9c3144SOlivier Houchard 
538c9c3144SOlivier Houchard #include <machine/elf.h>
54953a7d7cSAlex Richardson #ifdef VFP
55953a7d7cSAlex Richardson #include <machine/vfp.h>
56953a7d7cSAlex Richardson #endif
578c9c3144SOlivier Houchard 
588c9c3144SOlivier Houchard #include <compat/freebsd32/freebsd32_util.h>
598c9c3144SOlivier Houchard 
608c9c3144SOlivier Houchard #define	FREEBSD32_MINUSER	0x00001000
618c9c3144SOlivier Houchard #define	FREEBSD32_MAXUSER	((1ul << 32) - PAGE_SIZE)
628c9c3144SOlivier Houchard #define	FREEBSD32_SHAREDPAGE	(FREEBSD32_MAXUSER - PAGE_SIZE)
638c9c3144SOlivier Houchard #define	FREEBSD32_USRSTACK	FREEBSD32_SHAREDPAGE
648c9c3144SOlivier Houchard 
658c9c3144SOlivier Houchard extern const char *freebsd32_syscallnames[];
668c9c3144SOlivier Houchard 
678c9c3144SOlivier Houchard extern char aarch32_sigcode[];
688c9c3144SOlivier Houchard extern int sz_aarch32_sigcode;
698c9c3144SOlivier Houchard 
708c9c3144SOlivier Houchard static int freebsd32_fetch_syscall_args(struct thread *td);
718c9c3144SOlivier Houchard static void freebsd32_setregs(struct thread *td, struct image_params *imgp,
728c9c3144SOlivier Houchard     u_long stack);
738c9c3144SOlivier Houchard static void freebsd32_set_syscall_retval(struct thread *, int);
748c9c3144SOlivier Houchard 
750cad2aa2SKonstantin Belousov static boolean_t elf32_arm_abi_supported(struct image_params *, int32_t *,
760cad2aa2SKonstantin Belousov     uint32_t *);
778c9c3144SOlivier Houchard 
788c9c3144SOlivier Houchard extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
798c9c3144SOlivier Houchard 
808c9c3144SOlivier Houchard static struct sysentvec elf32_freebsd_sysvec = {
818c9c3144SOlivier Houchard 	.sv_size	= SYS_MAXSYSCALL,
828c9c3144SOlivier Houchard 	.sv_table	= freebsd32_sysent,
838c9c3144SOlivier Houchard 	.sv_transtrap	= NULL,
848c9c3144SOlivier Houchard 	.sv_fixup	= elf32_freebsd_fixup,
858c9c3144SOlivier Houchard 	.sv_sendsig	= freebsd32_sendsig,
868c9c3144SOlivier Houchard 	.sv_sigcode	= aarch32_sigcode,
878c9c3144SOlivier Houchard 	.sv_szsigcode	= &sz_aarch32_sigcode,
888c9c3144SOlivier Houchard 	.sv_name	= "FreeBSD ELF32",
898c9c3144SOlivier Houchard 	.sv_coredump	= elf32_coredump,
908c9c3144SOlivier Houchard 	.sv_imgact_try	= NULL,
918c9c3144SOlivier Houchard 	.sv_minsigstksz	= MINSIGSTKSZ,
928c9c3144SOlivier Houchard 	.sv_minuser	= FREEBSD32_MINUSER,
938c9c3144SOlivier Houchard 	.sv_maxuser	= FREEBSD32_MAXUSER,
948c9c3144SOlivier Houchard 	.sv_usrstack	= FREEBSD32_USRSTACK,
958c9c3144SOlivier Houchard 	.sv_psstrings	= FREEBSD32_PS_STRINGS,
968c9c3144SOlivier Houchard 	.sv_stackprot	= VM_PROT_READ | VM_PROT_WRITE,
97e3532331SJohn Baldwin 	.sv_copyout_auxargs = elf32_freebsd_copyout_auxargs,
988c9c3144SOlivier Houchard 	.sv_copyout_strings = freebsd32_copyout_strings,
998c9c3144SOlivier Houchard 	.sv_setregs	= freebsd32_setregs,
1008c9c3144SOlivier Houchard 	.sv_fixlimit	= NULL, // XXX
1018c9c3144SOlivier Houchard 	.sv_maxssiz	= NULL,
102f8e8a06dSConrad Meyer 	.sv_flags	= SV_ABI_FREEBSD | SV_ILP32 | SV_SHP | SV_TIMEKEEP |
103f8e8a06dSConrad Meyer 	    SV_RNG_SEED_VER,
1048c9c3144SOlivier Houchard 	.sv_set_syscall_retval = freebsd32_set_syscall_retval,
1058c9c3144SOlivier Houchard 	.sv_fetch_syscall_args = freebsd32_fetch_syscall_args,
1068c9c3144SOlivier Houchard 	.sv_syscallnames = freebsd32_syscallnames,
1078c9c3144SOlivier Houchard 	.sv_shared_page_base = FREEBSD32_SHAREDPAGE,
1088c9c3144SOlivier Houchard 	.sv_shared_page_len = PAGE_SIZE,
1098c9c3144SOlivier Houchard 	.sv_schedtail	= NULL,
1108c9c3144SOlivier Houchard 	.sv_thread_detach = NULL,
1118c9c3144SOlivier Houchard 	.sv_trap	= NULL,
1128c9c3144SOlivier Houchard };
1138c9c3144SOlivier Houchard INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
1148c9c3144SOlivier Houchard 
1158c9c3144SOlivier Houchard static Elf32_Brandinfo freebsd32_brand_info = {
1168c9c3144SOlivier Houchard 	.brand		= ELFOSABI_FREEBSD,
1178c9c3144SOlivier Houchard 	.machine	= EM_ARM,
1188c9c3144SOlivier Houchard 	.compat_3_brand	= "FreeBSD",
1198c9c3144SOlivier Houchard 	.emul_path	= NULL,
1208c9c3144SOlivier Houchard 	.interp_path	= "/libexec/ld-elf.so.1",
1218c9c3144SOlivier Houchard 	.sysvec		= &elf32_freebsd_sysvec,
12224718606SJustin Hibbits 	.interp_newpath	= "/libexec/ld-elf32.so.1",
1238c9c3144SOlivier Houchard 	.brand_note	= &elf32_freebsd_brandnote,
1248c9c3144SOlivier Houchard 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
1258c9c3144SOlivier Houchard 	.header_supported= elf32_arm_abi_supported,
1268c9c3144SOlivier Houchard };
1278c9c3144SOlivier Houchard 
1288c9c3144SOlivier Houchard SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST,
1298c9c3144SOlivier Houchard     (sysinit_cfunc_t)elf32_insert_brand_entry, &freebsd32_brand_info);
1308c9c3144SOlivier Houchard 
1318c9c3144SOlivier Houchard static boolean_t
1320cad2aa2SKonstantin Belousov elf32_arm_abi_supported(struct image_params *imgp, int32_t *osrel __unused,
1330cad2aa2SKonstantin Belousov     uint32_t *fctl0 __unused)
1348c9c3144SOlivier Houchard {
1358c9c3144SOlivier Houchard 	const Elf32_Ehdr *hdr;
1368c9c3144SOlivier Houchard 
1378c9c3144SOlivier Houchard 	/* Check if we support AArch32 */
13844e446a1SAndrew Turner 	if (ID_AA64PFR0_EL0_VAL(READ_SPECIALREG(id_aa64pfr0_el1)) !=
1398c9c3144SOlivier Houchard 	    ID_AA64PFR0_EL0_64_32)
1408c9c3144SOlivier Houchard 		return (FALSE);
1418c9c3144SOlivier Houchard 
1428c9c3144SOlivier Houchard #define	EF_ARM_EABI_VERSION(x)	(((x) & EF_ARM_EABIMASK) >> 24)
1438c9c3144SOlivier Houchard #define	EF_ARM_EABI_FREEBSD_MIN	4
1448c9c3144SOlivier Houchard 	hdr = (const Elf32_Ehdr *)imgp->image_header;
1458c9c3144SOlivier Houchard 	if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) {
1468c9c3144SOlivier Houchard 		if (bootverbose)
1478c9c3144SOlivier Houchard 			uprintf("Attempting to execute non EABI binary "
1488c9c3144SOlivier Houchard 			    "(rev %d) image %s",
1498c9c3144SOlivier Houchard 			    EF_ARM_EABI_VERSION(hdr->e_flags),
1508c9c3144SOlivier Houchard 			    imgp->args->fname);
1518c9c3144SOlivier Houchard 		return (FALSE);
1528c9c3144SOlivier Houchard         }
1538c9c3144SOlivier Houchard 
1548c9c3144SOlivier Houchard 	return (TRUE);
1558c9c3144SOlivier Houchard }
1568c9c3144SOlivier Houchard 
1578c9c3144SOlivier Houchard static int
1588c9c3144SOlivier Houchard freebsd32_fetch_syscall_args(struct thread *td)
1598c9c3144SOlivier Houchard {
1608c9c3144SOlivier Houchard 	struct proc *p;
1618c9c3144SOlivier Houchard 	register_t *ap;
1628c9c3144SOlivier Houchard 	struct syscall_args *sa;
1631e2521ffSEdward Tomasz Napierala 	int error, i, nap, narg;
1648c9c3144SOlivier Houchard 	unsigned int args[4];
1658c9c3144SOlivier Houchard 
1668c9c3144SOlivier Houchard 	nap = 4;
1678c9c3144SOlivier Houchard 	p = td->td_proc;
1688c9c3144SOlivier Houchard 	ap = td->td_frame->tf_x;
1698c9c3144SOlivier Houchard 	sa = &td->td_sa;
1708c9c3144SOlivier Houchard 
1718c9c3144SOlivier Houchard 	/* r7 is the syscall id */
1728c9c3144SOlivier Houchard 	sa->code = td->td_frame->tf_x[7];
1738c9c3144SOlivier Houchard 
1748c9c3144SOlivier Houchard 	if (sa->code == SYS_syscall) {
1758c9c3144SOlivier Houchard 		sa->code = *ap++;
1768c9c3144SOlivier Houchard 		nap--;
1778c9c3144SOlivier Houchard 	} else if (sa->code == SYS___syscall) {
1788c9c3144SOlivier Houchard 		sa->code = ap[1];
1798c9c3144SOlivier Houchard 		nap -= 2;
1808c9c3144SOlivier Houchard 		ap += 2;
1818c9c3144SOlivier Houchard 	}
1828c9c3144SOlivier Houchard 
1838c9c3144SOlivier Houchard 	if (sa->code >= p->p_sysent->sv_size)
1848c9c3144SOlivier Houchard 		sa->callp = &p->p_sysent->sv_table[0];
1858c9c3144SOlivier Houchard 	else
1868c9c3144SOlivier Houchard 		sa->callp = &p->p_sysent->sv_table[sa->code];
1878c9c3144SOlivier Houchard 
1881e2521ffSEdward Tomasz Napierala 	narg = sa->callp->sy_narg;
1898c9c3144SOlivier Houchard 	for (i = 0; i < nap; i++)
1908c9c3144SOlivier Houchard 		sa->args[i] = ap[i];
1911e2521ffSEdward Tomasz Napierala 	if (narg > nap) {
1921e2521ffSEdward Tomasz Napierala 		if (narg - nap > nitems(args))
1938c9c3144SOlivier Houchard 			panic("Too many system call arguiments");
1948c9c3144SOlivier Houchard 		error = copyin((void *)td->td_frame->tf_x[13], args,
1951e2521ffSEdward Tomasz Napierala 		    (narg - nap) * sizeof(int));
1961e2521ffSEdward Tomasz Napierala 		for (i = 0; i < (narg - nap); i++)
1978c9c3144SOlivier Houchard 			sa->args[i + nap] = args[i];
1988c9c3144SOlivier Houchard 	}
1998c9c3144SOlivier Houchard 
2008c9c3144SOlivier Houchard 	td->td_retval[0] = 0;
2018c9c3144SOlivier Houchard 	td->td_retval[1] = 0;
2028c9c3144SOlivier Houchard 
2038c9c3144SOlivier Houchard 	return (0);
2048c9c3144SOlivier Houchard }
2058c9c3144SOlivier Houchard 
2068c9c3144SOlivier Houchard static void
2078c9c3144SOlivier Houchard freebsd32_set_syscall_retval(struct thread *td, int error)
2088c9c3144SOlivier Houchard {
2098c9c3144SOlivier Houchard 	struct trapframe *frame;
2108c9c3144SOlivier Houchard 
2118c9c3144SOlivier Houchard 	frame = td->td_frame;
2128c9c3144SOlivier Houchard 	switch (error) {
2138c9c3144SOlivier Houchard 	case 0:
2148c9c3144SOlivier Houchard 		frame->tf_x[0] = td->td_retval[0];
2158c9c3144SOlivier Houchard 		frame->tf_x[1] = td->td_retval[1];
2168c9c3144SOlivier Houchard 		frame->tf_spsr &= ~PSR_C;
2178c9c3144SOlivier Houchard 		break;
2188c9c3144SOlivier Houchard 	case ERESTART:
2198c9c3144SOlivier Houchard 		/*
2208c9c3144SOlivier Houchard 		 * Reconstruct the pc to point at the swi.
2218c9c3144SOlivier Houchard 		 */
2228c9c3144SOlivier Houchard 		if ((frame->tf_spsr & PSR_T) != 0)
2238c9c3144SOlivier Houchard 			frame->tf_elr -= 2; //THUMB_INSN_SIZE;
2248c9c3144SOlivier Houchard 		else
2258c9c3144SOlivier Houchard 			frame->tf_elr -= 4; //INSN_SIZE;
2268c9c3144SOlivier Houchard 		break;
2278c9c3144SOlivier Houchard 	case EJUSTRETURN:
2288c9c3144SOlivier Houchard 		/* nothing to do */
2298c9c3144SOlivier Houchard 		break;
2308c9c3144SOlivier Houchard 	default:
2318c9c3144SOlivier Houchard 		frame->tf_x[0] = error;
2328c9c3144SOlivier Houchard 		frame->tf_spsr |= PSR_C;
2338c9c3144SOlivier Houchard 		break;
2348c9c3144SOlivier Houchard 	}
2358c9c3144SOlivier Houchard }
2368c9c3144SOlivier Houchard 
2378c9c3144SOlivier Houchard static void
2388c9c3144SOlivier Houchard freebsd32_setregs(struct thread *td, struct image_params *imgp,
23931174518SJohn Baldwin    uintptr_t stack)
2408c9c3144SOlivier Houchard {
2418c9c3144SOlivier Houchard 	struct trapframe *tf = td->td_frame;
242a2a8b582SMitchell Horne 	struct pcb *pcb = td->td_pcb;
2438c9c3144SOlivier Houchard 
2448c9c3144SOlivier Houchard 	memset(tf, 0, sizeof(struct trapframe));
2458c9c3144SOlivier Houchard 
2468c9c3144SOlivier Houchard 	/*
2478c9c3144SOlivier Houchard 	 * We need to set x0 for init as it doesn't call
2488c9c3144SOlivier Houchard 	 * cpu_set_syscall_retval to copy the value. We also
2498c9c3144SOlivier Houchard 	 * need to set td_retval for the cases where we do.
2508c9c3144SOlivier Houchard 	 */
2518c9c3144SOlivier Houchard 	tf->tf_x[0] = stack;
2528c9c3144SOlivier Houchard 	/* SP_usr is mapped to x13 */
2538c9c3144SOlivier Houchard 	tf->tf_x[13] = stack;
2548c9c3144SOlivier Houchard 	/* LR_usr is mapped to x14 */
2558c9c3144SOlivier Houchard 	tf->tf_x[14] = imgp->entry_addr;
2568c9c3144SOlivier Houchard 	tf->tf_elr = imgp->entry_addr;
2578c9c3144SOlivier Houchard 	tf->tf_spsr = PSR_M_32;
258953a7d7cSAlex Richardson 
259953a7d7cSAlex Richardson #ifdef VFP
260a2a8b582SMitchell Horne 	vfp_reset_state(td, pcb);
261953a7d7cSAlex Richardson #endif
262a2a8b582SMitchell Horne 
263a2a8b582SMitchell Horne 	/*
264a2a8b582SMitchell Horne 	 * Clear debug register state. It is not applicable to the new process.
265a2a8b582SMitchell Horne 	 */
266a2a8b582SMitchell Horne 	bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs));
2678c9c3144SOlivier Houchard }
2689dcf90f8SEd Schouten 
2699dcf90f8SEd Schouten void
2708c9c3144SOlivier Houchard elf32_dump_thread(struct thread *td, void *dst, size_t *off)
2719dcf90f8SEd Schouten {
2728c9c3144SOlivier Houchard 	/* XXX: VFP */
2739dcf90f8SEd Schouten }
274