xref: /freebsd/sys/arm64/arm64/elf32_machdep.c (revision 6419bb52)
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 *);
73 
74 extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
75 
76 static struct sysentvec elf32_freebsd_sysvec = {
77 	.sv_size	= SYS_MAXSYSCALL,
78 	.sv_table	= freebsd32_sysent,
79 	.sv_errsize	= 0,
80 	.sv_errtbl	= NULL,
81 	.sv_transtrap	= NULL,
82 	.sv_fixup	= elf32_freebsd_fixup,
83 	.sv_sendsig	= freebsd32_sendsig,
84 	.sv_sigcode	= aarch32_sigcode,
85 	.sv_szsigcode	= &sz_aarch32_sigcode,
86 	.sv_name	= "FreeBSD ELF32",
87 	.sv_coredump	= elf32_coredump,
88 	.sv_imgact_try	= NULL,
89 	.sv_minsigstksz	= MINSIGSTKSZ,
90 	.sv_minuser	= FREEBSD32_MINUSER,
91 	.sv_maxuser	= FREEBSD32_MAXUSER,
92 	.sv_usrstack	= FREEBSD32_USRSTACK,
93 	.sv_psstrings	= FREEBSD32_PS_STRINGS,
94 	.sv_stackprot	= VM_PROT_READ | VM_PROT_WRITE,
95 	.sv_copyout_auxargs = elf32_freebsd_copyout_auxargs,
96 	.sv_copyout_strings = freebsd32_copyout_strings,
97 	.sv_setregs	= freebsd32_setregs,
98 	.sv_fixlimit	= NULL, // XXX
99 	.sv_maxssiz	= NULL,
100 	.sv_flags	= SV_ABI_FREEBSD | SV_ILP32 | SV_SHP | SV_TIMEKEEP,
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
129 elf32_arm_abi_supported(struct image_params *imgp)
130 {
131 	const Elf32_Ehdr *hdr;
132 
133 	/* Check if we support AArch32 */
134 	if (ID_AA64PFR0_EL0_VAL(READ_SPECIALREG(id_aa64pfr0_el1)) !=
135 	    ID_AA64PFR0_EL0_64_32)
136 		return (FALSE);
137 
138 #define	EF_ARM_EABI_VERSION(x)	(((x) & EF_ARM_EABIMASK) >> 24)
139 #define	EF_ARM_EABI_FREEBSD_MIN	4
140 	hdr = (const Elf32_Ehdr *)imgp->image_header;
141 	if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) {
142 		if (bootverbose)
143 			uprintf("Attempting to execute non EABI binary "
144 			    "(rev %d) image %s",
145 			    EF_ARM_EABI_VERSION(hdr->e_flags),
146 			    imgp->args->fname);
147 		return (FALSE);
148         }
149 
150 	return (TRUE);
151 }
152 
153 static int
154 freebsd32_fetch_syscall_args(struct thread *td)
155 {
156 	struct proc *p;
157 	register_t *ap;
158 	struct syscall_args *sa;
159 	int error, i, nap;
160 	unsigned int args[4];
161 
162 	nap = 4;
163 	p = td->td_proc;
164 	ap = td->td_frame->tf_x;
165 	sa = &td->td_sa;
166 
167 	/* r7 is the syscall id */
168 	sa->code = td->td_frame->tf_x[7];
169 
170 	if (sa->code == SYS_syscall) {
171 		sa->code = *ap++;
172 		nap--;
173 	} else if (sa->code == SYS___syscall) {
174 		sa->code = ap[1];
175 		nap -= 2;
176 		ap += 2;
177 	}
178 
179 	if (sa->code >= p->p_sysent->sv_size)
180 		sa->callp = &p->p_sysent->sv_table[0];
181 	else
182 		sa->callp = &p->p_sysent->sv_table[sa->code];
183 
184 	sa->narg = sa->callp->sy_narg;
185 	for (i = 0; i < nap; i++)
186 		sa->args[i] = ap[i];
187 	if (sa->narg > nap) {
188 		if ((sa->narg - nap) > nitems(args))
189 			panic("Too many system call arguiments");
190 		error = copyin((void *)td->td_frame->tf_x[13], args,
191 		    (sa->narg - nap) * sizeof(int));
192 		for (i = 0; i < (sa->narg - nap); i++)
193 			sa->args[i + nap] = args[i];
194 	}
195 
196 	td->td_retval[0] = 0;
197 	td->td_retval[1] = 0;
198 
199 	return (0);
200 }
201 
202 static void
203 freebsd32_set_syscall_retval(struct thread *td, int error)
204 {
205 	struct trapframe *frame;
206 
207 	frame = td->td_frame;
208 	switch (error) {
209 	case 0:
210 		frame->tf_x[0] = td->td_retval[0];
211 		frame->tf_x[1] = td->td_retval[1];
212 		frame->tf_spsr &= ~PSR_C;
213 		break;
214 	case ERESTART:
215 		/*
216 		 * Reconstruct the pc to point at the swi.
217 		 */
218 		if ((frame->tf_spsr & PSR_T) != 0)
219 			frame->tf_elr -= 2; //THUMB_INSN_SIZE;
220 		else
221 			frame->tf_elr -= 4; //INSN_SIZE;
222 		break;
223 	case EJUSTRETURN:
224 		/* nothing to do */
225 		break;
226 	default:
227 		frame->tf_x[0] = error;
228 		frame->tf_spsr |= PSR_C;
229 		break;
230 	}
231 }
232 
233 static void
234 freebsd32_setregs(struct thread *td, struct image_params *imgp,
235    uintptr_t stack)
236 {
237 	struct trapframe *tf = td->td_frame;
238 
239 	memset(tf, 0, sizeof(struct trapframe));
240 
241 	/*
242 	 * We need to set x0 for init as it doesn't call
243 	 * cpu_set_syscall_retval to copy the value. We also
244 	 * need to set td_retval for the cases where we do.
245 	 */
246 	tf->tf_x[0] = stack;
247 	/* SP_usr is mapped to x13 */
248 	tf->tf_x[13] = stack;
249 	/* LR_usr is mapped to x14 */
250 	tf->tf_x[14] = imgp->entry_addr;
251 	tf->tf_elr = imgp->entry_addr;
252 	tf->tf_spsr = PSR_M_32;
253 }
254 
255 void
256 elf32_dump_thread(struct thread *td, void *dst, size_t *off)
257 {
258 	/* XXX: VFP */
259 }
260