xref: /freebsd/sys/amd64/linux32/linux32_sysvec.c (revision fcdffc03f80577070fad20ff11fa3c9c5c09328e)
1ea0fabbcSTim J. Robbins /*-
2ea0fabbcSTim J. Robbins  * Copyright (c) 2004 Tim J. Robbins
3ea0fabbcSTim J. Robbins  * Copyright (c) 2003 Peter Wemm
4ea0fabbcSTim J. Robbins  * Copyright (c) 2002 Doug Rabson
5ea0fabbcSTim J. Robbins  * Copyright (c) 1998-1999 Andrew Gallatin
69a14aa01SUlrich Spörlein  * Copyright (c) 1994-1996 Søren Schmidt
7ea0fabbcSTim J. Robbins  * All rights reserved.
8ea0fabbcSTim J. Robbins  *
9ea0fabbcSTim J. Robbins  * Redistribution and use in source and binary forms, with or without
10ea0fabbcSTim J. Robbins  * modification, are permitted provided that the following conditions
11ea0fabbcSTim J. Robbins  * are met:
12ea0fabbcSTim J. Robbins  * 1. Redistributions of source code must retain the above copyright
13ea0fabbcSTim J. Robbins  *    notice, this list of conditions and the following disclaimer
14ea0fabbcSTim J. Robbins  *    in this position and unchanged.
15ea0fabbcSTim J. Robbins  * 2. Redistributions in binary form must reproduce the above copyright
16ea0fabbcSTim J. Robbins  *    notice, this list of conditions and the following disclaimer in the
17ea0fabbcSTim J. Robbins  *    documentation and/or other materials provided with the distribution.
18ea0fabbcSTim J. Robbins  * 3. The name of the author may not be used to endorse or promote products
19ea0fabbcSTim J. Robbins  *    derived from this software without specific prior written permission
20ea0fabbcSTim J. Robbins  *
21ea0fabbcSTim J. Robbins  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22ea0fabbcSTim J. Robbins  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23ea0fabbcSTim J. Robbins  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24ea0fabbcSTim J. Robbins  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25ea0fabbcSTim J. Robbins  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26ea0fabbcSTim J. Robbins  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27ea0fabbcSTim J. Robbins  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28ea0fabbcSTim J. Robbins  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29ea0fabbcSTim J. Robbins  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30ea0fabbcSTim J. Robbins  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31ea0fabbcSTim J. Robbins  */
32ea0fabbcSTim J. Robbins 
33ea0fabbcSTim J. Robbins #include <sys/cdefs.h>
34ea0fabbcSTim J. Robbins __FBSDID("$FreeBSD$");
35aefce619SRuslan Ermilov #include "opt_compat.h"
36ea0fabbcSTim J. Robbins 
37841c0c7eSNathan Whitehorn #ifndef COMPAT_FREEBSD32
38841c0c7eSNathan Whitehorn #error "Unable to compile Linux-emulator due to missing COMPAT_FREEBSD32 option!"
39ea0fabbcSTim J. Robbins #endif
40ea0fabbcSTim J. Robbins 
41ea0fabbcSTim J. Robbins #define	__ELF_WORD_SIZE	32
42ea0fabbcSTim J. Robbins 
43ea0fabbcSTim J. Robbins #include <sys/param.h>
44ea0fabbcSTim J. Robbins #include <sys/systm.h>
45ea0fabbcSTim J. Robbins #include <sys/exec.h>
4648b05c3fSKonstantin Belousov #include <sys/fcntl.h>
47ea0fabbcSTim J. Robbins #include <sys/imgact.h>
48ea0fabbcSTim J. Robbins #include <sys/imgact_elf.h>
49ea0fabbcSTim J. Robbins #include <sys/kernel.h>
50ea0fabbcSTim J. Robbins #include <sys/lock.h>
51ea0fabbcSTim J. Robbins #include <sys/malloc.h>
52ea0fabbcSTim J. Robbins #include <sys/module.h>
53ea0fabbcSTim J. Robbins #include <sys/mutex.h>
54ea0fabbcSTim J. Robbins #include <sys/proc.h>
556004362eSDavid Schultz #include <sys/resourcevar.h>
56ea0fabbcSTim J. Robbins #include <sys/signalvar.h>
57ea0fabbcSTim J. Robbins #include <sys/sysctl.h>
58ea0fabbcSTim J. Robbins #include <sys/syscallsubr.h>
59ea0fabbcSTim J. Robbins #include <sys/sysent.h>
60ea0fabbcSTim J. Robbins #include <sys/sysproto.h>
61ea0fabbcSTim J. Robbins #include <sys/vnode.h>
627c09e6c0SAlexander Leidinger #include <sys/eventhandler.h>
63ea0fabbcSTim J. Robbins 
64ea0fabbcSTim J. Robbins #include <vm/vm.h>
65ea0fabbcSTim J. Robbins #include <vm/pmap.h>
66ea0fabbcSTim J. Robbins #include <vm/vm_extern.h>
67ea0fabbcSTim J. Robbins #include <vm/vm_map.h>
68ea0fabbcSTim J. Robbins #include <vm/vm_object.h>
69ea0fabbcSTim J. Robbins #include <vm/vm_page.h>
70ea0fabbcSTim J. Robbins #include <vm/vm_param.h>
71ea0fabbcSTim J. Robbins 
72ea0fabbcSTim J. Robbins #include <machine/cpu.h>
73ea0fabbcSTim J. Robbins #include <machine/md_var.h>
746004362eSDavid Schultz #include <machine/pcb.h>
75ea0fabbcSTim J. Robbins #include <machine/specialreg.h>
76ea0fabbcSTim J. Robbins 
77ea0fabbcSTim J. Robbins #include <amd64/linux32/linux.h>
78ea0fabbcSTim J. Robbins #include <amd64/linux32/linux32_proto.h>
797c09e6c0SAlexander Leidinger #include <compat/linux/linux_emul.h>
80fde63162SDmitry Chagin #include <compat/linux/linux_futex.h>
81d825ce0aSJohn Baldwin #include <compat/linux/linux_ioctl.h>
82ea0fabbcSTim J. Robbins #include <compat/linux/linux_mib.h>
834d7c2e8aSDmitry Chagin #include <compat/linux/linux_misc.h>
84ea0fabbcSTim J. Robbins #include <compat/linux/linux_signal.h>
85ea0fabbcSTim J. Robbins #include <compat/linux/linux_util.h>
86bdc37934SDmitry Chagin #include <compat/linux/linux_vdso.h>
87ea0fabbcSTim J. Robbins 
88ea0fabbcSTim J. Robbins MODULE_VERSION(linux, 1);
89ea0fabbcSTim J. Robbins 
90ea0fabbcSTim J. Robbins #define	AUXARGS_ENTRY_32(pos, id, val)	\
91ea0fabbcSTim J. Robbins 	do {				\
92ea0fabbcSTim J. Robbins 		suword32(pos++, id);	\
93ea0fabbcSTim J. Robbins 		suword32(pos++, val);	\
94ea0fabbcSTim J. Robbins 	} while (0)
95ea0fabbcSTim J. Robbins 
96ea0fabbcSTim J. Robbins #if BYTE_ORDER == LITTLE_ENDIAN
97ea0fabbcSTim J. Robbins #define SHELLMAGIC      0x2123 /* #! */
98ea0fabbcSTim J. Robbins #else
99ea0fabbcSTim J. Robbins #define SHELLMAGIC      0x2321
100ea0fabbcSTim J. Robbins #endif
101ea0fabbcSTim J. Robbins 
102ea0fabbcSTim J. Robbins /*
103ea0fabbcSTim J. Robbins  * Allow the sendsig functions to use the ldebug() facility
104ea0fabbcSTim J. Robbins  * even though they are not syscalls themselves. Map them
105ea0fabbcSTim J. Robbins  * to syscall 0. This is slightly less bogus than using
106ea0fabbcSTim J. Robbins  * ldebug(sigreturn).
107ea0fabbcSTim J. Robbins  */
108ea0fabbcSTim J. Robbins #define	LINUX_SYS_linux_rt_sendsig	0
109ea0fabbcSTim J. Robbins #define	LINUX_SYS_linux_sendsig		0
110ea0fabbcSTim J. Robbins 
1110020bdf1SDmitry Chagin const char *linux_kplatform;
112bdc37934SDmitry Chagin static int linux_szsigcode;
113bdc37934SDmitry Chagin static vm_object_t linux_shared_page_obj;
114bdc37934SDmitry Chagin static char *linux_shared_page_mapping;
115bdc37934SDmitry Chagin extern char _binary_linux32_locore_o_start;
116bdc37934SDmitry Chagin extern char _binary_linux32_locore_o_end;
117ea0fabbcSTim J. Robbins 
118ea0fabbcSTim J. Robbins extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
119ea0fabbcSTim J. Robbins 
120ea0fabbcSTim J. Robbins SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
121ea0fabbcSTim J. Robbins 
122ea0fabbcSTim J. Robbins static int	elf_linux_fixup(register_t **stack_base,
123ea0fabbcSTim J. Robbins 		    struct image_params *iparams);
124ea0fabbcSTim J. Robbins static register_t *linux_copyout_strings(struct image_params *imgp);
1259104847fSDavid Xu static void     linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
126a107d8aaSNathan Whitehorn static void	exec_linux_setregs(struct thread *td,
127a107d8aaSNathan Whitehorn 				   struct image_params *imgp, u_long stack);
12819059a13SJohn Baldwin static void	linux32_fixlimit(struct rlimit *rl, int which);
12989ffc202SBjoern A. Zeeb static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel);
130bdc37934SDmitry Chagin static void	linux_vdso_install(void *param);
131bdc37934SDmitry Chagin static void	linux_vdso_deinstall(void *param);
132ea0fabbcSTim J. Robbins 
133ea0fabbcSTim J. Robbins /*
134ea0fabbcSTim J. Robbins  * Linux syscalls return negative errno's, we do positive and map them
13550e422f0SAlexander Leidinger  * Reference:
13650e422f0SAlexander Leidinger  *   FreeBSD: src/sys/sys/errno.h
13750e422f0SAlexander Leidinger  *   Linux:   linux-2.6.17.8/include/asm-generic/errno-base.h
13850e422f0SAlexander Leidinger  *            linux-2.6.17.8/include/asm-generic/errno.h
139ea0fabbcSTim J. Robbins  */
140ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = {
141ea0fabbcSTim J. Robbins 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
142ea0fabbcSTim J. Robbins 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
143ea0fabbcSTim J. Robbins 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
144ea0fabbcSTim J. Robbins 	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
145ea0fabbcSTim J. Robbins 	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
146ea0fabbcSTim J. Robbins 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
147ea0fabbcSTim J. Robbins 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
148ea0fabbcSTim J. Robbins 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
14950e422f0SAlexander Leidinger 	  -6,  -6, -43, -42, -75,-125, -84, -95, -16, -74,
15050e422f0SAlexander Leidinger 	 -72, -67, -71
151ea0fabbcSTim J. Robbins };
152ea0fabbcSTim J. Robbins 
153ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
154ea0fabbcSTim J. Robbins 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
155ea0fabbcSTim J. Robbins 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
156ea0fabbcSTim J. Robbins 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
157ea0fabbcSTim J. Robbins 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
158ea0fabbcSTim J. Robbins 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
159ea0fabbcSTim J. Robbins 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
160ea0fabbcSTim J. Robbins 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
161ea0fabbcSTim J. Robbins 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
162ea0fabbcSTim J. Robbins };
163ea0fabbcSTim J. Robbins 
164ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
165ea0fabbcSTim J. Robbins 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
166ea0fabbcSTim J. Robbins 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
167ea0fabbcSTim J. Robbins 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
168ea0fabbcSTim J. Robbins 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
169ea0fabbcSTim J. Robbins 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
170ea0fabbcSTim J. Robbins 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
171ea0fabbcSTim J. Robbins 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
172ea0fabbcSTim J. Robbins 	SIGIO, SIGURG, SIGSYS
173ea0fabbcSTim J. Robbins };
174ea0fabbcSTim J. Robbins 
175ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN  255
176ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = {
177ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 0 */
178ea0fabbcSTim J. Robbins 	6,			/* 1  T_PRIVINFLT */
179ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 2 */
180ea0fabbcSTim J. Robbins 	3,			/* 3  T_BPTFLT */
181ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 4 */
182ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 5 */
183ea0fabbcSTim J. Robbins 	16,			/* 6  T_ARITHTRAP */
184ea0fabbcSTim J. Robbins 	254,			/* 7  T_ASTFLT */
185ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 8 */
186ea0fabbcSTim J. Robbins 	13,			/* 9  T_PROTFLT */
187ea0fabbcSTim J. Robbins 	1,			/* 10 T_TRCTRAP */
188ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 11 */
189ea0fabbcSTim J. Robbins 	14,			/* 12 T_PAGEFLT */
190ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 13 */
191ea0fabbcSTim J. Robbins 	17,			/* 14 T_ALIGNFLT */
192ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 15 */
193ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 16 */
194ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 17 */
195ea0fabbcSTim J. Robbins 	0,			/* 18 T_DIVIDE */
196ea0fabbcSTim J. Robbins 	2,			/* 19 T_NMI */
197ea0fabbcSTim J. Robbins 	4,			/* 20 T_OFLOW */
198ea0fabbcSTim J. Robbins 	5,			/* 21 T_BOUND */
199ea0fabbcSTim J. Robbins 	7,			/* 22 T_DNA */
200ea0fabbcSTim J. Robbins 	8,			/* 23 T_DOUBLEFLT */
201ea0fabbcSTim J. Robbins 	9,			/* 24 T_FPOPFLT */
202ea0fabbcSTim J. Robbins 	10,			/* 25 T_TSSFLT */
203ea0fabbcSTim J. Robbins 	11,			/* 26 T_SEGNPFLT */
204ea0fabbcSTim J. Robbins 	12,			/* 27 T_STKFLT */
205ea0fabbcSTim J. Robbins 	18,			/* 28 T_MCHK */
206ea0fabbcSTim J. Robbins 	19,			/* 29 T_XMMFLT */
207ea0fabbcSTim J. Robbins 	15			/* 30 T_RESERVED */
208ea0fabbcSTim J. Robbins };
209ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \
210ea0fabbcSTim J. Robbins     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
211ea0fabbcSTim J. Robbins      _bsd_to_linux_trapcode[(code)]: \
212ea0fabbcSTim J. Robbins      LINUX_T_UNKNOWN)
213ea0fabbcSTim J. Robbins 
214ea0fabbcSTim J. Robbins struct linux32_ps_strings {
215ea0fabbcSTim J. Robbins 	u_int32_t ps_argvstr;	/* first of 0 or more argument strings */
216f2c7668eSDavid Schultz 	u_int ps_nargvstr;	/* the number of argument strings */
217ea0fabbcSTim J. Robbins 	u_int32_t ps_envstr;	/* first of 0 or more environment strings */
218f2c7668eSDavid Schultz 	u_int ps_nenvstr;	/* the number of environment strings */
219ea0fabbcSTim J. Robbins };
220ea0fabbcSTim J. Robbins 
221bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_sigcode);
222bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_rt_sigcode);
223bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_vsyscall);
2240020bdf1SDmitry Chagin LINUX_VDSO_SYM_CHAR(linux_platform);
225bdc37934SDmitry Chagin 
226ea0fabbcSTim J. Robbins /*
227ea0fabbcSTim J. Robbins  * If FreeBSD & Linux have a difference of opinion about what a trap
228ea0fabbcSTim J. Robbins  * means, deal with it here.
229ea0fabbcSTim J. Robbins  *
230ea0fabbcSTim J. Robbins  * MPSAFE
231ea0fabbcSTim J. Robbins  */
232ea0fabbcSTim J. Robbins static int
233ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code)
234ea0fabbcSTim J. Robbins {
235ea0fabbcSTim J. Robbins 	if (signal != SIGBUS)
236ea0fabbcSTim J. Robbins 		return signal;
237ea0fabbcSTim J. Robbins 	switch (trap_code) {
238ea0fabbcSTim J. Robbins 	case T_PROTFLT:
239ea0fabbcSTim J. Robbins 	case T_TSSFLT:
240ea0fabbcSTim J. Robbins 	case T_DOUBLEFLT:
241ea0fabbcSTim J. Robbins 	case T_PAGEFLT:
242ea0fabbcSTim J. Robbins 		return SIGSEGV;
243ea0fabbcSTim J. Robbins 	default:
244ea0fabbcSTim J. Robbins 		return signal;
245ea0fabbcSTim J. Robbins 	}
246ea0fabbcSTim J. Robbins }
247ea0fabbcSTim J. Robbins 
248ea0fabbcSTim J. Robbins static int
249ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
250ea0fabbcSTim J. Robbins {
251ea0fabbcSTim J. Robbins 	Elf32_Auxargs *args;
252ea0fabbcSTim J. Robbins 	Elf32_Addr *base;
2530020bdf1SDmitry Chagin 	Elf32_Addr *pos;
2544d7c2e8aSDmitry Chagin 	struct linux32_ps_strings *arginfo;
2554d7c2e8aSDmitry Chagin 
2564d7c2e8aSDmitry Chagin 	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
257ea0fabbcSTim J. Robbins 
2586617724cSJeff Roberson 	KASSERT(curthread->td_proc == imgp->proc,
259ea0fabbcSTim J. Robbins 	    ("unsafe elf_linux_fixup(), should be curproc"));
260ea0fabbcSTim J. Robbins 	base = (Elf32_Addr *)*stack_base;
261ea0fabbcSTim J. Robbins 	args = (Elf32_Auxargs *)imgp->auxargs;
262610ecfe0SMaxim Sobolev 	pos = base + (imgp->args->argc + imgp->args->envc + 2);
263ea0fabbcSTim J. Robbins 
264bdc37934SDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO_EHDR,
265bdc37934SDmitry Chagin 	    imgp->proc->p_sysent->sv_shared_page_base);
266bdc37934SDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO, linux32_vsyscall);
2674d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);
2688d30f381SDmitry Chagin 
2698d30f381SDmitry Chagin 	/*
2708d30f381SDmitry Chagin 	 * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0,
2718d30f381SDmitry Chagin 	 * as it has appeared in the 2.4.0-rc7 first time.
2728d30f381SDmitry Chagin 	 * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK),
2738d30f381SDmitry Chagin 	 * glibc falls back to the hard-coded CLK_TCK value when aux entry
2748d30f381SDmitry Chagin 	 * is not present.
2758d30f381SDmitry Chagin 	 * Also see linux_times() implementation.
2768d30f381SDmitry Chagin 	 */
2778d30f381SDmitry Chagin 	if (linux_kernver(curthread) >= LINUX_KERNVER_2004000)
2781ca16454SDmitry Chagin 		AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz);
279ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr);
280ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent);
281ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum);
282ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz);
283ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags);
284ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry);
285ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_BASE, args->base);
2864d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0);
287ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
288ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
289ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
290ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
2910020bdf1SDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(linux_platform));
2924048f59cSDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_RANDOM, PTROUT(imgp->canary));
2934048f59cSDmitry Chagin 	if (imgp->execpathp != 0)
2944048f59cSDmitry Chagin 		AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp));
2954d7c2e8aSDmitry Chagin 	if (args->execfd != -1)
2964d7c2e8aSDmitry Chagin 		AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
297ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_NULL, 0);
298ea0fabbcSTim J. Robbins 
299ea0fabbcSTim J. Robbins 	free(imgp->auxargs, M_TEMP);
300ea0fabbcSTim J. Robbins 	imgp->auxargs = NULL;
301ea0fabbcSTim J. Robbins 
302ea0fabbcSTim J. Robbins 	base--;
303610ecfe0SMaxim Sobolev 	suword32(base, (uint32_t)imgp->args->argc);
304ea0fabbcSTim J. Robbins 	*stack_base = (register_t *)base;
305af682d48SDmitry Chagin 	return (0);
306ea0fabbcSTim J. Robbins }
307ea0fabbcSTim J. Robbins 
308ea0fabbcSTim J. Robbins static void
3099104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
310ea0fabbcSTim J. Robbins {
311ea0fabbcSTim J. Robbins 	struct thread *td = curthread;
312ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
313ea0fabbcSTim J. Robbins 	struct sigacts *psp;
314ea0fabbcSTim J. Robbins 	struct trapframe *regs;
315ea0fabbcSTim J. Robbins 	struct l_rt_sigframe *fp, frame;
316ea0fabbcSTim J. Robbins 	int oonstack;
3179104847fSDavid Xu 	int sig;
3189104847fSDavid Xu 	int code;
319ea0fabbcSTim J. Robbins 
3209104847fSDavid Xu 	sig = ksi->ksi_signo;
3219104847fSDavid Xu 	code = ksi->ksi_code;
322ea0fabbcSTim J. Robbins 	PROC_LOCK_ASSERT(p, MA_OWNED);
323ea0fabbcSTim J. Robbins 	psp = p->p_sigacts;
324ea0fabbcSTim J. Robbins 	mtx_assert(&psp->ps_mtx, MA_OWNED);
325ea0fabbcSTim J. Robbins 	regs = td->td_frame;
326ea0fabbcSTim J. Robbins 	oonstack = sigonstack(regs->tf_rsp);
327ea0fabbcSTim J. Robbins 
328ea0fabbcSTim J. Robbins #ifdef DEBUG
329ea0fabbcSTim J. Robbins 	if (ldebug(rt_sendsig))
330728ef954SJohn Baldwin 		printf(ARGS(rt_sendsig, "%p, %d, %p, %u"),
331ea0fabbcSTim J. Robbins 		    catcher, sig, (void*)mask, code);
332ea0fabbcSTim J. Robbins #endif
333ea0fabbcSTim J. Robbins 	/*
334ea0fabbcSTim J. Robbins 	 * Allocate space for the signal handler context.
335ea0fabbcSTim J. Robbins 	 */
336ea0fabbcSTim J. Robbins 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
337ea0fabbcSTim J. Robbins 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
338ea0fabbcSTim J. Robbins 		fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp +
339ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe));
340ea0fabbcSTim J. Robbins 	} else
341ea0fabbcSTim J. Robbins 		fp = (struct l_rt_sigframe *)regs->tf_rsp - 1;
342ea0fabbcSTim J. Robbins 	mtx_unlock(&psp->ps_mtx);
343ea0fabbcSTim J. Robbins 
344ea0fabbcSTim J. Robbins 	/*
345ea0fabbcSTim J. Robbins 	 * Build the argument list for the signal handler.
346ea0fabbcSTim J. Robbins 	 */
34726c68e1fSDmitry Chagin 	sig = BSD_TO_LINUX_SIGNAL(sig);
348ea0fabbcSTim J. Robbins 
349ea0fabbcSTim J. Robbins 	bzero(&frame, sizeof(frame));
350ea0fabbcSTim J. Robbins 
351ea0fabbcSTim J. Robbins 	frame.sf_handler = PTROUT(catcher);
352ea0fabbcSTim J. Robbins 	frame.sf_sig = sig;
353ea0fabbcSTim J. Robbins 	frame.sf_siginfo = PTROUT(&fp->sf_si);
354ea0fabbcSTim J. Robbins 	frame.sf_ucontext = PTROUT(&fp->sf_sc);
355ea0fabbcSTim J. Robbins 
356ea0fabbcSTim J. Robbins 	/* Fill in POSIX parts */
357aa8b2011SKonstantin Belousov 	ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig);
358ea0fabbcSTim J. Robbins 
359ea0fabbcSTim J. Robbins 	/*
360bdc37934SDmitry Chagin 	 * Build the signal context to be used by sigreturn
361bdc37934SDmitry Chagin 	 * and libgcc unwind.
362ea0fabbcSTim J. Robbins 	 */
363ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
364ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_link = 0;		/* XXX ??? */
365ea0fabbcSTim J. Robbins 
366ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp);
367ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size;
368ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
369ea0fabbcSTim J. Robbins 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
370ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
371ea0fabbcSTim J. Robbins 
372ea0fabbcSTim J. Robbins 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
373ea0fabbcSTim J. Robbins 
374ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
375ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_rdi;
376ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_rsi;
377ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_rbp;
378ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_rbx;
379bdc37934SDmitry Chagin 	frame.sf_sc.uc_mcontext.sc_esp    = regs->tf_rsp;
380ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_rdx;
381ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_rcx;
382ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_rax;
383ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_rip;
384ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
3852c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_gs     = regs->tf_gs;
3862c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
3872c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
3882c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
389ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags;
390ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp;
391ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
392ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
39396a2b635SKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_cr2    = (u_int32_t)(uintptr_t)ksi->ksi_addr;
394ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
395ea0fabbcSTim J. Robbins 
396ea0fabbcSTim J. Robbins #ifdef DEBUG
397ea0fabbcSTim J. Robbins 	if (ldebug(rt_sendsig))
398c680f6b1SDavid E. O'Brien 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"),
399ea0fabbcSTim J. Robbins 		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
400ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
401ea0fabbcSTim J. Robbins #endif
402ea0fabbcSTim J. Robbins 
403ea0fabbcSTim J. Robbins 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
404ea0fabbcSTim J. Robbins 		/*
405ea0fabbcSTim J. Robbins 		 * Process has trashed its stack; give it an illegal
406ea0fabbcSTim J. Robbins 		 * instruction to halt it in its tracks.
407ea0fabbcSTim J. Robbins 		 */
408ea0fabbcSTim J. Robbins #ifdef DEBUG
409ea0fabbcSTim J. Robbins 		if (ldebug(rt_sendsig))
410ea0fabbcSTim J. Robbins 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
411ea0fabbcSTim J. Robbins 			    fp, oonstack);
412ea0fabbcSTim J. Robbins #endif
413ea0fabbcSTim J. Robbins 		PROC_LOCK(p);
414ea0fabbcSTim J. Robbins 		sigexit(td, SIGILL);
415ea0fabbcSTim J. Robbins 	}
416ea0fabbcSTim J. Robbins 
417ea0fabbcSTim J. Robbins 	/*
418ea0fabbcSTim J. Robbins 	 * Build context to run handler in.
419ea0fabbcSTim J. Robbins 	 */
420ea0fabbcSTim J. Robbins 	regs->tf_rsp = PTROUT(fp);
421bdc37934SDmitry Chagin 	regs->tf_rip = linux32_rt_sigcode;
42222eca0bfSKonstantin Belousov 	regs->tf_rflags &= ~(PSL_T | PSL_D);
423ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
424ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
4252c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
4262c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
4272c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
4282c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
4292c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
430e6c006d9SJung-uk Kim 	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
431ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
432ea0fabbcSTim J. Robbins 	mtx_lock(&psp->ps_mtx);
433ea0fabbcSTim J. Robbins }
434ea0fabbcSTim J. Robbins 
435ea0fabbcSTim J. Robbins 
436ea0fabbcSTim J. Robbins /*
437ea0fabbcSTim J. Robbins  * Send an interrupt to process.
438ea0fabbcSTim J. Robbins  *
439ea0fabbcSTim J. Robbins  * Stack is set up to allow sigcode stored
440ea0fabbcSTim J. Robbins  * in u. to call routine, followed by kcall
441ea0fabbcSTim J. Robbins  * to sigreturn routine below.  After sigreturn
442ea0fabbcSTim J. Robbins  * resets the signal mask, the stack, and the
443ea0fabbcSTim J. Robbins  * frame pointer, it returns to the user
444ea0fabbcSTim J. Robbins  * specified pc, psl.
445ea0fabbcSTim J. Robbins  */
446ea0fabbcSTim J. Robbins static void
4479104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
448ea0fabbcSTim J. Robbins {
449ea0fabbcSTim J. Robbins 	struct thread *td = curthread;
450ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
451ea0fabbcSTim J. Robbins 	struct sigacts *psp;
452ea0fabbcSTim J. Robbins 	struct trapframe *regs;
453ea0fabbcSTim J. Robbins 	struct l_sigframe *fp, frame;
454ea0fabbcSTim J. Robbins 	l_sigset_t lmask;
455ea0fabbcSTim J. Robbins 	int oonstack, i;
4569104847fSDavid Xu 	int sig, code;
457ea0fabbcSTim J. Robbins 
4589104847fSDavid Xu 	sig = ksi->ksi_signo;
4599104847fSDavid Xu 	code = ksi->ksi_code;
460ea0fabbcSTim J. Robbins 	PROC_LOCK_ASSERT(p, MA_OWNED);
461ea0fabbcSTim J. Robbins 	psp = p->p_sigacts;
462ea0fabbcSTim J. Robbins 	mtx_assert(&psp->ps_mtx, MA_OWNED);
463ea0fabbcSTim J. Robbins 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
464ea0fabbcSTim J. Robbins 		/* Signal handler installed with SA_SIGINFO. */
4659104847fSDavid Xu 		linux_rt_sendsig(catcher, ksi, mask);
466ea0fabbcSTim J. Robbins 		return;
467ea0fabbcSTim J. Robbins 	}
468ea0fabbcSTim J. Robbins 
469ea0fabbcSTim J. Robbins 	regs = td->td_frame;
470ea0fabbcSTim J. Robbins 	oonstack = sigonstack(regs->tf_rsp);
471ea0fabbcSTim J. Robbins 
472ea0fabbcSTim J. Robbins #ifdef DEBUG
473ea0fabbcSTim J. Robbins 	if (ldebug(sendsig))
474728ef954SJohn Baldwin 		printf(ARGS(sendsig, "%p, %d, %p, %u"),
475ea0fabbcSTim J. Robbins 		    catcher, sig, (void*)mask, code);
476ea0fabbcSTim J. Robbins #endif
477ea0fabbcSTim J. Robbins 
478ea0fabbcSTim J. Robbins 	/*
479ea0fabbcSTim J. Robbins 	 * Allocate space for the signal handler context.
480ea0fabbcSTim J. Robbins 	 */
481ea0fabbcSTim J. Robbins 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
482ea0fabbcSTim J. Robbins 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
483ea0fabbcSTim J. Robbins 		fp = (struct l_sigframe *)(td->td_sigstk.ss_sp +
484ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size - sizeof(struct l_sigframe));
485ea0fabbcSTim J. Robbins 	} else
486ea0fabbcSTim J. Robbins 		fp = (struct l_sigframe *)regs->tf_rsp - 1;
487ea0fabbcSTim J. Robbins 	mtx_unlock(&psp->ps_mtx);
488ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
489ea0fabbcSTim J. Robbins 
490ea0fabbcSTim J. Robbins 	/*
491ea0fabbcSTim J. Robbins 	 * Build the argument list for the signal handler.
492ea0fabbcSTim J. Robbins 	 */
49326c68e1fSDmitry Chagin 	sig = BSD_TO_LINUX_SIGNAL(sig);
494ea0fabbcSTim J. Robbins 
495ea0fabbcSTim J. Robbins 	bzero(&frame, sizeof(frame));
496ea0fabbcSTim J. Robbins 
497ea0fabbcSTim J. Robbins 	frame.sf_handler = PTROUT(catcher);
498ea0fabbcSTim J. Robbins 	frame.sf_sig = sig;
499ea0fabbcSTim J. Robbins 
500ea0fabbcSTim J. Robbins 	bsd_to_linux_sigset(mask, &lmask);
501ea0fabbcSTim J. Robbins 
502ea0fabbcSTim J. Robbins 	/*
503ea0fabbcSTim J. Robbins 	 * Build the signal context to be used by sigreturn.
504ea0fabbcSTim J. Robbins 	 */
505ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_mask   = lmask.__bits[0];
5062c66cccaSKonstantin Belousov 	frame.sf_sc.sc_gs     = regs->tf_gs;
5072c66cccaSKonstantin Belousov 	frame.sf_sc.sc_fs     = regs->tf_fs;
5082c66cccaSKonstantin Belousov 	frame.sf_sc.sc_es     = regs->tf_es;
5092c66cccaSKonstantin Belousov 	frame.sf_sc.sc_ds     = regs->tf_ds;
510ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_edi    = regs->tf_rdi;
511ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_esi    = regs->tf_rsi;
512ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ebp    = regs->tf_rbp;
513ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ebx    = regs->tf_rbx;
514bdc37934SDmitry Chagin 	frame.sf_sc.sc_esp    = regs->tf_rsp;
515ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_edx    = regs->tf_rdx;
516ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ecx    = regs->tf_rcx;
517ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eax    = regs->tf_rax;
518ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eip    = regs->tf_rip;
519ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_cs     = regs->tf_cs;
520ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eflags = regs->tf_rflags;
521ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_esp_at_signal = regs->tf_rsp;
522ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ss     = regs->tf_ss;
523ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_err    = regs->tf_err;
52496a2b635SKonstantin Belousov 	frame.sf_sc.sc_cr2    = (u_int32_t)(uintptr_t)ksi->ksi_addr;
525ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code);
526ea0fabbcSTim J. Robbins 
527ea0fabbcSTim J. Robbins 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
528ea0fabbcSTim J. Robbins 		frame.sf_extramask[i] = lmask.__bits[i+1];
529ea0fabbcSTim J. Robbins 
530ea0fabbcSTim J. Robbins 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
531ea0fabbcSTim J. Robbins 		/*
532ea0fabbcSTim J. Robbins 		 * Process has trashed its stack; give it an illegal
533ea0fabbcSTim J. Robbins 		 * instruction to halt it in its tracks.
534ea0fabbcSTim J. Robbins 		 */
535ea0fabbcSTim J. Robbins 		PROC_LOCK(p);
536ea0fabbcSTim J. Robbins 		sigexit(td, SIGILL);
537ea0fabbcSTim J. Robbins 	}
538ea0fabbcSTim J. Robbins 
539ea0fabbcSTim J. Robbins 	/*
540ea0fabbcSTim J. Robbins 	 * Build context to run handler in.
541ea0fabbcSTim J. Robbins 	 */
542ea0fabbcSTim J. Robbins 	regs->tf_rsp = PTROUT(fp);
543bdc37934SDmitry Chagin 	regs->tf_rip = linux32_sigcode;
54422eca0bfSKonstantin Belousov 	regs->tf_rflags &= ~(PSL_T | PSL_D);
545ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
546ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
5472c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
5482c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
5492c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
5502c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
5512c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
552e6c006d9SJung-uk Kim 	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
553ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
554ea0fabbcSTim J. Robbins 	mtx_lock(&psp->ps_mtx);
555ea0fabbcSTim J. Robbins }
556ea0fabbcSTim J. Robbins 
557ea0fabbcSTim J. Robbins /*
558ea0fabbcSTim J. Robbins  * System call to cleanup state after a signal
559ea0fabbcSTim J. Robbins  * has been taken.  Reset signal mask and
560ea0fabbcSTim J. Robbins  * stack state from context left by sendsig (above).
561ea0fabbcSTim J. Robbins  * Return to previous pc and psl as specified by
562ea0fabbcSTim J. Robbins  * context left by sendsig. Check carefully to
563ea0fabbcSTim J. Robbins  * make sure that the user has not modified the
564ea0fabbcSTim J. Robbins  * psl to gain improper privileges or to cause
565ea0fabbcSTim J. Robbins  * a machine fault.
566ea0fabbcSTim J. Robbins  */
567ea0fabbcSTim J. Robbins int
568ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
569ea0fabbcSTim J. Robbins {
570ea0fabbcSTim J. Robbins 	struct l_sigframe frame;
571ea0fabbcSTim J. Robbins 	struct trapframe *regs;
572d6e029adSKonstantin Belousov 	sigset_t bmask;
573ea0fabbcSTim J. Robbins 	l_sigset_t lmask;
574ea0fabbcSTim J. Robbins 	int eflags, i;
5759104847fSDavid Xu 	ksiginfo_t ksi;
576ea0fabbcSTim J. Robbins 
577ea0fabbcSTim J. Robbins 	regs = td->td_frame;
578ea0fabbcSTim J. Robbins 
579ea0fabbcSTim J. Robbins #ifdef DEBUG
580ea0fabbcSTim J. Robbins 	if (ldebug(sigreturn))
581ea0fabbcSTim J. Robbins 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
582ea0fabbcSTim J. Robbins #endif
583ea0fabbcSTim J. Robbins 	/*
584ea0fabbcSTim J. Robbins 	 * The trampoline code hands us the sigframe.
585ea0fabbcSTim J. Robbins 	 * It is unsafe to keep track of it ourselves, in the event that a
586ea0fabbcSTim J. Robbins 	 * program jumps out of a signal handler.
587ea0fabbcSTim J. Robbins 	 */
588ea0fabbcSTim J. Robbins 	if (copyin(args->sfp, &frame, sizeof(frame)) != 0)
589ea0fabbcSTim J. Robbins 		return (EFAULT);
590ea0fabbcSTim J. Robbins 
591ea0fabbcSTim J. Robbins 	/*
592ea0fabbcSTim J. Robbins 	 * Check for security violations.
593ea0fabbcSTim J. Robbins 	 */
594ea0fabbcSTim J. Robbins #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
595ea0fabbcSTim J. Robbins 	eflags = frame.sf_sc.sc_eflags;
5963d271aaaSEd Maste 	if (!EFLAGS_SECURE(eflags, regs->tf_rflags))
597ea0fabbcSTim J. Robbins 		return(EINVAL);
598ea0fabbcSTim J. Robbins 
599ea0fabbcSTim J. Robbins 	/*
600ea0fabbcSTim J. Robbins 	 * Don't allow users to load a valid privileged %cs.  Let the
601ea0fabbcSTim J. Robbins 	 * hardware check for invalid selectors, excess privilege in
602ea0fabbcSTim J. Robbins 	 * other selectors, invalid %eip's and invalid %esp's.
603ea0fabbcSTim J. Robbins 	 */
604ea0fabbcSTim J. Robbins #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
605ea0fabbcSTim J. Robbins 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
6069104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
6079104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
6089104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
6099104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
6109104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_rip;
6119104847fSDavid Xu 		trapsignal(td, &ksi);
612ea0fabbcSTim J. Robbins 		return(EINVAL);
613ea0fabbcSTim J. Robbins 	}
614ea0fabbcSTim J. Robbins 
615ea0fabbcSTim J. Robbins 	lmask.__bits[0] = frame.sf_sc.sc_mask;
616ea0fabbcSTim J. Robbins 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
617ea0fabbcSTim J. Robbins 		lmask.__bits[i+1] = frame.sf_extramask[i];
618d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&lmask, &bmask);
619d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
620ea0fabbcSTim J. Robbins 
621ea0fabbcSTim J. Robbins 	/*
622ea0fabbcSTim J. Robbins 	 * Restore signal context.
623ea0fabbcSTim J. Robbins 	 */
624ea0fabbcSTim J. Robbins 	regs->tf_rdi    = frame.sf_sc.sc_edi;
625ea0fabbcSTim J. Robbins 	regs->tf_rsi    = frame.sf_sc.sc_esi;
626ea0fabbcSTim J. Robbins 	regs->tf_rbp    = frame.sf_sc.sc_ebp;
627ea0fabbcSTim J. Robbins 	regs->tf_rbx    = frame.sf_sc.sc_ebx;
628ea0fabbcSTim J. Robbins 	regs->tf_rdx    = frame.sf_sc.sc_edx;
629ea0fabbcSTim J. Robbins 	regs->tf_rcx    = frame.sf_sc.sc_ecx;
630ea0fabbcSTim J. Robbins 	regs->tf_rax    = frame.sf_sc.sc_eax;
631ea0fabbcSTim J. Robbins 	regs->tf_rip    = frame.sf_sc.sc_eip;
632ea0fabbcSTim J. Robbins 	regs->tf_cs     = frame.sf_sc.sc_cs;
6332c66cccaSKonstantin Belousov 	regs->tf_ds     = frame.sf_sc.sc_ds;
6342c66cccaSKonstantin Belousov 	regs->tf_es     = frame.sf_sc.sc_es;
6352c66cccaSKonstantin Belousov 	regs->tf_fs     = frame.sf_sc.sc_fs;
6362c66cccaSKonstantin Belousov 	regs->tf_gs     = frame.sf_sc.sc_gs;
637ea0fabbcSTim J. Robbins 	regs->tf_rflags = eflags;
638ea0fabbcSTim J. Robbins 	regs->tf_rsp    = frame.sf_sc.sc_esp_at_signal;
639ea0fabbcSTim J. Robbins 	regs->tf_ss     = frame.sf_sc.sc_ss;
640e6c006d9SJung-uk Kim 	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
641ea0fabbcSTim J. Robbins 
642ea0fabbcSTim J. Robbins 	return (EJUSTRETURN);
643ea0fabbcSTim J. Robbins }
644ea0fabbcSTim J. Robbins 
645ea0fabbcSTim J. Robbins /*
646ea0fabbcSTim J. Robbins  * System call to cleanup state after a signal
647ea0fabbcSTim J. Robbins  * has been taken.  Reset signal mask and
648ea0fabbcSTim J. Robbins  * stack state from context left by rt_sendsig (above).
649ea0fabbcSTim J. Robbins  * Return to previous pc and psl as specified by
650ea0fabbcSTim J. Robbins  * context left by sendsig. Check carefully to
651ea0fabbcSTim J. Robbins  * make sure that the user has not modified the
652ea0fabbcSTim J. Robbins  * psl to gain improper privileges or to cause
653ea0fabbcSTim J. Robbins  * a machine fault.
654ea0fabbcSTim J. Robbins  */
655ea0fabbcSTim J. Robbins int
656ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
657ea0fabbcSTim J. Robbins {
658ea0fabbcSTim J. Robbins 	struct l_ucontext uc;
659ea0fabbcSTim J. Robbins 	struct l_sigcontext *context;
660d6e029adSKonstantin Belousov 	sigset_t bmask;
661ea0fabbcSTim J. Robbins 	l_stack_t *lss;
662ea0fabbcSTim J. Robbins 	stack_t ss;
663ea0fabbcSTim J. Robbins 	struct trapframe *regs;
664ea0fabbcSTim J. Robbins 	int eflags;
6659104847fSDavid Xu 	ksiginfo_t ksi;
666ea0fabbcSTim J. Robbins 
667ea0fabbcSTim J. Robbins 	regs = td->td_frame;
668ea0fabbcSTim J. Robbins 
669ea0fabbcSTim J. Robbins #ifdef DEBUG
670ea0fabbcSTim J. Robbins 	if (ldebug(rt_sigreturn))
671ea0fabbcSTim J. Robbins 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
672ea0fabbcSTim J. Robbins #endif
673ea0fabbcSTim J. Robbins 	/*
674ea0fabbcSTim J. Robbins 	 * The trampoline code hands us the ucontext.
675ea0fabbcSTim J. Robbins 	 * It is unsafe to keep track of it ourselves, in the event that a
676ea0fabbcSTim J. Robbins 	 * program jumps out of a signal handler.
677ea0fabbcSTim J. Robbins 	 */
678ea0fabbcSTim J. Robbins 	if (copyin(args->ucp, &uc, sizeof(uc)) != 0)
679ea0fabbcSTim J. Robbins 		return (EFAULT);
680ea0fabbcSTim J. Robbins 
681ea0fabbcSTim J. Robbins 	context = &uc.uc_mcontext;
682ea0fabbcSTim J. Robbins 
683ea0fabbcSTim J. Robbins 	/*
684ea0fabbcSTim J. Robbins 	 * Check for security violations.
685ea0fabbcSTim J. Robbins 	 */
686ea0fabbcSTim J. Robbins #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
687ea0fabbcSTim J. Robbins 	eflags = context->sc_eflags;
6883d271aaaSEd Maste 	if (!EFLAGS_SECURE(eflags, regs->tf_rflags))
689ea0fabbcSTim J. Robbins 		return(EINVAL);
690ea0fabbcSTim J. Robbins 
691ea0fabbcSTim J. Robbins 	/*
692ea0fabbcSTim J. Robbins 	 * Don't allow users to load a valid privileged %cs.  Let the
693ea0fabbcSTim J. Robbins 	 * hardware check for invalid selectors, excess privilege in
694ea0fabbcSTim J. Robbins 	 * other selectors, invalid %eip's and invalid %esp's.
695ea0fabbcSTim J. Robbins 	 */
696ea0fabbcSTim J. Robbins #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
697ea0fabbcSTim J. Robbins 	if (!CS_SECURE(context->sc_cs)) {
6989104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
6999104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
7009104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
7019104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
7029104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_rip;
7039104847fSDavid Xu 		trapsignal(td, &ksi);
704ea0fabbcSTim J. Robbins 		return(EINVAL);
705ea0fabbcSTim J. Robbins 	}
706ea0fabbcSTim J. Robbins 
707d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&uc.uc_sigmask, &bmask);
708d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
709ea0fabbcSTim J. Robbins 
710ea0fabbcSTim J. Robbins 	/*
711ea0fabbcSTim J. Robbins 	 * Restore signal context
712ea0fabbcSTim J. Robbins 	 */
7132c66cccaSKonstantin Belousov 	regs->tf_gs	= context->sc_gs;
7142c66cccaSKonstantin Belousov 	regs->tf_fs	= context->sc_fs;
7152c66cccaSKonstantin Belousov 	regs->tf_es	= context->sc_es;
7162c66cccaSKonstantin Belousov 	regs->tf_ds	= context->sc_ds;
717ea0fabbcSTim J. Robbins 	regs->tf_rdi    = context->sc_edi;
718ea0fabbcSTim J. Robbins 	regs->tf_rsi    = context->sc_esi;
719ea0fabbcSTim J. Robbins 	regs->tf_rbp    = context->sc_ebp;
720ea0fabbcSTim J. Robbins 	regs->tf_rbx    = context->sc_ebx;
721ea0fabbcSTim J. Robbins 	regs->tf_rdx    = context->sc_edx;
722ea0fabbcSTim J. Robbins 	regs->tf_rcx    = context->sc_ecx;
723ea0fabbcSTim J. Robbins 	regs->tf_rax    = context->sc_eax;
724ea0fabbcSTim J. Robbins 	regs->tf_rip    = context->sc_eip;
725ea0fabbcSTim J. Robbins 	regs->tf_cs     = context->sc_cs;
726ea0fabbcSTim J. Robbins 	regs->tf_rflags = eflags;
727ea0fabbcSTim J. Robbins 	regs->tf_rsp    = context->sc_esp_at_signal;
728ea0fabbcSTim J. Robbins 	regs->tf_ss     = context->sc_ss;
729e6c006d9SJung-uk Kim 	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
730ea0fabbcSTim J. Robbins 
731ea0fabbcSTim J. Robbins 	/*
732ea0fabbcSTim J. Robbins 	 * call sigaltstack & ignore results..
733ea0fabbcSTim J. Robbins 	 */
734ea0fabbcSTim J. Robbins 	lss = &uc.uc_stack;
735ea0fabbcSTim J. Robbins 	ss.ss_sp = PTRIN(lss->ss_sp);
736ea0fabbcSTim J. Robbins 	ss.ss_size = lss->ss_size;
737ea0fabbcSTim J. Robbins 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
738ea0fabbcSTim J. Robbins 
739ea0fabbcSTim J. Robbins #ifdef DEBUG
740ea0fabbcSTim J. Robbins 	if (ldebug(rt_sigreturn))
741c680f6b1SDavid E. O'Brien 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"),
742ea0fabbcSTim J. Robbins 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
743ea0fabbcSTim J. Robbins #endif
744ea0fabbcSTim J. Robbins 	(void)kern_sigaltstack(td, &ss, NULL);
745ea0fabbcSTim J. Robbins 
746ea0fabbcSTim J. Robbins 	return (EJUSTRETURN);
747ea0fabbcSTim J. Robbins }
748ea0fabbcSTim J. Robbins 
749afe1a688SKonstantin Belousov static int
750afe1a688SKonstantin Belousov linux32_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
751ea0fabbcSTim J. Robbins {
752afe1a688SKonstantin Belousov 	struct proc *p;
753afe1a688SKonstantin Belousov 	struct trapframe *frame;
754afe1a688SKonstantin Belousov 
755afe1a688SKonstantin Belousov 	p = td->td_proc;
756afe1a688SKonstantin Belousov 	frame = td->td_frame;
757afe1a688SKonstantin Belousov 
758afe1a688SKonstantin Belousov 	sa->args[0] = frame->tf_rbx;
759afe1a688SKonstantin Belousov 	sa->args[1] = frame->tf_rcx;
760afe1a688SKonstantin Belousov 	sa->args[2] = frame->tf_rdx;
761afe1a688SKonstantin Belousov 	sa->args[3] = frame->tf_rsi;
762afe1a688SKonstantin Belousov 	sa->args[4] = frame->tf_rdi;
763afe1a688SKonstantin Belousov 	sa->args[5] = frame->tf_rbp;	/* Unconfirmed */
764afe1a688SKonstantin Belousov 	sa->code = frame->tf_rax;
765afe1a688SKonstantin Belousov 
766afe1a688SKonstantin Belousov 	if (sa->code >= p->p_sysent->sv_size)
767*fcdffc03SDmitry Chagin 		/* nosys */
768*fcdffc03SDmitry Chagin 		sa->callp = &p->p_sysent->sv_table[LINUX_SYS_MAXSYSCALL];
769afe1a688SKonstantin Belousov 	else
770afe1a688SKonstantin Belousov 		sa->callp = &p->p_sysent->sv_table[sa->code];
771afe1a688SKonstantin Belousov 	sa->narg = sa->callp->sy_narg;
772afe1a688SKonstantin Belousov 
773afe1a688SKonstantin Belousov 	td->td_retval[0] = 0;
774afe1a688SKonstantin Belousov 	td->td_retval[1] = frame->tf_rdx;
775afe1a688SKonstantin Belousov 
776afe1a688SKonstantin Belousov 	return (0);
777ea0fabbcSTim J. Robbins }
778ea0fabbcSTim J. Robbins 
779ea0fabbcSTim J. Robbins /*
780ea0fabbcSTim J. Robbins  * If a linux binary is exec'ing something, try this image activator
781ea0fabbcSTim J. Robbins  * first.  We override standard shell script execution in order to
782ea0fabbcSTim J. Robbins  * be able to modify the interpreter path.  We only do this if a linux
783ea0fabbcSTim J. Robbins  * binary is doing the exec, so we do not create an EXEC module for it.
784ea0fabbcSTim J. Robbins  */
785ea0fabbcSTim J. Robbins static int	exec_linux_imgact_try(struct image_params *iparams);
786ea0fabbcSTim J. Robbins 
787ea0fabbcSTim J. Robbins static int
788ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp)
789ea0fabbcSTim J. Robbins {
790ea0fabbcSTim J. Robbins 	const char *head = (const char *)imgp->image_header;
7911d15fdd9SJohn Baldwin 	char *rpath;
792a14a9498SAlan Cox 	int error = -1;
793ea0fabbcSTim J. Robbins 
794ea0fabbcSTim J. Robbins 	/*
795ea0fabbcSTim J. Robbins 	* The interpreter for shell scripts run from a linux binary needs
796ea0fabbcSTim J. Robbins 	* to be located in /compat/linux if possible in order to recursively
797ea0fabbcSTim J. Robbins 	* maintain linux path emulation.
798ea0fabbcSTim J. Robbins 	*/
799ea0fabbcSTim J. Robbins 	if (((const short *)head)[0] == SHELLMAGIC) {
800ea0fabbcSTim J. Robbins 		/*
801ea0fabbcSTim J. Robbins 		* Run our normal shell image activator.  If it succeeds attempt
802d065e13dSDavid E. O'Brien 		* to use the alternate path for the interpreter.  If an
803d065e13dSDavid E. O'Brien 		* alternate * path is found, use our stringspace to store it.
804ea0fabbcSTim J. Robbins 		*/
805ea0fabbcSTim J. Robbins 		if ((error = exec_shell_imgact(imgp)) == 0) {
8061d15fdd9SJohn Baldwin 			linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
807d065e13dSDavid E. O'Brien 			    imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0,
808d065e13dSDavid E. O'Brien 			    AT_FDCWD);
809a14a9498SAlan Cox 			if (rpath != NULL)
810a14a9498SAlan Cox 				imgp->args->fname_buf =
811a14a9498SAlan Cox 				    imgp->interpreter_name = rpath;
812ea0fabbcSTim J. Robbins 		}
813ea0fabbcSTim J. Robbins 	}
814ea0fabbcSTim J. Robbins 	return (error);
815ea0fabbcSTim J. Robbins }
816ea0fabbcSTim J. Robbins 
817ea0fabbcSTim J. Robbins /*
818ea0fabbcSTim J. Robbins  * Clear registers on exec
819ea0fabbcSTim J. Robbins  * XXX copied from ia32_signal.c.
820ea0fabbcSTim J. Robbins  */
821ea0fabbcSTim J. Robbins static void
822a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack)
823ea0fabbcSTim J. Robbins {
824ea0fabbcSTim J. Robbins 	struct trapframe *regs = td->td_frame;
825ea0fabbcSTim J. Robbins 	struct pcb *pcb = td->td_pcb;
826ea0fabbcSTim J. Robbins 
8272c66cccaSKonstantin Belousov 	mtx_lock(&dt_lock);
8282c66cccaSKonstantin Belousov 	if (td->td_proc->p_md.md_ldt != NULL)
8292c66cccaSKonstantin Belousov 		user_ldt_free(td);
8302c66cccaSKonstantin Belousov 	else
8312c66cccaSKonstantin Belousov 		mtx_unlock(&dt_lock);
8322c66cccaSKonstantin Belousov 
8339c5b213eSJung-uk Kim 	critical_enter();
834ea0fabbcSTim J. Robbins 	wrmsr(MSR_FSBASE, 0);
835ea0fabbcSTim J. Robbins 	wrmsr(MSR_KGSBASE, 0);	/* User value while we're in the kernel */
836ea0fabbcSTim J. Robbins 	pcb->pcb_fsbase = 0;
837ea0fabbcSTim J. Robbins 	pcb->pcb_gsbase = 0;
8389c5b213eSJung-uk Kim 	critical_exit();
8392ee8325fSJohn Baldwin 	pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
840ea0fabbcSTim J. Robbins 
841ea0fabbcSTim J. Robbins 	bzero((char *)regs, sizeof(struct trapframe));
842a107d8aaSNathan Whitehorn 	regs->tf_rip = imgp->entry_addr;
843ea0fabbcSTim J. Robbins 	regs->tf_rsp = stack;
844ea0fabbcSTim J. Robbins 	regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
8452c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
8462c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
8472c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
8482c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
849ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
8502c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
851ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
852a107d8aaSNathan Whitehorn 	regs->tf_rbx = imgp->ps_strings;
853bdbf2db5SJung-uk Kim 
8542a988f7cSStephan Uphoff 	fpstate_drop(td);
855ea0fabbcSTim J. Robbins 
8561b3c3256SKonstantin Belousov 	/* Do full restore on return so that we can change to a different %cs */
857e6c006d9SJung-uk Kim 	set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET);
858ea0fabbcSTim J. Robbins 	td->td_retval[1] = 0;
859ea0fabbcSTim J. Robbins }
860ea0fabbcSTim J. Robbins 
861ea0fabbcSTim J. Robbins /*
862ea0fabbcSTim J. Robbins  * XXX copied from ia32_sysvec.c.
863ea0fabbcSTim J. Robbins  */
864ea0fabbcSTim J. Robbins static register_t *
865ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp)
866ea0fabbcSTim J. Robbins {
867ea0fabbcSTim J. Robbins 	int argc, envc;
868ea0fabbcSTim J. Robbins 	u_int32_t *vectp;
869ea0fabbcSTim J. Robbins 	char *stringp, *destp;
870ea0fabbcSTim J. Robbins 	u_int32_t *stack_base;
871ea0fabbcSTim J. Robbins 	struct linux32_ps_strings *arginfo;
8724048f59cSDmitry Chagin 	char canary[LINUX_AT_RANDOM_LEN];
8734048f59cSDmitry Chagin 	size_t execpath_len;
874ea0fabbcSTim J. Robbins 
875ea0fabbcSTim J. Robbins 	/*
876ea0fabbcSTim J. Robbins 	 * Calculate string base and vector table pointers.
877ea0fabbcSTim J. Robbins 	 */
8784048f59cSDmitry Chagin 	if (imgp->execpath != NULL && imgp->auxargs != NULL)
8794048f59cSDmitry Chagin 		execpath_len = strlen(imgp->execpath) + 1;
8804048f59cSDmitry Chagin 	else
8814048f59cSDmitry Chagin 		execpath_len = 0;
8824048f59cSDmitry Chagin 
883ea0fabbcSTim J. Robbins 	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
8840020bdf1SDmitry Chagin 	destp =	(caddr_t)arginfo - SPARE_USRSPACE -
8854048f59cSDmitry Chagin 	    roundup(sizeof(canary), sizeof(char *)) -
8864048f59cSDmitry Chagin 	    roundup(execpath_len, sizeof(char *)) -
8870020bdf1SDmitry Chagin 	    roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
888ea0fabbcSTim J. Robbins 
8894048f59cSDmitry Chagin 	if (execpath_len != 0) {
8904048f59cSDmitry Chagin 		imgp->execpathp = (uintptr_t)arginfo - execpath_len;
8914048f59cSDmitry Chagin 		copyout(imgp->execpath, (void *)imgp->execpathp, execpath_len);
8924048f59cSDmitry Chagin 	}
8934048f59cSDmitry Chagin 
8944048f59cSDmitry Chagin 	/*
8954048f59cSDmitry Chagin 	 * Prepare the canary for SSP.
8964048f59cSDmitry Chagin 	 */
8974048f59cSDmitry Chagin 	arc4rand(canary, sizeof(canary), 0);
8984048f59cSDmitry Chagin 	imgp->canary = (uintptr_t)arginfo -
8994048f59cSDmitry Chagin 	    roundup(execpath_len, sizeof(char *)) -
9004048f59cSDmitry Chagin 	    roundup(sizeof(canary), sizeof(char *));
9014048f59cSDmitry Chagin 	copyout(canary, (void *)imgp->canary, sizeof(canary));
9024048f59cSDmitry Chagin 
903ea0fabbcSTim J. Robbins 	/*
904ea0fabbcSTim J. Robbins 	 * If we have a valid auxargs ptr, prepare some room
905ea0fabbcSTim J. Robbins 	 * on the stack.
906ea0fabbcSTim J. Robbins 	 */
907ea0fabbcSTim J. Robbins 	if (imgp->auxargs) {
908ea0fabbcSTim J. Robbins 		/*
909ea0fabbcSTim J. Robbins 		 * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
910ea0fabbcSTim J. Robbins 		 * lower compatibility.
911ea0fabbcSTim J. Robbins 		 */
912d065e13dSDavid E. O'Brien 		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
9134d7c2e8aSDmitry Chagin 		    (LINUX_AT_COUNT * 2);
914ea0fabbcSTim J. Robbins 		/*
915ea0fabbcSTim J. Robbins 		 * The '+ 2' is for the null pointers at the end of each of
916ea0fabbcSTim J. Robbins 		 * the arg and env vector sets,and imgp->auxarg_size is room
917ea0fabbcSTim J. Robbins 		 * for argument of Runtime loader.
918ea0fabbcSTim J. Robbins 		 */
919d065e13dSDavid E. O'Brien 		vectp = (u_int32_t *) (destp - (imgp->args->argc +
920d065e13dSDavid E. O'Brien 		    imgp->args->envc + 2 + imgp->auxarg_size) *
921d065e13dSDavid E. O'Brien 		    sizeof(u_int32_t));
922ea0fabbcSTim J. Robbins 
923ea0fabbcSTim J. Robbins 	} else
924ea0fabbcSTim J. Robbins 		/*
925ea0fabbcSTim J. Robbins 		 * The '+ 2' is for the null pointers at the end of each of
926ea0fabbcSTim J. Robbins 		 * the arg and env vector sets
927ea0fabbcSTim J. Robbins 		 */
928d065e13dSDavid E. O'Brien 		vectp = (u_int32_t *)(destp - (imgp->args->argc +
929d065e13dSDavid E. O'Brien 		    imgp->args->envc + 2) * sizeof(u_int32_t));
930ea0fabbcSTim J. Robbins 
931ea0fabbcSTim J. Robbins 	/*
932ea0fabbcSTim J. Robbins 	 * vectp also becomes our initial stack base
933ea0fabbcSTim J. Robbins 	 */
934ea0fabbcSTim J. Robbins 	stack_base = vectp;
935ea0fabbcSTim J. Robbins 
936610ecfe0SMaxim Sobolev 	stringp = imgp->args->begin_argv;
937610ecfe0SMaxim Sobolev 	argc = imgp->args->argc;
938610ecfe0SMaxim Sobolev 	envc = imgp->args->envc;
939ea0fabbcSTim J. Robbins 	/*
940ea0fabbcSTim J. Robbins 	 * Copy out strings - arguments and environment.
941ea0fabbcSTim J. Robbins 	 */
942610ecfe0SMaxim Sobolev 	copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
943ea0fabbcSTim J. Robbins 
944ea0fabbcSTim J. Robbins 	/*
945ea0fabbcSTim J. Robbins 	 * Fill in "ps_strings" struct for ps, w, etc.
946ea0fabbcSTim J. Robbins 	 */
9474d7c2e8aSDmitry Chagin 	suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp);
948ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_nargvstr, argc);
949ea0fabbcSTim J. Robbins 
950ea0fabbcSTim J. Robbins 	/*
951ea0fabbcSTim J. Robbins 	 * Fill in argument portion of vector table.
952ea0fabbcSTim J. Robbins 	 */
953ea0fabbcSTim J. Robbins 	for (; argc > 0; --argc) {
9544d7c2e8aSDmitry Chagin 		suword32(vectp++, (uint32_t)(intptr_t)destp);
955ea0fabbcSTim J. Robbins 		while (*stringp++ != 0)
956ea0fabbcSTim J. Robbins 			destp++;
957ea0fabbcSTim J. Robbins 		destp++;
958ea0fabbcSTim J. Robbins 	}
959ea0fabbcSTim J. Robbins 
960ea0fabbcSTim J. Robbins 	/* a null vector table pointer separates the argp's from the envp's */
961ea0fabbcSTim J. Robbins 	suword32(vectp++, 0);
962ea0fabbcSTim J. Robbins 
9634d7c2e8aSDmitry Chagin 	suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp);
964ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_nenvstr, envc);
965ea0fabbcSTim J. Robbins 
966ea0fabbcSTim J. Robbins 	/*
967ea0fabbcSTim J. Robbins 	 * Fill in environment portion of vector table.
968ea0fabbcSTim J. Robbins 	 */
969ea0fabbcSTim J. Robbins 	for (; envc > 0; --envc) {
9704d7c2e8aSDmitry Chagin 		suword32(vectp++, (uint32_t)(intptr_t)destp);
971ea0fabbcSTim J. Robbins 		while (*stringp++ != 0)
972ea0fabbcSTim J. Robbins 			destp++;
973ea0fabbcSTim J. Robbins 		destp++;
974ea0fabbcSTim J. Robbins 	}
975ea0fabbcSTim J. Robbins 
976ea0fabbcSTim J. Robbins 	/* end of vector table is a null pointer */
977ea0fabbcSTim J. Robbins 	suword32(vectp, 0);
978ea0fabbcSTim J. Robbins 
979ea0fabbcSTim J. Robbins 	return ((register_t *)stack_base);
980ea0fabbcSTim J. Robbins }
981ea0fabbcSTim J. Robbins 
9826472ac3dSEd Schouten static SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0,
983ea0fabbcSTim J. Robbins     "32-bit Linux emulation");
984ea0fabbcSTim J. Robbins 
985ea0fabbcSTim J. Robbins static u_long	linux32_maxdsiz = LINUX32_MAXDSIZ;
986ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW,
987ea0fabbcSTim J. Robbins     &linux32_maxdsiz, 0, "");
988ea0fabbcSTim J. Robbins static u_long	linux32_maxssiz = LINUX32_MAXSSIZ;
989ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW,
990ea0fabbcSTim J. Robbins     &linux32_maxssiz, 0, "");
991ea0fabbcSTim J. Robbins static u_long	linux32_maxvmem = LINUX32_MAXVMEM;
992ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW,
993ea0fabbcSTim J. Robbins     &linux32_maxvmem, 0, "");
994ea0fabbcSTim J. Robbins 
99567d39748SDmitry Chagin #if defined(DEBUG)
99667d39748SDmitry Chagin SYSCTL_PROC(_compat_linux32, OID_AUTO, debug,
99767d39748SDmitry Chagin             CTLTYPE_STRING | CTLFLAG_RW,
99867d39748SDmitry Chagin             0, 0, linux_sysctl_debug, "A",
99967d39748SDmitry Chagin             "Linux debugging control");
100067d39748SDmitry Chagin #endif
100167d39748SDmitry Chagin 
1002ea0fabbcSTim J. Robbins static void
100319059a13SJohn Baldwin linux32_fixlimit(struct rlimit *rl, int which)
1004ea0fabbcSTim J. Robbins {
1005ea0fabbcSTim J. Robbins 
100619059a13SJohn Baldwin 	switch (which) {
100719059a13SJohn Baldwin 	case RLIMIT_DATA:
1008ea0fabbcSTim J. Robbins 		if (linux32_maxdsiz != 0) {
100919059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxdsiz)
101019059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxdsiz;
101119059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxdsiz)
101219059a13SJohn Baldwin 				rl->rlim_max = linux32_maxdsiz;
1013ea0fabbcSTim J. Robbins 		}
101419059a13SJohn Baldwin 		break;
101519059a13SJohn Baldwin 	case RLIMIT_STACK:
1016ea0fabbcSTim J. Robbins 		if (linux32_maxssiz != 0) {
101719059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxssiz)
101819059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxssiz;
101919059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxssiz)
102019059a13SJohn Baldwin 				rl->rlim_max = linux32_maxssiz;
1021ea0fabbcSTim J. Robbins 		}
102219059a13SJohn Baldwin 		break;
102319059a13SJohn Baldwin 	case RLIMIT_VMEM:
1024ea0fabbcSTim J. Robbins 		if (linux32_maxvmem != 0) {
102519059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxvmem)
102619059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxvmem;
102719059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxvmem)
102819059a13SJohn Baldwin 				rl->rlim_max = linux32_maxvmem;
1029ea0fabbcSTim J. Robbins 		}
103019059a13SJohn Baldwin 		break;
103119059a13SJohn Baldwin 	}
1032ea0fabbcSTim J. Robbins }
1033ea0fabbcSTim J. Robbins 
1034ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = {
1035a8d403e1SKonstantin Belousov 	.sv_size	= LINUX_SYS_MAXSYSCALL,
1036a8d403e1SKonstantin Belousov 	.sv_table	= linux_sysent,
1037a8d403e1SKonstantin Belousov 	.sv_mask	= 0,
1038a8d403e1SKonstantin Belousov 	.sv_sigsize	= LINUX_SIGTBLSZ,
1039a8d403e1SKonstantin Belousov 	.sv_sigtbl	= bsd_to_linux_signal,
1040a8d403e1SKonstantin Belousov 	.sv_errsize	= ELAST + 1,
1041a8d403e1SKonstantin Belousov 	.sv_errtbl	= bsd_to_linux_errno,
1042a8d403e1SKonstantin Belousov 	.sv_transtrap	= translate_traps,
1043a8d403e1SKonstantin Belousov 	.sv_fixup	= elf_linux_fixup,
1044a8d403e1SKonstantin Belousov 	.sv_sendsig	= linux_sendsig,
1045bdc37934SDmitry Chagin 	.sv_sigcode	= &_binary_linux32_locore_o_start,
1046a8d403e1SKonstantin Belousov 	.sv_szsigcode	= &linux_szsigcode,
1047afe1a688SKonstantin Belousov 	.sv_prepsyscall	= NULL,
1048a8d403e1SKonstantin Belousov 	.sv_name	= "Linux ELF32",
1049a8d403e1SKonstantin Belousov 	.sv_coredump	= elf32_coredump,
1050a8d403e1SKonstantin Belousov 	.sv_imgact_try	= exec_linux_imgact_try,
1051a8d403e1SKonstantin Belousov 	.sv_minsigstksz	= LINUX_MINSIGSTKSZ,
1052a8d403e1SKonstantin Belousov 	.sv_pagesize	= PAGE_SIZE,
1053a8d403e1SKonstantin Belousov 	.sv_minuser	= VM_MIN_ADDRESS,
10548f1e49a6SDmitry Chagin 	.sv_maxuser	= LINUX32_MAXUSER,
1055a8d403e1SKonstantin Belousov 	.sv_usrstack	= LINUX32_USRSTACK,
1056a8d403e1SKonstantin Belousov 	.sv_psstrings	= LINUX32_PS_STRINGS,
1057a8d403e1SKonstantin Belousov 	.sv_stackprot	= VM_PROT_ALL,
1058a8d403e1SKonstantin Belousov 	.sv_copyout_strings = linux_copyout_strings,
1059a8d403e1SKonstantin Belousov 	.sv_setregs	= exec_linux_setregs,
1060a8d403e1SKonstantin Belousov 	.sv_fixlimit	= linux32_fixlimit,
1061a8d403e1SKonstantin Belousov 	.sv_maxssiz	= &linux32_maxssiz,
10628f1e49a6SDmitry Chagin 	.sv_flags	= SV_ABI_LINUX | SV_ILP32 | SV_IA32 | SV_SHP,
1063afe1a688SKonstantin Belousov 	.sv_set_syscall_retval = cpu_set_syscall_retval,
1064afe1a688SKonstantin Belousov 	.sv_fetch_syscall_args = linux32_fetch_syscall_args,
1065afe1a688SKonstantin Belousov 	.sv_syscallnames = NULL,
10668f1e49a6SDmitry Chagin 	.sv_shared_page_base = LINUX32_SHAREDPAGE,
10678f1e49a6SDmitry Chagin 	.sv_shared_page_len = PAGE_SIZE,
1068e5d81ef1SDmitry Chagin 	.sv_schedtail	= linux_schedtail,
106981338031SDmitry Chagin 	.sv_thread_detach = linux_thread_detach,
1070ea0fabbcSTim J. Robbins };
1071bdc37934SDmitry Chagin 
1072bdc37934SDmitry Chagin static void
1073bdc37934SDmitry Chagin linux_vdso_install(void *param)
1074bdc37934SDmitry Chagin {
1075bdc37934SDmitry Chagin 
1076bdc37934SDmitry Chagin 	linux_szsigcode = (&_binary_linux32_locore_o_end -
1077bdc37934SDmitry Chagin 	    &_binary_linux32_locore_o_start);
1078bdc37934SDmitry Chagin 
1079bdc37934SDmitry Chagin 	if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len)
1080bdc37934SDmitry Chagin 		panic("Linux invalid vdso size\n");
1081bdc37934SDmitry Chagin 
1082bdc37934SDmitry Chagin 	__elfN(linux_vdso_fixup)(&elf_linux_sysvec);
1083bdc37934SDmitry Chagin 
1084bdc37934SDmitry Chagin 	linux_shared_page_obj = __elfN(linux_shared_page_init)
1085bdc37934SDmitry Chagin 	    (&linux_shared_page_mapping);
1086bdc37934SDmitry Chagin 
1087bdc37934SDmitry Chagin 	__elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX32_SHAREDPAGE);
1088bdc37934SDmitry Chagin 
1089bdc37934SDmitry Chagin 	bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping,
1090bdc37934SDmitry Chagin 	    linux_szsigcode);
1091bdc37934SDmitry Chagin 	elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj;
10920020bdf1SDmitry Chagin 
10930020bdf1SDmitry Chagin 	linux_kplatform = linux_shared_page_mapping +
10940020bdf1SDmitry Chagin 	    (linux_platform - (caddr_t)LINUX32_SHAREDPAGE);
1095bdc37934SDmitry Chagin }
1096bdc37934SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY,
1097bdc37934SDmitry Chagin     (sysinit_cfunc_t)linux_vdso_install, NULL);
1098bdc37934SDmitry Chagin 
1099bdc37934SDmitry Chagin static void
1100bdc37934SDmitry Chagin linux_vdso_deinstall(void *param)
1101bdc37934SDmitry Chagin {
1102bdc37934SDmitry Chagin 
1103bdc37934SDmitry Chagin 	__elfN(linux_shared_page_fini)(linux_shared_page_obj);
1104bdc37934SDmitry Chagin };
1105bdc37934SDmitry Chagin SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST,
1106bdc37934SDmitry Chagin     (sysinit_cfunc_t)linux_vdso_deinstall, NULL);
1107ea0fabbcSTim J. Robbins 
110889ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU";
110989ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0;
111089ffc202SBjoern A. Zeeb 
111189ffc202SBjoern A. Zeeb static boolean_t
111289ffc202SBjoern A. Zeeb linux32_trans_osrel(const Elf_Note *note, int32_t *osrel)
111389ffc202SBjoern A. Zeeb {
111489ffc202SBjoern A. Zeeb 	const Elf32_Word *desc;
111589ffc202SBjoern A. Zeeb 	uintptr_t p;
111689ffc202SBjoern A. Zeeb 
111789ffc202SBjoern A. Zeeb 	p = (uintptr_t)(note + 1);
111889ffc202SBjoern A. Zeeb 	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
111989ffc202SBjoern A. Zeeb 
112089ffc202SBjoern A. Zeeb 	desc = (const Elf32_Word *)p;
112189ffc202SBjoern A. Zeeb 	if (desc[0] != GNULINUX_ABI_DESC)
112289ffc202SBjoern A. Zeeb 		return (FALSE);
112389ffc202SBjoern A. Zeeb 
112489ffc202SBjoern A. Zeeb 	/*
112589ffc202SBjoern A. Zeeb 	 * For linux we encode osrel as follows (see linux_mib.c):
112689ffc202SBjoern A. Zeeb 	 * VVVMMMIII (version, major, minor), see linux_mib.c.
112789ffc202SBjoern A. Zeeb 	 */
112889ffc202SBjoern A. Zeeb 	*osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3];
112989ffc202SBjoern A. Zeeb 
113089ffc202SBjoern A. Zeeb 	return (TRUE);
113189ffc202SBjoern A. Zeeb }
113232c01de2SDmitry Chagin 
113332c01de2SDmitry Chagin static Elf_Brandnote linux32_brandnote = {
113489ffc202SBjoern A. Zeeb 	.hdr.n_namesz	= sizeof(GNU_ABI_VENDOR),
113589ffc202SBjoern A. Zeeb 	.hdr.n_descsz	= 16,	/* XXX at least 16 */
113632c01de2SDmitry Chagin 	.hdr.n_type	= 1,
113789ffc202SBjoern A. Zeeb 	.vendor		= GNU_ABI_VENDOR,
113889ffc202SBjoern A. Zeeb 	.flags		= BN_TRANSLATE_OSREL,
113989ffc202SBjoern A. Zeeb 	.trans_osrel	= linux32_trans_osrel
114032c01de2SDmitry Chagin };
114132c01de2SDmitry Chagin 
1142ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = {
1143a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1144a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1145a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1146a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1147a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.1",
1148a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1149a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
115032c01de2SDmitry Chagin 	.brand_note	= &linux32_brandnote,
11512dedc128SDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
1152ea0fabbcSTim J. Robbins };
1153ea0fabbcSTim J. Robbins 
1154ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = {
1155a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1156a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1157a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1158a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1159a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.2",
1160a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1161a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
116232c01de2SDmitry Chagin 	.brand_note	= &linux32_brandnote,
11632dedc128SDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
1164ea0fabbcSTim J. Robbins };
1165ea0fabbcSTim J. Robbins 
1166ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = {
1167ea0fabbcSTim J. Robbins 	&linux_brand,
1168ea0fabbcSTim J. Robbins 	&linux_glibc2brand,
1169ea0fabbcSTim J. Robbins 	NULL
1170ea0fabbcSTim J. Robbins };
1171ea0fabbcSTim J. Robbins 
1172ea0fabbcSTim J. Robbins static int
1173ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data)
1174ea0fabbcSTim J. Robbins {
1175ea0fabbcSTim J. Robbins 	Elf32_Brandinfo **brandinfo;
1176ea0fabbcSTim J. Robbins 	int error;
1177ea0fabbcSTim J. Robbins 	struct linux_ioctl_handler **lihp;
1178ea0fabbcSTim J. Robbins 
1179ea0fabbcSTim J. Robbins 	error = 0;
1180ea0fabbcSTim J. Robbins 
1181ea0fabbcSTim J. Robbins 	switch(type) {
1182ea0fabbcSTim J. Robbins 	case MOD_LOAD:
1183ea0fabbcSTim J. Robbins 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1184ea0fabbcSTim J. Robbins 		     ++brandinfo)
1185ea0fabbcSTim J. Robbins 			if (elf32_insert_brand_entry(*brandinfo) < 0)
1186ea0fabbcSTim J. Robbins 				error = EINVAL;
1187ea0fabbcSTim J. Robbins 		if (error == 0) {
1188ea0fabbcSTim J. Robbins 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1189ea0fabbcSTim J. Robbins 				linux_ioctl_register_handler(*lihp);
11907c09e6c0SAlexander Leidinger 			LIST_INIT(&futex_list);
119179262bf1SDmitry Chagin 			mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF);
11921ca16454SDmitry Chagin 			stclohz = (stathz ? stathz : hz);
1193ea0fabbcSTim J. Robbins 			if (bootverbose)
1194ea0fabbcSTim J. Robbins 				printf("Linux ELF exec handler installed\n");
1195ea0fabbcSTim J. Robbins 		} else
1196ea0fabbcSTim J. Robbins 			printf("cannot insert Linux ELF brand handler\n");
1197ea0fabbcSTim J. Robbins 		break;
1198ea0fabbcSTim J. Robbins 	case MOD_UNLOAD:
1199ea0fabbcSTim J. Robbins 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1200ea0fabbcSTim J. Robbins 		     ++brandinfo)
1201ea0fabbcSTim J. Robbins 			if (elf32_brand_inuse(*brandinfo))
1202ea0fabbcSTim J. Robbins 				error = EBUSY;
1203ea0fabbcSTim J. Robbins 		if (error == 0) {
1204ea0fabbcSTim J. Robbins 			for (brandinfo = &linux_brandlist[0];
1205ea0fabbcSTim J. Robbins 			     *brandinfo != NULL; ++brandinfo)
1206ea0fabbcSTim J. Robbins 				if (elf32_remove_brand_entry(*brandinfo) < 0)
1207ea0fabbcSTim J. Robbins 					error = EINVAL;
1208ea0fabbcSTim J. Robbins 		}
1209ea0fabbcSTim J. Robbins 		if (error == 0) {
1210ea0fabbcSTim J. Robbins 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1211ea0fabbcSTim J. Robbins 				linux_ioctl_unregister_handler(*lihp);
121279262bf1SDmitry Chagin 			mtx_destroy(&futex_mtx);
1213ea0fabbcSTim J. Robbins 			if (bootverbose)
1214ea0fabbcSTim J. Robbins 				printf("Linux ELF exec handler removed\n");
1215ea0fabbcSTim J. Robbins 		} else
1216ea0fabbcSTim J. Robbins 			printf("Could not deinstall ELF interpreter entry\n");
1217ea0fabbcSTim J. Robbins 		break;
1218ea0fabbcSTim J. Robbins 	default:
1219af682d48SDmitry Chagin 		return (EOPNOTSUPP);
1220ea0fabbcSTim J. Robbins 	}
1221af682d48SDmitry Chagin 	return (error);
1222ea0fabbcSTim J. Robbins }
1223ea0fabbcSTim J. Robbins 
1224ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = {
1225ea0fabbcSTim J. Robbins 	"linuxelf",
1226ea0fabbcSTim J. Robbins 	linux_elf_modevent,
12279823d527SKevin Lo 	0
1228ea0fabbcSTim J. Robbins };
1229ea0fabbcSTim J. Robbins 
123078ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
123167d39748SDmitry Chagin MODULE_DEPEND(linuxelf, linux_common, 1, 1, 1);
1232