xref: /freebsd/sys/arm64/linux/linux_sysvec.c (revision 3911ee2c92b773064abaefe0ce08006e2bebd26d)
1*3911ee2cSEd Maste /*-
2*3911ee2cSEd Maste  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*3911ee2cSEd Maste  *
4*3911ee2cSEd Maste  * Copyright (c) 1994-1996 Søren Schmidt
5*3911ee2cSEd Maste  * Copyright (c) 2018 Turing Robotic Industries Inc.
6*3911ee2cSEd Maste  *
7*3911ee2cSEd Maste  * Redistribution and use in source and binary forms, with or without
8*3911ee2cSEd Maste  * modification, are permitted provided that the following conditions
9*3911ee2cSEd Maste  * are met:
10*3911ee2cSEd Maste  * 1. Redistributions of source code must retain the above copyright
11*3911ee2cSEd Maste  *    notice, this list of conditions and the following disclaimer.
12*3911ee2cSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
13*3911ee2cSEd Maste  *    notice, this list of conditions and the following disclaimer in the
14*3911ee2cSEd Maste  *    documentation and/or other materials provided with the distribution.
15*3911ee2cSEd Maste  *
16*3911ee2cSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*3911ee2cSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*3911ee2cSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*3911ee2cSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*3911ee2cSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*3911ee2cSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*3911ee2cSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*3911ee2cSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*3911ee2cSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*3911ee2cSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*3911ee2cSEd Maste  * SUCH DAMAGE.
27*3911ee2cSEd Maste  */
28*3911ee2cSEd Maste 
29*3911ee2cSEd Maste #include <sys/cdefs.h>
30*3911ee2cSEd Maste __FBSDID("$FreeBSD$");
31*3911ee2cSEd Maste 
32*3911ee2cSEd Maste #include <sys/param.h>
33*3911ee2cSEd Maste #include <sys/systm.h>
34*3911ee2cSEd Maste #include <sys/cdefs.h>
35*3911ee2cSEd Maste #include <sys/elf.h>
36*3911ee2cSEd Maste #include <sys/exec.h>
37*3911ee2cSEd Maste #include <sys/imgact.h>
38*3911ee2cSEd Maste #include <sys/imgact_elf.h>
39*3911ee2cSEd Maste #include <sys/kernel.h>
40*3911ee2cSEd Maste #include <sys/lock.h>
41*3911ee2cSEd Maste #include <sys/module.h>
42*3911ee2cSEd Maste #include <sys/mutex.h>
43*3911ee2cSEd Maste #include <sys/proc.h>
44*3911ee2cSEd Maste #include <sys/signalvar.h>
45*3911ee2cSEd Maste #include <sys/sysctl.h>
46*3911ee2cSEd Maste #include <sys/sysent.h>
47*3911ee2cSEd Maste 
48*3911ee2cSEd Maste #include <vm/vm_param.h>
49*3911ee2cSEd Maste 
50*3911ee2cSEd Maste #include <arm64/linux/linux.h>
51*3911ee2cSEd Maste #include <arm64/linux/linux_proto.h>
52*3911ee2cSEd Maste #include <compat/linux/linux_dtrace.h>
53*3911ee2cSEd Maste #include <compat/linux/linux_emul.h>
54*3911ee2cSEd Maste #include <compat/linux/linux_futex.h>
55*3911ee2cSEd Maste #include <compat/linux/linux_ioctl.h>
56*3911ee2cSEd Maste #include <compat/linux/linux_mib.h>
57*3911ee2cSEd Maste #include <compat/linux/linux_misc.h>
58*3911ee2cSEd Maste #include <compat/linux/linux_vdso.h>
59*3911ee2cSEd Maste 
60*3911ee2cSEd Maste MODULE_VERSION(linux64elf, 1);
61*3911ee2cSEd Maste 
62*3911ee2cSEd Maste #if defined(DEBUG)
63*3911ee2cSEd Maste SYSCTL_PROC(_compat_linux, OID_AUTO, debug, CTLTYPE_STRING | CTLFLAG_RW, 0, 0,
64*3911ee2cSEd Maste     linux_sysctl_debug, "A", "64-bit Linux debugging control");
65*3911ee2cSEd Maste #endif
66*3911ee2cSEd Maste 
67*3911ee2cSEd Maste const char *linux_kplatform;
68*3911ee2cSEd Maste static int linux_szsigcode;
69*3911ee2cSEd Maste static vm_object_t linux_shared_page_obj;
70*3911ee2cSEd Maste static char *linux_shared_page_mapping;
71*3911ee2cSEd Maste extern char _binary_linux_locore_o_start;
72*3911ee2cSEd Maste extern char _binary_linux_locore_o_end;
73*3911ee2cSEd Maste 
74*3911ee2cSEd Maste extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
75*3911ee2cSEd Maste 
76*3911ee2cSEd Maste SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
77*3911ee2cSEd Maste 
78*3911ee2cSEd Maste static register_t *linux_copyout_strings(struct image_params *imgp);
79*3911ee2cSEd Maste static int	linux_elf_fixup(register_t **stack_base,
80*3911ee2cSEd Maste 		    struct image_params *iparams);
81*3911ee2cSEd Maste static bool	linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
82*3911ee2cSEd Maste static void	linux_vdso_install(const void *param);
83*3911ee2cSEd Maste static void	linux_vdso_deinstall(const void *param);
84*3911ee2cSEd Maste static void	linux_set_syscall_retval(struct thread *td, int error);
85*3911ee2cSEd Maste static int	linux_fetch_syscall_args(struct thread *td);
86*3911ee2cSEd Maste static void	linux_exec_setregs(struct thread *td, struct image_params *imgp,
87*3911ee2cSEd Maste 		    u_long stack);
88*3911ee2cSEd Maste static int	linux_vsyscall(struct thread *td);
89*3911ee2cSEd Maste 
90*3911ee2cSEd Maste /* DTrace init */
91*3911ee2cSEd Maste LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
92*3911ee2cSEd Maste 
93*3911ee2cSEd Maste /* DTrace probes */
94*3911ee2cSEd Maste LIN_SDT_PROBE_DEFINE2(sysvec, linux_translate_traps, todo, "int", "int");
95*3911ee2cSEd Maste LIN_SDT_PROBE_DEFINE0(sysvec, linux_exec_setregs, todo);
96*3911ee2cSEd Maste LIN_SDT_PROBE_DEFINE0(sysvec, linux_elf_fixup, todo);
97*3911ee2cSEd Maste LIN_SDT_PROBE_DEFINE0(sysvec, linux_rt_sigreturn, todo);
98*3911ee2cSEd Maste LIN_SDT_PROBE_DEFINE0(sysvec, linux_rt_sendsig, todo);
99*3911ee2cSEd Maste LIN_SDT_PROBE_DEFINE0(sysvec, linux_vsyscall, todo);
100*3911ee2cSEd Maste LIN_SDT_PROBE_DEFINE0(sysvec, linux_vdso_install, todo);
101*3911ee2cSEd Maste LIN_SDT_PROBE_DEFINE0(sysvec, linux_vdso_deinstall, todo);
102*3911ee2cSEd Maste 
103*3911ee2cSEd Maste /* LINUXTODO: do we have traps to translate? */
104*3911ee2cSEd Maste static int
105*3911ee2cSEd Maste linux_translate_traps(int signal, int trap_code)
106*3911ee2cSEd Maste {
107*3911ee2cSEd Maste 
108*3911ee2cSEd Maste 	LIN_SDT_PROBE2(sysvec, linux_translate_traps, todo, signal, trap_code);
109*3911ee2cSEd Maste 	return (signal);
110*3911ee2cSEd Maste }
111*3911ee2cSEd Maste 
112*3911ee2cSEd Maste LINUX_VDSO_SYM_CHAR(linux_platform);
113*3911ee2cSEd Maste 
114*3911ee2cSEd Maste static int
115*3911ee2cSEd Maste linux_fetch_syscall_args(struct thread *td)
116*3911ee2cSEd Maste {
117*3911ee2cSEd Maste 	struct proc *p;
118*3911ee2cSEd Maste 	struct syscall_args *sa;
119*3911ee2cSEd Maste 	register_t *ap;
120*3911ee2cSEd Maste 
121*3911ee2cSEd Maste 	p = td->td_proc;
122*3911ee2cSEd Maste 	ap = td->td_frame->tf_x;
123*3911ee2cSEd Maste 	sa = &td->td_sa;
124*3911ee2cSEd Maste 
125*3911ee2cSEd Maste 	sa->code = td->td_frame->tf_x[8];
126*3911ee2cSEd Maste 	/* LINUXTODO: generic syscall? */
127*3911ee2cSEd Maste 	if (p->p_sysent->sv_mask)
128*3911ee2cSEd Maste 		sa->code &= p->p_sysent->sv_mask;
129*3911ee2cSEd Maste 	if (sa->code >= p->p_sysent->sv_size)
130*3911ee2cSEd Maste 		sa->callp = &p->p_sysent->sv_table[0];
131*3911ee2cSEd Maste 	else
132*3911ee2cSEd Maste 		sa->callp = &p->p_sysent->sv_table[sa->code];
133*3911ee2cSEd Maste 
134*3911ee2cSEd Maste 	sa->narg = sa->callp->sy_narg;
135*3911ee2cSEd Maste 	if (sa->narg > 8)
136*3911ee2cSEd Maste 		panic("ARM64TODO: Could we have more than 8 args?");
137*3911ee2cSEd Maste 	memcpy(sa->args, ap, 8 * sizeof(register_t));
138*3911ee2cSEd Maste 
139*3911ee2cSEd Maste 	td->td_retval[0] = 0;
140*3911ee2cSEd Maste 	return (0);
141*3911ee2cSEd Maste }
142*3911ee2cSEd Maste 
143*3911ee2cSEd Maste static void
144*3911ee2cSEd Maste linux_set_syscall_retval(struct thread *td, int error)
145*3911ee2cSEd Maste {
146*3911ee2cSEd Maste 	struct trapframe *frame;
147*3911ee2cSEd Maste 
148*3911ee2cSEd Maste 	frame = td->td_frame;
149*3911ee2cSEd Maste 
150*3911ee2cSEd Maste 	switch (error) {
151*3911ee2cSEd Maste 	case 0:
152*3911ee2cSEd Maste 		frame->tf_x[0] = td->td_retval[0];
153*3911ee2cSEd Maste 		frame->tf_x[1] = td->td_retval[1];
154*3911ee2cSEd Maste 		break;
155*3911ee2cSEd Maste 	case ERESTART:
156*3911ee2cSEd Maste 		/* LINUXTODO: verify */
157*3911ee2cSEd Maste 		frame->tf_elr -= 4;
158*3911ee2cSEd Maste 		break;
159*3911ee2cSEd Maste 	case EJUSTRETURN:
160*3911ee2cSEd Maste 		break;
161*3911ee2cSEd Maste 	default:
162*3911ee2cSEd Maste 		frame->tf_x[0] = error;
163*3911ee2cSEd Maste 		break;
164*3911ee2cSEd Maste 	}
165*3911ee2cSEd Maste }
166*3911ee2cSEd Maste 
167*3911ee2cSEd Maste static int
168*3911ee2cSEd Maste linux_elf_fixup(register_t **stack_base, struct image_params *imgp)
169*3911ee2cSEd Maste {
170*3911ee2cSEd Maste 	Elf_Auxargs *args;
171*3911ee2cSEd Maste 	Elf_Auxinfo *argarray, *pos;
172*3911ee2cSEd Maste 	Elf_Addr *auxbase, *base;
173*3911ee2cSEd Maste 	struct ps_strings *arginfo;
174*3911ee2cSEd Maste 	struct proc *p;
175*3911ee2cSEd Maste 	int error, issetugid;
176*3911ee2cSEd Maste 
177*3911ee2cSEd Maste 	LIN_SDT_PROBE0(sysvec, linux_elf_fixup, todo);
178*3911ee2cSEd Maste 	p = imgp->proc;
179*3911ee2cSEd Maste 	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
180*3911ee2cSEd Maste 
181*3911ee2cSEd Maste 	KASSERT(curthread->td_proc == imgp->proc,
182*3911ee2cSEd Maste 	    ("unsafe linux_elf_fixup(), should be curproc"));
183*3911ee2cSEd Maste 	base = (Elf64_Addr *)*stack_base;
184*3911ee2cSEd Maste 	args = (Elf64_Auxargs *)imgp->auxargs;
185*3911ee2cSEd Maste 	/* Auxargs after argc, and NULL-terminated argv and envv lists. */
186*3911ee2cSEd Maste 	auxbase = base + 1 + imgp->args->argc + 1 + imgp->args->envc + 1;
187*3911ee2cSEd Maste 	argarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP,
188*3911ee2cSEd Maste 	    M_WAITOK | M_ZERO);
189*3911ee2cSEd Maste 
190*3911ee2cSEd Maste 	issetugid = p->p_flag & P_SUGID ? 1 : 0;
191*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR,
192*3911ee2cSEd Maste 	    imgp->proc->p_sysent->sv_shared_page_base);
193*3911ee2cSEd Maste #if 0	/* LINUXTODO: implement arm64 LINUX_AT_HWCAP */
194*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
195*3911ee2cSEd Maste #endif
196*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz);
197*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
198*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
199*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
200*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
201*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
202*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
203*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
204*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
205*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
206*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
207*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
208*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid);
209*3911ee2cSEd Maste #if 0	/* LINUXTODO: implement arm64 LINUX_AT_PLATFORM */
210*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform));
211*3911ee2cSEd Maste #endif
212*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, LINUX_AT_RANDOM, imgp->canary);
213*3911ee2cSEd Maste 	if (imgp->execpathp != 0)
214*3911ee2cSEd Maste 		AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, imgp->execpathp);
215*3911ee2cSEd Maste 	if (args->execfd != -1)
216*3911ee2cSEd Maste 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
217*3911ee2cSEd Maste 	AUXARGS_ENTRY(pos, AT_NULL, 0);
218*3911ee2cSEd Maste 	free(imgp->auxargs, M_TEMP);
219*3911ee2cSEd Maste 	imgp->auxargs = NULL;
220*3911ee2cSEd Maste 	KASSERT(pos - argarray <= LINUX_AT_COUNT, ("Too many auxargs"));
221*3911ee2cSEd Maste 
222*3911ee2cSEd Maste 	error = copyout(argarray, auxbase, sizeof(*argarray) * LINUX_AT_COUNT);
223*3911ee2cSEd Maste 	free(argarray, M_TEMP);
224*3911ee2cSEd Maste 	if (error != 0)
225*3911ee2cSEd Maste 		return (error);
226*3911ee2cSEd Maste 
227*3911ee2cSEd Maste 	return (0);
228*3911ee2cSEd Maste }
229*3911ee2cSEd Maste 
230*3911ee2cSEd Maste /*
231*3911ee2cSEd Maste  * Copy strings out to the new process address space, constructing new arg
232*3911ee2cSEd Maste  * and env vector tables. Return a pointer to the base so that it can be used
233*3911ee2cSEd Maste  * as the initial stack pointer.
234*3911ee2cSEd Maste  * LINUXTODO: deduplicate against other linuxulator archs
235*3911ee2cSEd Maste  */
236*3911ee2cSEd Maste static register_t *
237*3911ee2cSEd Maste linux_copyout_strings(struct image_params *imgp)
238*3911ee2cSEd Maste {
239*3911ee2cSEd Maste 	char **vectp;
240*3911ee2cSEd Maste 	char *stringp, *destp;
241*3911ee2cSEd Maste 	register_t *stack_base;
242*3911ee2cSEd Maste 	struct ps_strings *arginfo;
243*3911ee2cSEd Maste 	char canary[LINUX_AT_RANDOM_LEN];
244*3911ee2cSEd Maste 	size_t execpath_len;
245*3911ee2cSEd Maste 	struct proc *p;
246*3911ee2cSEd Maste 	int argc, envc;
247*3911ee2cSEd Maste 
248*3911ee2cSEd Maste 	/* Calculate string base and vector table pointers. */
249*3911ee2cSEd Maste 	if (imgp->execpath != NULL && imgp->auxargs != NULL)
250*3911ee2cSEd Maste 		execpath_len = strlen(imgp->execpath) + 1;
251*3911ee2cSEd Maste 	else
252*3911ee2cSEd Maste 		execpath_len = 0;
253*3911ee2cSEd Maste 
254*3911ee2cSEd Maste 	p = imgp->proc;
255*3911ee2cSEd Maste 	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
256*3911ee2cSEd Maste 	destp = (caddr_t)arginfo - SPARE_USRSPACE -
257*3911ee2cSEd Maste 	    roundup(sizeof(canary), sizeof(char *)) -
258*3911ee2cSEd Maste 	    roundup(execpath_len, sizeof(char *)) -
259*3911ee2cSEd Maste 	    roundup(ARG_MAX - imgp->args->stringspace, sizeof(char *));
260*3911ee2cSEd Maste 
261*3911ee2cSEd Maste 	if (execpath_len != 0) {
262*3911ee2cSEd Maste 		imgp->execpathp = (uintptr_t)arginfo - execpath_len;
263*3911ee2cSEd Maste 		copyout(imgp->execpath, (void *)imgp->execpathp, execpath_len);
264*3911ee2cSEd Maste 	}
265*3911ee2cSEd Maste 
266*3911ee2cSEd Maste 	/* Prepare the canary for SSP. */
267*3911ee2cSEd Maste 	arc4rand(canary, sizeof(canary), 0);
268*3911ee2cSEd Maste 	imgp->canary = (uintptr_t)arginfo -
269*3911ee2cSEd Maste 	    roundup(execpath_len, sizeof(char *)) -
270*3911ee2cSEd Maste 	    roundup(sizeof(canary), sizeof(char *));
271*3911ee2cSEd Maste 	copyout(canary, (void *)imgp->canary, sizeof(canary));
272*3911ee2cSEd Maste 
273*3911ee2cSEd Maste 	vectp = (char **)destp;
274*3911ee2cSEd Maste 	if (imgp->auxargs) {
275*3911ee2cSEd Maste 		/*
276*3911ee2cSEd Maste 		 * Allocate room on the stack for the ELF auxargs
277*3911ee2cSEd Maste 		 * array.  It has up to LINUX_AT_COUNT entries.
278*3911ee2cSEd Maste 		 */
279*3911ee2cSEd Maste 		vectp -= howmany(LINUX_AT_COUNT * sizeof(Elf64_Auxinfo),
280*3911ee2cSEd Maste 		    sizeof(*vectp));
281*3911ee2cSEd Maste 	}
282*3911ee2cSEd Maste 
283*3911ee2cSEd Maste 	/*
284*3911ee2cSEd Maste 	 * Allocate room for argc and the argv[] and env vectors including the
285*3911ee2cSEd Maste 	 * terminating NULL pointers.
286*3911ee2cSEd Maste 	 */
287*3911ee2cSEd Maste 	vectp -= 1 + imgp->args->argc + 1 + imgp->args->envc + 1;
288*3911ee2cSEd Maste 	vectp = (char **)STACKALIGN(vectp);
289*3911ee2cSEd Maste 
290*3911ee2cSEd Maste 	/* vectp also becomes our initial stack base. */
291*3911ee2cSEd Maste 	stack_base = (register_t *)vectp;
292*3911ee2cSEd Maste 
293*3911ee2cSEd Maste 	stringp = imgp->args->begin_argv;
294*3911ee2cSEd Maste 	argc = imgp->args->argc;
295*3911ee2cSEd Maste 	envc = imgp->args->envc;
296*3911ee2cSEd Maste 
297*3911ee2cSEd Maste 	/* Copy out strings - arguments and environment. */
298*3911ee2cSEd Maste 	copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
299*3911ee2cSEd Maste 
300*3911ee2cSEd Maste 	/* Fill in "ps_strings" struct for ps, w, etc. */
301*3911ee2cSEd Maste 	suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp);
302*3911ee2cSEd Maste 	suword(&arginfo->ps_nargvstr, argc);
303*3911ee2cSEd Maste 
304*3911ee2cSEd Maste 	suword(vectp++, argc);
305*3911ee2cSEd Maste 	/* Fill in argument portion of vector table. */
306*3911ee2cSEd Maste 	for (; argc > 0; --argc) {
307*3911ee2cSEd Maste 		suword(vectp++, (long)(intptr_t)destp);
308*3911ee2cSEd Maste 		while (*stringp++ != 0)
309*3911ee2cSEd Maste 			destp++;
310*3911ee2cSEd Maste 		destp++;
311*3911ee2cSEd Maste 	}
312*3911ee2cSEd Maste 
313*3911ee2cSEd Maste 	/* A null vector table pointer separates the argp's from the envp's. */
314*3911ee2cSEd Maste 	suword(vectp++, 0);
315*3911ee2cSEd Maste 
316*3911ee2cSEd Maste 	suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
317*3911ee2cSEd Maste 	suword(&arginfo->ps_nenvstr, envc);
318*3911ee2cSEd Maste 
319*3911ee2cSEd Maste 	/* Fill in environment portion of vector table. */
320*3911ee2cSEd Maste 	for (; envc > 0; --envc) {
321*3911ee2cSEd Maste 		suword(vectp++, (long)(intptr_t)destp);
322*3911ee2cSEd Maste 		while (*stringp++ != 0)
323*3911ee2cSEd Maste 			destp++;
324*3911ee2cSEd Maste 		destp++;
325*3911ee2cSEd Maste 	}
326*3911ee2cSEd Maste 
327*3911ee2cSEd Maste 	/* The end of the vector table is a null pointer. */
328*3911ee2cSEd Maste 	suword(vectp, 0);
329*3911ee2cSEd Maste 	return (stack_base);
330*3911ee2cSEd Maste }
331*3911ee2cSEd Maste 
332*3911ee2cSEd Maste /*
333*3911ee2cSEd Maste  * Reset registers to default values on exec.
334*3911ee2cSEd Maste  */
335*3911ee2cSEd Maste static void
336*3911ee2cSEd Maste linux_exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
337*3911ee2cSEd Maste {
338*3911ee2cSEd Maste 	struct trapframe *regs = td->td_frame;
339*3911ee2cSEd Maste 
340*3911ee2cSEd Maste 	/* LINUXTODO: validate */
341*3911ee2cSEd Maste 	LIN_SDT_PROBE0(sysvec, linux_exec_setregs, todo);
342*3911ee2cSEd Maste 
343*3911ee2cSEd Maste 	memset(regs, 0, sizeof(*regs));
344*3911ee2cSEd Maste 	/* glibc start.S registers function pointer in x0 with atexit. */
345*3911ee2cSEd Maste         regs->tf_sp = stack;
346*3911ee2cSEd Maste #if 0	/* LINUXTODO: See if this is used. */
347*3911ee2cSEd Maste 	regs->tf_lr = imgp->entry_addr;
348*3911ee2cSEd Maste #else
349*3911ee2cSEd Maste         regs->tf_lr = 0xffffffffffffffff;
350*3911ee2cSEd Maste #endif
351*3911ee2cSEd Maste         regs->tf_elr = imgp->entry_addr;
352*3911ee2cSEd Maste }
353*3911ee2cSEd Maste 
354*3911ee2cSEd Maste int
355*3911ee2cSEd Maste linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
356*3911ee2cSEd Maste {
357*3911ee2cSEd Maste 
358*3911ee2cSEd Maste 	/* LINUXTODO: implement */
359*3911ee2cSEd Maste 	LIN_SDT_PROBE0(sysvec, linux_rt_sigreturn, todo);
360*3911ee2cSEd Maste 	return (EDOOFUS);
361*3911ee2cSEd Maste }
362*3911ee2cSEd Maste 
363*3911ee2cSEd Maste static void
364*3911ee2cSEd Maste linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
365*3911ee2cSEd Maste {
366*3911ee2cSEd Maste 
367*3911ee2cSEd Maste 	/* LINUXTODO: implement */
368*3911ee2cSEd Maste 	LIN_SDT_PROBE0(sysvec, linux_rt_sendsig, todo);
369*3911ee2cSEd Maste }
370*3911ee2cSEd Maste 
371*3911ee2cSEd Maste static int
372*3911ee2cSEd Maste linux_vsyscall(struct thread *td)
373*3911ee2cSEd Maste {
374*3911ee2cSEd Maste 
375*3911ee2cSEd Maste 	/* LINUXTODO: implement */
376*3911ee2cSEd Maste 	LIN_SDT_PROBE0(sysvec, linux_vsyscall, todo);
377*3911ee2cSEd Maste 	return (EDOOFUS);
378*3911ee2cSEd Maste }
379*3911ee2cSEd Maste 
380*3911ee2cSEd Maste struct sysentvec elf_linux_sysvec = {
381*3911ee2cSEd Maste 	.sv_size	= LINUX_SYS_MAXSYSCALL,
382*3911ee2cSEd Maste 	.sv_table	= linux_sysent,
383*3911ee2cSEd Maste 	.sv_mask	= 0,
384*3911ee2cSEd Maste 	.sv_errsize	= ELAST + 1,
385*3911ee2cSEd Maste 	.sv_errtbl	= linux_errtbl,
386*3911ee2cSEd Maste 	.sv_transtrap	= linux_translate_traps,
387*3911ee2cSEd Maste 	.sv_fixup	= linux_elf_fixup,
388*3911ee2cSEd Maste 	.sv_sendsig	= linux_rt_sendsig,
389*3911ee2cSEd Maste 	.sv_sigcode	= &_binary_linux_locore_o_start,
390*3911ee2cSEd Maste 	.sv_szsigcode	= &linux_szsigcode,
391*3911ee2cSEd Maste 	.sv_name	= "Linux ELF64",
392*3911ee2cSEd Maste 	.sv_coredump	= elf64_coredump,
393*3911ee2cSEd Maste 	.sv_imgact_try	= linux_exec_imgact_try,
394*3911ee2cSEd Maste 	.sv_minsigstksz	= LINUX_MINSIGSTKSZ,
395*3911ee2cSEd Maste 	.sv_pagesize	= PAGE_SIZE,
396*3911ee2cSEd Maste 	.sv_minuser	= VM_MIN_ADDRESS,
397*3911ee2cSEd Maste 	.sv_maxuser	= VM_MAXUSER_ADDRESS,
398*3911ee2cSEd Maste 	.sv_usrstack	= USRSTACK,
399*3911ee2cSEd Maste 	.sv_psstrings	= PS_STRINGS, /* XXX */
400*3911ee2cSEd Maste 	.sv_stackprot	= VM_PROT_ALL, /* XXX */
401*3911ee2cSEd Maste 	.sv_copyout_strings = linux_copyout_strings,
402*3911ee2cSEd Maste 	.sv_setregs	= linux_exec_setregs,
403*3911ee2cSEd Maste 	.sv_fixlimit	= NULL,
404*3911ee2cSEd Maste 	.sv_maxssiz	= NULL,
405*3911ee2cSEd Maste 	.sv_flags	= SV_ABI_LINUX | SV_LP64 | SV_SHP,
406*3911ee2cSEd Maste 	.sv_set_syscall_retval = linux_set_syscall_retval,
407*3911ee2cSEd Maste 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
408*3911ee2cSEd Maste 	.sv_syscallnames = NULL,
409*3911ee2cSEd Maste 	.sv_shared_page_base = SHAREDPAGE,
410*3911ee2cSEd Maste 	.sv_shared_page_len = PAGE_SIZE,
411*3911ee2cSEd Maste 	.sv_schedtail	= linux_schedtail,
412*3911ee2cSEd Maste 	.sv_thread_detach = linux_thread_detach,
413*3911ee2cSEd Maste 	.sv_trap	= linux_vsyscall,
414*3911ee2cSEd Maste };
415*3911ee2cSEd Maste 
416*3911ee2cSEd Maste static void
417*3911ee2cSEd Maste linux_vdso_install(const void *param)
418*3911ee2cSEd Maste {
419*3911ee2cSEd Maste 
420*3911ee2cSEd Maste 	linux_szsigcode = (&_binary_linux_locore_o_end -
421*3911ee2cSEd Maste 	    &_binary_linux_locore_o_start);
422*3911ee2cSEd Maste 
423*3911ee2cSEd Maste 	if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len)
424*3911ee2cSEd Maste 		panic("invalid Linux VDSO size\n");
425*3911ee2cSEd Maste 
426*3911ee2cSEd Maste 	__elfN(linux_vdso_fixup)(&elf_linux_sysvec);
427*3911ee2cSEd Maste 
428*3911ee2cSEd Maste 	linux_shared_page_obj = __elfN(linux_shared_page_init)
429*3911ee2cSEd Maste 	    (&linux_shared_page_mapping);
430*3911ee2cSEd Maste 
431*3911ee2cSEd Maste 	__elfN(linux_vdso_reloc)(&elf_linux_sysvec);
432*3911ee2cSEd Maste 
433*3911ee2cSEd Maste 	memcpy(linux_shared_page_mapping, elf_linux_sysvec.sv_sigcode,
434*3911ee2cSEd Maste 	    linux_szsigcode);
435*3911ee2cSEd Maste 	elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj;
436*3911ee2cSEd Maste 
437*3911ee2cSEd Maste 	printf("LINUXTODO: %s: fix linux_kplatform\n", __func__);
438*3911ee2cSEd Maste #if 0
439*3911ee2cSEd Maste 	linux_kplatform = linux_shared_page_mapping +
440*3911ee2cSEd Maste 	    (linux_platform - (caddr_t)elf_linux_sysvec.sv_shared_page_base);
441*3911ee2cSEd Maste #else
442*3911ee2cSEd Maste 	linux_kplatform = "arm64";
443*3911ee2cSEd Maste #endif
444*3911ee2cSEd Maste }
445*3911ee2cSEd Maste SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY,
446*3911ee2cSEd Maste     linux_vdso_install, NULL);
447*3911ee2cSEd Maste 
448*3911ee2cSEd Maste static void
449*3911ee2cSEd Maste linux_vdso_deinstall(const void *param)
450*3911ee2cSEd Maste {
451*3911ee2cSEd Maste 
452*3911ee2cSEd Maste 	LIN_SDT_PROBE0(sysvec, linux_vdso_deinstall, todo);
453*3911ee2cSEd Maste 	__elfN(linux_shared_page_fini)(linux_shared_page_obj);
454*3911ee2cSEd Maste }
455*3911ee2cSEd Maste SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST,
456*3911ee2cSEd Maste     linux_vdso_deinstall, NULL);
457*3911ee2cSEd Maste 
458*3911ee2cSEd Maste static char GNU_ABI_VENDOR[] = "GNU";
459*3911ee2cSEd Maste static int GNU_ABI_LINUX = 0;
460*3911ee2cSEd Maste 
461*3911ee2cSEd Maste /* LINUXTODO: deduplicate */
462*3911ee2cSEd Maste static bool
463*3911ee2cSEd Maste linux_trans_osrel(const Elf_Note *note, int32_t *osrel)
464*3911ee2cSEd Maste {
465*3911ee2cSEd Maste 	const Elf32_Word *desc;
466*3911ee2cSEd Maste 	uintptr_t p;
467*3911ee2cSEd Maste 
468*3911ee2cSEd Maste 	p = (uintptr_t)(note + 1);
469*3911ee2cSEd Maste 	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
470*3911ee2cSEd Maste 
471*3911ee2cSEd Maste 	desc = (const Elf32_Word *)p;
472*3911ee2cSEd Maste 	if (desc[0] != GNU_ABI_LINUX)
473*3911ee2cSEd Maste 		return (false);
474*3911ee2cSEd Maste 
475*3911ee2cSEd Maste 	*osrel = LINUX_KERNVER(desc[1], desc[2], desc[3]);
476*3911ee2cSEd Maste 	return (true);
477*3911ee2cSEd Maste }
478*3911ee2cSEd Maste 
479*3911ee2cSEd Maste static Elf_Brandnote linux64_brandnote = {
480*3911ee2cSEd Maste 	.hdr.n_namesz	= sizeof(GNU_ABI_VENDOR),
481*3911ee2cSEd Maste 	.hdr.n_descsz	= 16,
482*3911ee2cSEd Maste 	.hdr.n_type	= 1,
483*3911ee2cSEd Maste 	.vendor		= GNU_ABI_VENDOR,
484*3911ee2cSEd Maste 	.flags		= BN_TRANSLATE_OSREL,
485*3911ee2cSEd Maste 	.trans_osrel	= linux_trans_osrel
486*3911ee2cSEd Maste };
487*3911ee2cSEd Maste 
488*3911ee2cSEd Maste static Elf64_Brandinfo linux_glibc2brand = {
489*3911ee2cSEd Maste 	.brand		= ELFOSABI_LINUX,
490*3911ee2cSEd Maste 	.machine	= EM_AARCH64,
491*3911ee2cSEd Maste 	.compat_3_brand	= "Linux",
492*3911ee2cSEd Maste 	.emul_path	= "/compat/linux",
493*3911ee2cSEd Maste 	.interp_path	= "/lib64/ld-linux-x86-64.so.2",
494*3911ee2cSEd Maste 	.sysvec		= &elf_linux_sysvec,
495*3911ee2cSEd Maste 	.interp_newpath	= NULL,
496*3911ee2cSEd Maste 	.brand_note	= &linux64_brandnote,
497*3911ee2cSEd Maste 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
498*3911ee2cSEd Maste };
499*3911ee2cSEd Maste 
500*3911ee2cSEd Maste Elf64_Brandinfo *linux_brandlist[] = {
501*3911ee2cSEd Maste 	&linux_glibc2brand,
502*3911ee2cSEd Maste 	NULL
503*3911ee2cSEd Maste };
504*3911ee2cSEd Maste 
505*3911ee2cSEd Maste static int
506*3911ee2cSEd Maste linux64_elf_modevent(module_t mod, int type, void *data)
507*3911ee2cSEd Maste {
508*3911ee2cSEd Maste 	Elf64_Brandinfo **brandinfo;
509*3911ee2cSEd Maste 	struct linux_ioctl_handler**lihp;
510*3911ee2cSEd Maste 	int error;
511*3911ee2cSEd Maste 
512*3911ee2cSEd Maste 	error = 0;
513*3911ee2cSEd Maste 	switch(type) {
514*3911ee2cSEd Maste 	case MOD_LOAD:
515*3911ee2cSEd Maste 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
516*3911ee2cSEd Maste 		    ++brandinfo)
517*3911ee2cSEd Maste 			if (elf64_insert_brand_entry(*brandinfo) < 0)
518*3911ee2cSEd Maste 				error = EINVAL;
519*3911ee2cSEd Maste 		if (error == 0) {
520*3911ee2cSEd Maste 			SET_FOREACH(lihp, linux_ioctl_handler_set)
521*3911ee2cSEd Maste 				linux_ioctl_register_handler(*lihp);
522*3911ee2cSEd Maste 			LIST_INIT(&futex_list);
523*3911ee2cSEd Maste 			mtx_init(&futex_mtx, "ftllk64", NULL, MTX_DEF);
524*3911ee2cSEd Maste 			stclohz = (stathz ? stathz : hz);
525*3911ee2cSEd Maste 			if (bootverbose)
526*3911ee2cSEd Maste 				printf("Linux arm64 ELF exec handler installed\n");
527*3911ee2cSEd Maste 		}
528*3911ee2cSEd Maste 		break;
529*3911ee2cSEd Maste 	case MOD_UNLOAD:
530*3911ee2cSEd Maste 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
531*3911ee2cSEd Maste 		    ++brandinfo)
532*3911ee2cSEd Maste 			if (elf64_brand_inuse(*brandinfo))
533*3911ee2cSEd Maste 				error = EBUSY;
534*3911ee2cSEd Maste 		if (error == 0) {
535*3911ee2cSEd Maste 			for (brandinfo = &linux_brandlist[0];
536*3911ee2cSEd Maste 			    *brandinfo != NULL; ++brandinfo)
537*3911ee2cSEd Maste 				if (elf64_remove_brand_entry(*brandinfo) < 0)
538*3911ee2cSEd Maste 					error = EINVAL;
539*3911ee2cSEd Maste 		}
540*3911ee2cSEd Maste 		if (error == 0) {
541*3911ee2cSEd Maste 			SET_FOREACH(lihp, linux_ioctl_handler_set)
542*3911ee2cSEd Maste 				linux_ioctl_unregister_handler(*lihp);
543*3911ee2cSEd Maste 			mtx_destroy(&futex_mtx);
544*3911ee2cSEd Maste 			if (bootverbose)
545*3911ee2cSEd Maste 				printf("Linux ELF exec handler removed\n");
546*3911ee2cSEd Maste 		} else
547*3911ee2cSEd Maste 			printf("Could not deinstall ELF interpreter entry\n");
548*3911ee2cSEd Maste 		break;
549*3911ee2cSEd Maste 	default:
550*3911ee2cSEd Maste 		return (EOPNOTSUPP);
551*3911ee2cSEd Maste 	}
552*3911ee2cSEd Maste 	return (error);
553*3911ee2cSEd Maste }
554*3911ee2cSEd Maste 
555*3911ee2cSEd Maste static moduledata_t linux64_elf_mod = {
556*3911ee2cSEd Maste 	"linux64elf",
557*3911ee2cSEd Maste 	linux64_elf_modevent,
558*3911ee2cSEd Maste 	0
559*3911ee2cSEd Maste };
560*3911ee2cSEd Maste 
561*3911ee2cSEd Maste DECLARE_MODULE_TIED(linux64elf, linux64_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
562*3911ee2cSEd Maste MODULE_DEPEND(linux64elf, linux_common, 1, 1, 1);
563*3911ee2cSEd Maste FEATURE(linux64, "AArch64 Linux 64bit support");
564