xref: /freebsd/sys/amd64/linux32/linux32_sysvec.c (revision bdc379344aee7b07ea84d4da61a4f228b72f8079)
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>
86*bdc37934SDmitry Chagin #include <compat/linux/linux_vdso.h>
87ea0fabbcSTim J. Robbins 
88ea0fabbcSTim J. Robbins MODULE_VERSION(linux, 1);
89ea0fabbcSTim J. Robbins 
90ea0fabbcSTim J. Robbins MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
91ea0fabbcSTim J. Robbins 
92ea0fabbcSTim J. Robbins #define	AUXARGS_ENTRY_32(pos, id, val)	\
93ea0fabbcSTim J. Robbins 	do {				\
94ea0fabbcSTim J. Robbins 		suword32(pos++, id);	\
95ea0fabbcSTim J. Robbins 		suword32(pos++, val);	\
96ea0fabbcSTim J. Robbins 	} while (0)
97ea0fabbcSTim J. Robbins 
98ea0fabbcSTim J. Robbins #if BYTE_ORDER == LITTLE_ENDIAN
99ea0fabbcSTim J. Robbins #define SHELLMAGIC      0x2123 /* #! */
100ea0fabbcSTim J. Robbins #else
101ea0fabbcSTim J. Robbins #define SHELLMAGIC      0x2321
102ea0fabbcSTim J. Robbins #endif
103ea0fabbcSTim J. Robbins 
104ea0fabbcSTim J. Robbins /*
105ea0fabbcSTim J. Robbins  * Allow the sendsig functions to use the ldebug() facility
106ea0fabbcSTim J. Robbins  * even though they are not syscalls themselves. Map them
107ea0fabbcSTim J. Robbins  * to syscall 0. This is slightly less bogus than using
108ea0fabbcSTim J. Robbins  * ldebug(sigreturn).
109ea0fabbcSTim J. Robbins  */
110ea0fabbcSTim J. Robbins #define	LINUX_SYS_linux_rt_sendsig	0
111ea0fabbcSTim J. Robbins #define	LINUX_SYS_linux_sendsig		0
112ea0fabbcSTim J. Robbins 
1134d7c2e8aSDmitry Chagin const char *linux_platform = "i686";
1144d7c2e8aSDmitry Chagin static int linux_szplatform;
115*bdc37934SDmitry Chagin static int linux_szsigcode;
116*bdc37934SDmitry Chagin static vm_object_t linux_shared_page_obj;
117*bdc37934SDmitry Chagin static char *linux_shared_page_mapping;
118*bdc37934SDmitry Chagin extern char _binary_linux32_locore_o_start;
119*bdc37934SDmitry Chagin extern char _binary_linux32_locore_o_end;
120ea0fabbcSTim J. Robbins 
121ea0fabbcSTim J. Robbins extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
122ea0fabbcSTim J. Robbins 
123ea0fabbcSTim J. Robbins SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
124387196bfSDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
125ea0fabbcSTim J. Robbins 
126ea0fabbcSTim J. Robbins static int	elf_linux_fixup(register_t **stack_base,
127ea0fabbcSTim J. Robbins 		    struct image_params *iparams);
128ea0fabbcSTim J. Robbins static register_t *linux_copyout_strings(struct image_params *imgp);
1299104847fSDavid Xu static void     linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
130a107d8aaSNathan Whitehorn static void	exec_linux_setregs(struct thread *td,
131a107d8aaSNathan Whitehorn 				   struct image_params *imgp, u_long stack);
13219059a13SJohn Baldwin static void	linux32_fixlimit(struct rlimit *rl, int which);
13389ffc202SBjoern A. Zeeb static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel);
134*bdc37934SDmitry Chagin static void	linux_vdso_install(void *param);
135*bdc37934SDmitry Chagin static void	linux_vdso_deinstall(void *param);
136ea0fabbcSTim J. Robbins 
1377c09e6c0SAlexander Leidinger static eventhandler_tag linux_exit_tag;
1387c09e6c0SAlexander Leidinger static eventhandler_tag linux_exec_tag;
13981338031SDmitry Chagin static eventhandler_tag linux_thread_dtor_tag;
1407c09e6c0SAlexander Leidinger 
141ea0fabbcSTim J. Robbins /*
142ea0fabbcSTim J. Robbins  * Linux syscalls return negative errno's, we do positive and map them
14350e422f0SAlexander Leidinger  * Reference:
14450e422f0SAlexander Leidinger  *   FreeBSD: src/sys/sys/errno.h
14550e422f0SAlexander Leidinger  *   Linux:   linux-2.6.17.8/include/asm-generic/errno-base.h
14650e422f0SAlexander Leidinger  *            linux-2.6.17.8/include/asm-generic/errno.h
147ea0fabbcSTim J. Robbins  */
148ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = {
149ea0fabbcSTim J. Robbins 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
150ea0fabbcSTim J. Robbins 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
151ea0fabbcSTim J. Robbins 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
152ea0fabbcSTim J. Robbins 	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
153ea0fabbcSTim J. Robbins 	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
154ea0fabbcSTim J. Robbins 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
155ea0fabbcSTim J. Robbins 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
156ea0fabbcSTim J. Robbins 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
15750e422f0SAlexander Leidinger 	  -6,  -6, -43, -42, -75,-125, -84, -95, -16, -74,
15850e422f0SAlexander Leidinger 	 -72, -67, -71
159ea0fabbcSTim J. Robbins };
160ea0fabbcSTim J. Robbins 
161ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
162ea0fabbcSTim J. Robbins 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
163ea0fabbcSTim J. Robbins 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
164ea0fabbcSTim J. Robbins 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
165ea0fabbcSTim J. Robbins 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
166ea0fabbcSTim J. Robbins 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
167ea0fabbcSTim J. Robbins 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
168ea0fabbcSTim J. Robbins 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
169ea0fabbcSTim J. Robbins 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
170ea0fabbcSTim J. Robbins };
171ea0fabbcSTim J. Robbins 
172ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
173ea0fabbcSTim J. Robbins 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
174ea0fabbcSTim J. Robbins 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
175ea0fabbcSTim J. Robbins 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
176ea0fabbcSTim J. Robbins 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
177ea0fabbcSTim J. Robbins 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
178ea0fabbcSTim J. Robbins 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
179ea0fabbcSTim J. Robbins 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
180ea0fabbcSTim J. Robbins 	SIGIO, SIGURG, SIGSYS
181ea0fabbcSTim J. Robbins };
182ea0fabbcSTim J. Robbins 
183ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN  255
184ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = {
185ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 0 */
186ea0fabbcSTim J. Robbins 	6,			/* 1  T_PRIVINFLT */
187ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 2 */
188ea0fabbcSTim J. Robbins 	3,			/* 3  T_BPTFLT */
189ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 4 */
190ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 5 */
191ea0fabbcSTim J. Robbins 	16,			/* 6  T_ARITHTRAP */
192ea0fabbcSTim J. Robbins 	254,			/* 7  T_ASTFLT */
193ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 8 */
194ea0fabbcSTim J. Robbins 	13,			/* 9  T_PROTFLT */
195ea0fabbcSTim J. Robbins 	1,			/* 10 T_TRCTRAP */
196ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 11 */
197ea0fabbcSTim J. Robbins 	14,			/* 12 T_PAGEFLT */
198ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 13 */
199ea0fabbcSTim J. Robbins 	17,			/* 14 T_ALIGNFLT */
200ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 15 */
201ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 16 */
202ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 17 */
203ea0fabbcSTim J. Robbins 	0,			/* 18 T_DIVIDE */
204ea0fabbcSTim J. Robbins 	2,			/* 19 T_NMI */
205ea0fabbcSTim J. Robbins 	4,			/* 20 T_OFLOW */
206ea0fabbcSTim J. Robbins 	5,			/* 21 T_BOUND */
207ea0fabbcSTim J. Robbins 	7,			/* 22 T_DNA */
208ea0fabbcSTim J. Robbins 	8,			/* 23 T_DOUBLEFLT */
209ea0fabbcSTim J. Robbins 	9,			/* 24 T_FPOPFLT */
210ea0fabbcSTim J. Robbins 	10,			/* 25 T_TSSFLT */
211ea0fabbcSTim J. Robbins 	11,			/* 26 T_SEGNPFLT */
212ea0fabbcSTim J. Robbins 	12,			/* 27 T_STKFLT */
213ea0fabbcSTim J. Robbins 	18,			/* 28 T_MCHK */
214ea0fabbcSTim J. Robbins 	19,			/* 29 T_XMMFLT */
215ea0fabbcSTim J. Robbins 	15			/* 30 T_RESERVED */
216ea0fabbcSTim J. Robbins };
217ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \
218ea0fabbcSTim J. Robbins     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
219ea0fabbcSTim J. Robbins      _bsd_to_linux_trapcode[(code)]: \
220ea0fabbcSTim J. Robbins      LINUX_T_UNKNOWN)
221ea0fabbcSTim J. Robbins 
222ea0fabbcSTim J. Robbins struct linux32_ps_strings {
223ea0fabbcSTim J. Robbins 	u_int32_t ps_argvstr;	/* first of 0 or more argument strings */
224f2c7668eSDavid Schultz 	u_int ps_nargvstr;	/* the number of argument strings */
225ea0fabbcSTim J. Robbins 	u_int32_t ps_envstr;	/* first of 0 or more environment strings */
226f2c7668eSDavid Schultz 	u_int ps_nenvstr;	/* the number of environment strings */
227ea0fabbcSTim J. Robbins };
228ea0fabbcSTim J. Robbins 
229*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_sigcode);
230*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_rt_sigcode);
231*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux32_vsyscall);
232*bdc37934SDmitry Chagin 
233ea0fabbcSTim J. Robbins /*
234ea0fabbcSTim J. Robbins  * If FreeBSD & Linux have a difference of opinion about what a trap
235ea0fabbcSTim J. Robbins  * means, deal with it here.
236ea0fabbcSTim J. Robbins  *
237ea0fabbcSTim J. Robbins  * MPSAFE
238ea0fabbcSTim J. Robbins  */
239ea0fabbcSTim J. Robbins static int
240ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code)
241ea0fabbcSTim J. Robbins {
242ea0fabbcSTim J. Robbins 	if (signal != SIGBUS)
243ea0fabbcSTim J. Robbins 		return signal;
244ea0fabbcSTim J. Robbins 	switch (trap_code) {
245ea0fabbcSTim J. Robbins 	case T_PROTFLT:
246ea0fabbcSTim J. Robbins 	case T_TSSFLT:
247ea0fabbcSTim J. Robbins 	case T_DOUBLEFLT:
248ea0fabbcSTim J. Robbins 	case T_PAGEFLT:
249ea0fabbcSTim J. Robbins 		return SIGSEGV;
250ea0fabbcSTim J. Robbins 	default:
251ea0fabbcSTim J. Robbins 		return signal;
252ea0fabbcSTim J. Robbins 	}
253ea0fabbcSTim J. Robbins }
254ea0fabbcSTim J. Robbins 
255ea0fabbcSTim J. Robbins static int
256ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
257ea0fabbcSTim J. Robbins {
258ea0fabbcSTim J. Robbins 	Elf32_Auxargs *args;
259ea0fabbcSTim J. Robbins 	Elf32_Addr *base;
2604d7c2e8aSDmitry Chagin 	Elf32_Addr *pos, *uplatform;
2614d7c2e8aSDmitry Chagin 	struct linux32_ps_strings *arginfo;
2624d7c2e8aSDmitry Chagin 
2634d7c2e8aSDmitry Chagin 	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
264acface68SDmitry Chagin 	uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
265ea0fabbcSTim J. Robbins 
2666617724cSJeff Roberson 	KASSERT(curthread->td_proc == imgp->proc,
267ea0fabbcSTim J. Robbins 	    ("unsafe elf_linux_fixup(), should be curproc"));
268ea0fabbcSTim J. Robbins 	base = (Elf32_Addr *)*stack_base;
269ea0fabbcSTim J. Robbins 	args = (Elf32_Auxargs *)imgp->auxargs;
270610ecfe0SMaxim Sobolev 	pos = base + (imgp->args->argc + imgp->args->envc + 2);
271ea0fabbcSTim J. Robbins 
272*bdc37934SDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO_EHDR,
273*bdc37934SDmitry Chagin 	    imgp->proc->p_sysent->sv_shared_page_base);
274*bdc37934SDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_SYSINFO, linux32_vsyscall);
2754d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);
2768d30f381SDmitry Chagin 
2778d30f381SDmitry Chagin 	/*
2788d30f381SDmitry Chagin 	 * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0,
2798d30f381SDmitry Chagin 	 * as it has appeared in the 2.4.0-rc7 first time.
2808d30f381SDmitry Chagin 	 * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK),
2818d30f381SDmitry Chagin 	 * glibc falls back to the hard-coded CLK_TCK value when aux entry
2828d30f381SDmitry Chagin 	 * is not present.
2838d30f381SDmitry Chagin 	 * Also see linux_times() implementation.
2848d30f381SDmitry Chagin 	 */
2858d30f381SDmitry Chagin 	if (linux_kernver(curthread) >= LINUX_KERNVER_2004000)
2861ca16454SDmitry Chagin 		AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz);
287ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr);
288ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent);
289ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum);
290ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz);
291ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags);
292ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry);
293ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_BASE, args->base);
2944d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0);
295ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
296ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
297ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
298ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
2994d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
3004d7c2e8aSDmitry Chagin 	if (args->execfd != -1)
3014d7c2e8aSDmitry Chagin 		AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
302ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_NULL, 0);
303ea0fabbcSTim J. Robbins 
304ea0fabbcSTim J. Robbins 	free(imgp->auxargs, M_TEMP);
305ea0fabbcSTim J. Robbins 	imgp->auxargs = NULL;
306ea0fabbcSTim J. Robbins 
307ea0fabbcSTim J. Robbins 	base--;
308610ecfe0SMaxim Sobolev 	suword32(base, (uint32_t)imgp->args->argc);
309ea0fabbcSTim J. Robbins 	*stack_base = (register_t *)base;
310af682d48SDmitry Chagin 	return (0);
311ea0fabbcSTim J. Robbins }
312ea0fabbcSTim J. Robbins 
313ea0fabbcSTim J. Robbins static void
3149104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
315ea0fabbcSTim J. Robbins {
316ea0fabbcSTim J. Robbins 	struct thread *td = curthread;
317ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
318ea0fabbcSTim J. Robbins 	struct sigacts *psp;
319ea0fabbcSTim J. Robbins 	struct trapframe *regs;
320ea0fabbcSTim J. Robbins 	struct l_rt_sigframe *fp, frame;
321ea0fabbcSTim J. Robbins 	int oonstack;
3229104847fSDavid Xu 	int sig;
3239104847fSDavid Xu 	int code;
324ea0fabbcSTim J. Robbins 
3259104847fSDavid Xu 	sig = ksi->ksi_signo;
3269104847fSDavid Xu 	code = ksi->ksi_code;
327ea0fabbcSTim J. Robbins 	PROC_LOCK_ASSERT(p, MA_OWNED);
328ea0fabbcSTim J. Robbins 	psp = p->p_sigacts;
329ea0fabbcSTim J. Robbins 	mtx_assert(&psp->ps_mtx, MA_OWNED);
330ea0fabbcSTim J. Robbins 	regs = td->td_frame;
331ea0fabbcSTim J. Robbins 	oonstack = sigonstack(regs->tf_rsp);
332ea0fabbcSTim J. Robbins 
333ea0fabbcSTim J. Robbins #ifdef DEBUG
334ea0fabbcSTim J. Robbins 	if (ldebug(rt_sendsig))
335728ef954SJohn Baldwin 		printf(ARGS(rt_sendsig, "%p, %d, %p, %u"),
336ea0fabbcSTim J. Robbins 		    catcher, sig, (void*)mask, code);
337ea0fabbcSTim J. Robbins #endif
338ea0fabbcSTim J. Robbins 	/*
339ea0fabbcSTim J. Robbins 	 * Allocate space for the signal handler context.
340ea0fabbcSTim J. Robbins 	 */
341ea0fabbcSTim J. Robbins 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
342ea0fabbcSTim J. Robbins 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
343ea0fabbcSTim J. Robbins 		fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp +
344ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe));
345ea0fabbcSTim J. Robbins 	} else
346ea0fabbcSTim J. Robbins 		fp = (struct l_rt_sigframe *)regs->tf_rsp - 1;
347ea0fabbcSTim J. Robbins 	mtx_unlock(&psp->ps_mtx);
348ea0fabbcSTim J. Robbins 
349ea0fabbcSTim J. Robbins 	/*
350ea0fabbcSTim J. Robbins 	 * Build the argument list for the signal handler.
351ea0fabbcSTim J. Robbins 	 */
352ea0fabbcSTim J. Robbins 	if (p->p_sysent->sv_sigtbl)
353ea0fabbcSTim J. Robbins 		if (sig <= p->p_sysent->sv_sigsize)
354ea0fabbcSTim J. Robbins 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
355ea0fabbcSTim J. Robbins 
356ea0fabbcSTim J. Robbins 	bzero(&frame, sizeof(frame));
357ea0fabbcSTim J. Robbins 
358ea0fabbcSTim J. Robbins 	frame.sf_handler = PTROUT(catcher);
359ea0fabbcSTim J. Robbins 	frame.sf_sig = sig;
360ea0fabbcSTim J. Robbins 	frame.sf_siginfo = PTROUT(&fp->sf_si);
361ea0fabbcSTim J. Robbins 	frame.sf_ucontext = PTROUT(&fp->sf_sc);
362ea0fabbcSTim J. Robbins 
363ea0fabbcSTim J. Robbins 	/* Fill in POSIX parts */
364aa8b2011SKonstantin Belousov 	ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig);
365ea0fabbcSTim J. Robbins 
366ea0fabbcSTim J. Robbins 	/*
367*bdc37934SDmitry Chagin 	 * Build the signal context to be used by sigreturn
368*bdc37934SDmitry Chagin 	 * and libgcc unwind.
369ea0fabbcSTim J. Robbins 	 */
370ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
371ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_link = 0;		/* XXX ??? */
372ea0fabbcSTim J. Robbins 
373ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp);
374ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size;
375ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
376ea0fabbcSTim J. Robbins 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
377ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
378ea0fabbcSTim J. Robbins 
379ea0fabbcSTim J. Robbins 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
380ea0fabbcSTim J. Robbins 
381ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
382ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_rdi;
383ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_rsi;
384ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_rbp;
385ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_rbx;
386*bdc37934SDmitry Chagin 	frame.sf_sc.uc_mcontext.sc_esp    = regs->tf_rsp;
387ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_rdx;
388ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_rcx;
389ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_rax;
390ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_rip;
391ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
3922c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_gs     = regs->tf_gs;
3932c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
3942c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
3952c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
396ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags;
397ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp;
398ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
399ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
40096a2b635SKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_cr2    = (u_int32_t)(uintptr_t)ksi->ksi_addr;
401ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
402ea0fabbcSTim J. Robbins 
403ea0fabbcSTim J. Robbins #ifdef DEBUG
404ea0fabbcSTim J. Robbins 	if (ldebug(rt_sendsig))
405c680f6b1SDavid E. O'Brien 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"),
406ea0fabbcSTim J. Robbins 		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
407ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
408ea0fabbcSTim J. Robbins #endif
409ea0fabbcSTim J. Robbins 
410ea0fabbcSTim J. Robbins 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
411ea0fabbcSTim J. Robbins 		/*
412ea0fabbcSTim J. Robbins 		 * Process has trashed its stack; give it an illegal
413ea0fabbcSTim J. Robbins 		 * instruction to halt it in its tracks.
414ea0fabbcSTim J. Robbins 		 */
415ea0fabbcSTim J. Robbins #ifdef DEBUG
416ea0fabbcSTim J. Robbins 		if (ldebug(rt_sendsig))
417ea0fabbcSTim J. Robbins 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
418ea0fabbcSTim J. Robbins 			    fp, oonstack);
419ea0fabbcSTim J. Robbins #endif
420ea0fabbcSTim J. Robbins 		PROC_LOCK(p);
421ea0fabbcSTim J. Robbins 		sigexit(td, SIGILL);
422ea0fabbcSTim J. Robbins 	}
423ea0fabbcSTim J. Robbins 
424ea0fabbcSTim J. Robbins 	/*
425ea0fabbcSTim J. Robbins 	 * Build context to run handler in.
426ea0fabbcSTim J. Robbins 	 */
427ea0fabbcSTim J. Robbins 	regs->tf_rsp = PTROUT(fp);
428*bdc37934SDmitry Chagin 	regs->tf_rip = linux32_rt_sigcode;
42922eca0bfSKonstantin Belousov 	regs->tf_rflags &= ~(PSL_T | PSL_D);
430ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
431ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
4322c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
4332c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
4342c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
4352c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
4362c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
437e6c006d9SJung-uk Kim 	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
438ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
439ea0fabbcSTim J. Robbins 	mtx_lock(&psp->ps_mtx);
440ea0fabbcSTim J. Robbins }
441ea0fabbcSTim J. Robbins 
442ea0fabbcSTim J. Robbins 
443ea0fabbcSTim J. Robbins /*
444ea0fabbcSTim J. Robbins  * Send an interrupt to process.
445ea0fabbcSTim J. Robbins  *
446ea0fabbcSTim J. Robbins  * Stack is set up to allow sigcode stored
447ea0fabbcSTim J. Robbins  * in u. to call routine, followed by kcall
448ea0fabbcSTim J. Robbins  * to sigreturn routine below.  After sigreturn
449ea0fabbcSTim J. Robbins  * resets the signal mask, the stack, and the
450ea0fabbcSTim J. Robbins  * frame pointer, it returns to the user
451ea0fabbcSTim J. Robbins  * specified pc, psl.
452ea0fabbcSTim J. Robbins  */
453ea0fabbcSTim J. Robbins static void
4549104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
455ea0fabbcSTim J. Robbins {
456ea0fabbcSTim J. Robbins 	struct thread *td = curthread;
457ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
458ea0fabbcSTim J. Robbins 	struct sigacts *psp;
459ea0fabbcSTim J. Robbins 	struct trapframe *regs;
460ea0fabbcSTim J. Robbins 	struct l_sigframe *fp, frame;
461ea0fabbcSTim J. Robbins 	l_sigset_t lmask;
462ea0fabbcSTim J. Robbins 	int oonstack, i;
4639104847fSDavid Xu 	int sig, code;
464ea0fabbcSTim J. Robbins 
4659104847fSDavid Xu 	sig = ksi->ksi_signo;
4669104847fSDavid Xu 	code = ksi->ksi_code;
467ea0fabbcSTim J. Robbins 	PROC_LOCK_ASSERT(p, MA_OWNED);
468ea0fabbcSTim J. Robbins 	psp = p->p_sigacts;
469ea0fabbcSTim J. Robbins 	mtx_assert(&psp->ps_mtx, MA_OWNED);
470ea0fabbcSTim J. Robbins 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
471ea0fabbcSTim J. Robbins 		/* Signal handler installed with SA_SIGINFO. */
4729104847fSDavid Xu 		linux_rt_sendsig(catcher, ksi, mask);
473ea0fabbcSTim J. Robbins 		return;
474ea0fabbcSTim J. Robbins 	}
475ea0fabbcSTim J. Robbins 
476ea0fabbcSTim J. Robbins 	regs = td->td_frame;
477ea0fabbcSTim J. Robbins 	oonstack = sigonstack(regs->tf_rsp);
478ea0fabbcSTim J. Robbins 
479ea0fabbcSTim J. Robbins #ifdef DEBUG
480ea0fabbcSTim J. Robbins 	if (ldebug(sendsig))
481728ef954SJohn Baldwin 		printf(ARGS(sendsig, "%p, %d, %p, %u"),
482ea0fabbcSTim J. Robbins 		    catcher, sig, (void*)mask, code);
483ea0fabbcSTim J. Robbins #endif
484ea0fabbcSTim J. Robbins 
485ea0fabbcSTim J. Robbins 	/*
486ea0fabbcSTim J. Robbins 	 * Allocate space for the signal handler context.
487ea0fabbcSTim J. Robbins 	 */
488ea0fabbcSTim J. Robbins 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
489ea0fabbcSTim J. Robbins 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
490ea0fabbcSTim J. Robbins 		fp = (struct l_sigframe *)(td->td_sigstk.ss_sp +
491ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size - sizeof(struct l_sigframe));
492ea0fabbcSTim J. Robbins 	} else
493ea0fabbcSTim J. Robbins 		fp = (struct l_sigframe *)regs->tf_rsp - 1;
494ea0fabbcSTim J. Robbins 	mtx_unlock(&psp->ps_mtx);
495ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
496ea0fabbcSTim J. Robbins 
497ea0fabbcSTim J. Robbins 	/*
498ea0fabbcSTim J. Robbins 	 * Build the argument list for the signal handler.
499ea0fabbcSTim J. Robbins 	 */
500ea0fabbcSTim J. Robbins 	if (p->p_sysent->sv_sigtbl)
501ea0fabbcSTim J. Robbins 		if (sig <= p->p_sysent->sv_sigsize)
502ea0fabbcSTim J. Robbins 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
503ea0fabbcSTim J. Robbins 
504ea0fabbcSTim J. Robbins 	bzero(&frame, sizeof(frame));
505ea0fabbcSTim J. Robbins 
506ea0fabbcSTim J. Robbins 	frame.sf_handler = PTROUT(catcher);
507ea0fabbcSTim J. Robbins 	frame.sf_sig = sig;
508ea0fabbcSTim J. Robbins 
509ea0fabbcSTim J. Robbins 	bsd_to_linux_sigset(mask, &lmask);
510ea0fabbcSTim J. Robbins 
511ea0fabbcSTim J. Robbins 	/*
512ea0fabbcSTim J. Robbins 	 * Build the signal context to be used by sigreturn.
513ea0fabbcSTim J. Robbins 	 */
514ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_mask   = lmask.__bits[0];
5152c66cccaSKonstantin Belousov 	frame.sf_sc.sc_gs     = regs->tf_gs;
5162c66cccaSKonstantin Belousov 	frame.sf_sc.sc_fs     = regs->tf_fs;
5172c66cccaSKonstantin Belousov 	frame.sf_sc.sc_es     = regs->tf_es;
5182c66cccaSKonstantin Belousov 	frame.sf_sc.sc_ds     = regs->tf_ds;
519ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_edi    = regs->tf_rdi;
520ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_esi    = regs->tf_rsi;
521ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ebp    = regs->tf_rbp;
522ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ebx    = regs->tf_rbx;
523*bdc37934SDmitry Chagin 	frame.sf_sc.sc_esp    = regs->tf_rsp;
524ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_edx    = regs->tf_rdx;
525ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ecx    = regs->tf_rcx;
526ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eax    = regs->tf_rax;
527ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eip    = regs->tf_rip;
528ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_cs     = regs->tf_cs;
529ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eflags = regs->tf_rflags;
530ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_esp_at_signal = regs->tf_rsp;
531ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ss     = regs->tf_ss;
532ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_err    = regs->tf_err;
53396a2b635SKonstantin Belousov 	frame.sf_sc.sc_cr2    = (u_int32_t)(uintptr_t)ksi->ksi_addr;
534ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code);
535ea0fabbcSTim J. Robbins 
536ea0fabbcSTim J. Robbins 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
537ea0fabbcSTim J. Robbins 		frame.sf_extramask[i] = lmask.__bits[i+1];
538ea0fabbcSTim J. Robbins 
539ea0fabbcSTim J. Robbins 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
540ea0fabbcSTim J. Robbins 		/*
541ea0fabbcSTim J. Robbins 		 * Process has trashed its stack; give it an illegal
542ea0fabbcSTim J. Robbins 		 * instruction to halt it in its tracks.
543ea0fabbcSTim J. Robbins 		 */
544ea0fabbcSTim J. Robbins 		PROC_LOCK(p);
545ea0fabbcSTim J. Robbins 		sigexit(td, SIGILL);
546ea0fabbcSTim J. Robbins 	}
547ea0fabbcSTim J. Robbins 
548ea0fabbcSTim J. Robbins 	/*
549ea0fabbcSTim J. Robbins 	 * Build context to run handler in.
550ea0fabbcSTim J. Robbins 	 */
551ea0fabbcSTim J. Robbins 	regs->tf_rsp = PTROUT(fp);
552*bdc37934SDmitry Chagin 	regs->tf_rip = linux32_sigcode;
55322eca0bfSKonstantin Belousov 	regs->tf_rflags &= ~(PSL_T | PSL_D);
554ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
555ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
5562c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
5572c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
5582c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
5592c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
5602c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
561e6c006d9SJung-uk Kim 	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
562ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
563ea0fabbcSTim J. Robbins 	mtx_lock(&psp->ps_mtx);
564ea0fabbcSTim J. Robbins }
565ea0fabbcSTim J. Robbins 
566ea0fabbcSTim J. Robbins /*
567ea0fabbcSTim J. Robbins  * System call to cleanup state after a signal
568ea0fabbcSTim J. Robbins  * has been taken.  Reset signal mask and
569ea0fabbcSTim J. Robbins  * stack state from context left by sendsig (above).
570ea0fabbcSTim J. Robbins  * Return to previous pc and psl as specified by
571ea0fabbcSTim J. Robbins  * context left by sendsig. Check carefully to
572ea0fabbcSTim J. Robbins  * make sure that the user has not modified the
573ea0fabbcSTim J. Robbins  * psl to gain improper privileges or to cause
574ea0fabbcSTim J. Robbins  * a machine fault.
575ea0fabbcSTim J. Robbins  */
576ea0fabbcSTim J. Robbins int
577ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
578ea0fabbcSTim J. Robbins {
579ea0fabbcSTim J. Robbins 	struct l_sigframe frame;
580ea0fabbcSTim J. Robbins 	struct trapframe *regs;
581d6e029adSKonstantin Belousov 	sigset_t bmask;
582ea0fabbcSTim J. Robbins 	l_sigset_t lmask;
583ea0fabbcSTim J. Robbins 	int eflags, i;
5849104847fSDavid Xu 	ksiginfo_t ksi;
585ea0fabbcSTim J. Robbins 
586ea0fabbcSTim J. Robbins 	regs = td->td_frame;
587ea0fabbcSTim J. Robbins 
588ea0fabbcSTim J. Robbins #ifdef DEBUG
589ea0fabbcSTim J. Robbins 	if (ldebug(sigreturn))
590ea0fabbcSTim J. Robbins 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
591ea0fabbcSTim J. Robbins #endif
592ea0fabbcSTim J. Robbins 	/*
593ea0fabbcSTim J. Robbins 	 * The trampoline code hands us the sigframe.
594ea0fabbcSTim J. Robbins 	 * It is unsafe to keep track of it ourselves, in the event that a
595ea0fabbcSTim J. Robbins 	 * program jumps out of a signal handler.
596ea0fabbcSTim J. Robbins 	 */
597ea0fabbcSTim J. Robbins 	if (copyin(args->sfp, &frame, sizeof(frame)) != 0)
598ea0fabbcSTim J. Robbins 		return (EFAULT);
599ea0fabbcSTim J. Robbins 
600ea0fabbcSTim J. Robbins 	/*
601ea0fabbcSTim J. Robbins 	 * Check for security violations.
602ea0fabbcSTim J. Robbins 	 */
603ea0fabbcSTim J. Robbins #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
604ea0fabbcSTim J. Robbins 	eflags = frame.sf_sc.sc_eflags;
6053d271aaaSEd Maste 	if (!EFLAGS_SECURE(eflags, regs->tf_rflags))
606ea0fabbcSTim J. Robbins 		return(EINVAL);
607ea0fabbcSTim J. Robbins 
608ea0fabbcSTim J. Robbins 	/*
609ea0fabbcSTim J. Robbins 	 * Don't allow users to load a valid privileged %cs.  Let the
610ea0fabbcSTim J. Robbins 	 * hardware check for invalid selectors, excess privilege in
611ea0fabbcSTim J. Robbins 	 * other selectors, invalid %eip's and invalid %esp's.
612ea0fabbcSTim J. Robbins 	 */
613ea0fabbcSTim J. Robbins #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
614ea0fabbcSTim J. Robbins 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
6159104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
6169104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
6179104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
6189104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
6199104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_rip;
6209104847fSDavid Xu 		trapsignal(td, &ksi);
621ea0fabbcSTim J. Robbins 		return(EINVAL);
622ea0fabbcSTim J. Robbins 	}
623ea0fabbcSTim J. Robbins 
624ea0fabbcSTim J. Robbins 	lmask.__bits[0] = frame.sf_sc.sc_mask;
625ea0fabbcSTim J. Robbins 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
626ea0fabbcSTim J. Robbins 		lmask.__bits[i+1] = frame.sf_extramask[i];
627d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&lmask, &bmask);
628d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
629ea0fabbcSTim J. Robbins 
630ea0fabbcSTim J. Robbins 	/*
631ea0fabbcSTim J. Robbins 	 * Restore signal context.
632ea0fabbcSTim J. Robbins 	 */
633ea0fabbcSTim J. Robbins 	regs->tf_rdi    = frame.sf_sc.sc_edi;
634ea0fabbcSTim J. Robbins 	regs->tf_rsi    = frame.sf_sc.sc_esi;
635ea0fabbcSTim J. Robbins 	regs->tf_rbp    = frame.sf_sc.sc_ebp;
636ea0fabbcSTim J. Robbins 	regs->tf_rbx    = frame.sf_sc.sc_ebx;
637ea0fabbcSTim J. Robbins 	regs->tf_rdx    = frame.sf_sc.sc_edx;
638ea0fabbcSTim J. Robbins 	regs->tf_rcx    = frame.sf_sc.sc_ecx;
639ea0fabbcSTim J. Robbins 	regs->tf_rax    = frame.sf_sc.sc_eax;
640ea0fabbcSTim J. Robbins 	regs->tf_rip    = frame.sf_sc.sc_eip;
641ea0fabbcSTim J. Robbins 	regs->tf_cs     = frame.sf_sc.sc_cs;
6422c66cccaSKonstantin Belousov 	regs->tf_ds     = frame.sf_sc.sc_ds;
6432c66cccaSKonstantin Belousov 	regs->tf_es     = frame.sf_sc.sc_es;
6442c66cccaSKonstantin Belousov 	regs->tf_fs     = frame.sf_sc.sc_fs;
6452c66cccaSKonstantin Belousov 	regs->tf_gs     = frame.sf_sc.sc_gs;
646ea0fabbcSTim J. Robbins 	regs->tf_rflags = eflags;
647ea0fabbcSTim J. Robbins 	regs->tf_rsp    = frame.sf_sc.sc_esp_at_signal;
648ea0fabbcSTim J. Robbins 	regs->tf_ss     = frame.sf_sc.sc_ss;
649e6c006d9SJung-uk Kim 	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
650ea0fabbcSTim J. Robbins 
651ea0fabbcSTim J. Robbins 	return (EJUSTRETURN);
652ea0fabbcSTim J. Robbins }
653ea0fabbcSTim J. Robbins 
654ea0fabbcSTim J. Robbins /*
655ea0fabbcSTim J. Robbins  * System call to cleanup state after a signal
656ea0fabbcSTim J. Robbins  * has been taken.  Reset signal mask and
657ea0fabbcSTim J. Robbins  * stack state from context left by rt_sendsig (above).
658ea0fabbcSTim J. Robbins  * Return to previous pc and psl as specified by
659ea0fabbcSTim J. Robbins  * context left by sendsig. Check carefully to
660ea0fabbcSTim J. Robbins  * make sure that the user has not modified the
661ea0fabbcSTim J. Robbins  * psl to gain improper privileges or to cause
662ea0fabbcSTim J. Robbins  * a machine fault.
663ea0fabbcSTim J. Robbins  */
664ea0fabbcSTim J. Robbins int
665ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
666ea0fabbcSTim J. Robbins {
667ea0fabbcSTim J. Robbins 	struct l_ucontext uc;
668ea0fabbcSTim J. Robbins 	struct l_sigcontext *context;
669d6e029adSKonstantin Belousov 	sigset_t bmask;
670ea0fabbcSTim J. Robbins 	l_stack_t *lss;
671ea0fabbcSTim J. Robbins 	stack_t ss;
672ea0fabbcSTim J. Robbins 	struct trapframe *regs;
673ea0fabbcSTim J. Robbins 	int eflags;
6749104847fSDavid Xu 	ksiginfo_t ksi;
675ea0fabbcSTim J. Robbins 
676ea0fabbcSTim J. Robbins 	regs = td->td_frame;
677ea0fabbcSTim J. Robbins 
678ea0fabbcSTim J. Robbins #ifdef DEBUG
679ea0fabbcSTim J. Robbins 	if (ldebug(rt_sigreturn))
680ea0fabbcSTim J. Robbins 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
681ea0fabbcSTim J. Robbins #endif
682ea0fabbcSTim J. Robbins 	/*
683ea0fabbcSTim J. Robbins 	 * The trampoline code hands us the ucontext.
684ea0fabbcSTim J. Robbins 	 * It is unsafe to keep track of it ourselves, in the event that a
685ea0fabbcSTim J. Robbins 	 * program jumps out of a signal handler.
686ea0fabbcSTim J. Robbins 	 */
687ea0fabbcSTim J. Robbins 	if (copyin(args->ucp, &uc, sizeof(uc)) != 0)
688ea0fabbcSTim J. Robbins 		return (EFAULT);
689ea0fabbcSTim J. Robbins 
690ea0fabbcSTim J. Robbins 	context = &uc.uc_mcontext;
691ea0fabbcSTim J. Robbins 
692ea0fabbcSTim J. Robbins 	/*
693ea0fabbcSTim J. Robbins 	 * Check for security violations.
694ea0fabbcSTim J. Robbins 	 */
695ea0fabbcSTim J. Robbins #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
696ea0fabbcSTim J. Robbins 	eflags = context->sc_eflags;
6973d271aaaSEd Maste 	if (!EFLAGS_SECURE(eflags, regs->tf_rflags))
698ea0fabbcSTim J. Robbins 		return(EINVAL);
699ea0fabbcSTim J. Robbins 
700ea0fabbcSTim J. Robbins 	/*
701ea0fabbcSTim J. Robbins 	 * Don't allow users to load a valid privileged %cs.  Let the
702ea0fabbcSTim J. Robbins 	 * hardware check for invalid selectors, excess privilege in
703ea0fabbcSTim J. Robbins 	 * other selectors, invalid %eip's and invalid %esp's.
704ea0fabbcSTim J. Robbins 	 */
705ea0fabbcSTim J. Robbins #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
706ea0fabbcSTim J. Robbins 	if (!CS_SECURE(context->sc_cs)) {
7079104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
7089104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
7099104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
7109104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
7119104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_rip;
7129104847fSDavid Xu 		trapsignal(td, &ksi);
713ea0fabbcSTim J. Robbins 		return(EINVAL);
714ea0fabbcSTim J. Robbins 	}
715ea0fabbcSTim J. Robbins 
716d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&uc.uc_sigmask, &bmask);
717d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
718ea0fabbcSTim J. Robbins 
719ea0fabbcSTim J. Robbins 	/*
720ea0fabbcSTim J. Robbins 	 * Restore signal context
721ea0fabbcSTim J. Robbins 	 */
7222c66cccaSKonstantin Belousov 	regs->tf_gs	= context->sc_gs;
7232c66cccaSKonstantin Belousov 	regs->tf_fs	= context->sc_fs;
7242c66cccaSKonstantin Belousov 	regs->tf_es	= context->sc_es;
7252c66cccaSKonstantin Belousov 	regs->tf_ds	= context->sc_ds;
726ea0fabbcSTim J. Robbins 	regs->tf_rdi    = context->sc_edi;
727ea0fabbcSTim J. Robbins 	regs->tf_rsi    = context->sc_esi;
728ea0fabbcSTim J. Robbins 	regs->tf_rbp    = context->sc_ebp;
729ea0fabbcSTim J. Robbins 	regs->tf_rbx    = context->sc_ebx;
730ea0fabbcSTim J. Robbins 	regs->tf_rdx    = context->sc_edx;
731ea0fabbcSTim J. Robbins 	regs->tf_rcx    = context->sc_ecx;
732ea0fabbcSTim J. Robbins 	regs->tf_rax    = context->sc_eax;
733ea0fabbcSTim J. Robbins 	regs->tf_rip    = context->sc_eip;
734ea0fabbcSTim J. Robbins 	regs->tf_cs     = context->sc_cs;
735ea0fabbcSTim J. Robbins 	regs->tf_rflags = eflags;
736ea0fabbcSTim J. Robbins 	regs->tf_rsp    = context->sc_esp_at_signal;
737ea0fabbcSTim J. Robbins 	regs->tf_ss     = context->sc_ss;
738e6c006d9SJung-uk Kim 	set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
739ea0fabbcSTim J. Robbins 
740ea0fabbcSTim J. Robbins 	/*
741ea0fabbcSTim J. Robbins 	 * call sigaltstack & ignore results..
742ea0fabbcSTim J. Robbins 	 */
743ea0fabbcSTim J. Robbins 	lss = &uc.uc_stack;
744ea0fabbcSTim J. Robbins 	ss.ss_sp = PTRIN(lss->ss_sp);
745ea0fabbcSTim J. Robbins 	ss.ss_size = lss->ss_size;
746ea0fabbcSTim J. Robbins 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
747ea0fabbcSTim J. Robbins 
748ea0fabbcSTim J. Robbins #ifdef DEBUG
749ea0fabbcSTim J. Robbins 	if (ldebug(rt_sigreturn))
750c680f6b1SDavid E. O'Brien 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"),
751ea0fabbcSTim J. Robbins 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
752ea0fabbcSTim J. Robbins #endif
753ea0fabbcSTim J. Robbins 	(void)kern_sigaltstack(td, &ss, NULL);
754ea0fabbcSTim J. Robbins 
755ea0fabbcSTim J. Robbins 	return (EJUSTRETURN);
756ea0fabbcSTim J. Robbins }
757ea0fabbcSTim J. Robbins 
758afe1a688SKonstantin Belousov static int
759afe1a688SKonstantin Belousov linux32_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
760ea0fabbcSTim J. Robbins {
761afe1a688SKonstantin Belousov 	struct proc *p;
762afe1a688SKonstantin Belousov 	struct trapframe *frame;
763afe1a688SKonstantin Belousov 
764afe1a688SKonstantin Belousov 	p = td->td_proc;
765afe1a688SKonstantin Belousov 	frame = td->td_frame;
766afe1a688SKonstantin Belousov 
767afe1a688SKonstantin Belousov 	sa->args[0] = frame->tf_rbx;
768afe1a688SKonstantin Belousov 	sa->args[1] = frame->tf_rcx;
769afe1a688SKonstantin Belousov 	sa->args[2] = frame->tf_rdx;
770afe1a688SKonstantin Belousov 	sa->args[3] = frame->tf_rsi;
771afe1a688SKonstantin Belousov 	sa->args[4] = frame->tf_rdi;
772afe1a688SKonstantin Belousov 	sa->args[5] = frame->tf_rbp;	/* Unconfirmed */
773afe1a688SKonstantin Belousov 	sa->code = frame->tf_rax;
774afe1a688SKonstantin Belousov 
775afe1a688SKonstantin Belousov 	if (sa->code >= p->p_sysent->sv_size)
776afe1a688SKonstantin Belousov 		sa->callp = &p->p_sysent->sv_table[0];
777afe1a688SKonstantin Belousov 	else
778afe1a688SKonstantin Belousov 		sa->callp = &p->p_sysent->sv_table[sa->code];
779afe1a688SKonstantin Belousov 	sa->narg = sa->callp->sy_narg;
780afe1a688SKonstantin Belousov 
781afe1a688SKonstantin Belousov 	td->td_retval[0] = 0;
782afe1a688SKonstantin Belousov 	td->td_retval[1] = frame->tf_rdx;
783afe1a688SKonstantin Belousov 
784afe1a688SKonstantin Belousov 	return (0);
785ea0fabbcSTim J. Robbins }
786ea0fabbcSTim J. Robbins 
787ea0fabbcSTim J. Robbins /*
788ea0fabbcSTim J. Robbins  * If a linux binary is exec'ing something, try this image activator
789ea0fabbcSTim J. Robbins  * first.  We override standard shell script execution in order to
790ea0fabbcSTim J. Robbins  * be able to modify the interpreter path.  We only do this if a linux
791ea0fabbcSTim J. Robbins  * binary is doing the exec, so we do not create an EXEC module for it.
792ea0fabbcSTim J. Robbins  */
793ea0fabbcSTim J. Robbins static int	exec_linux_imgact_try(struct image_params *iparams);
794ea0fabbcSTim J. Robbins 
795ea0fabbcSTim J. Robbins static int
796ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp)
797ea0fabbcSTim J. Robbins {
798ea0fabbcSTim J. Robbins 	const char *head = (const char *)imgp->image_header;
7991d15fdd9SJohn Baldwin 	char *rpath;
800a14a9498SAlan Cox 	int error = -1;
801ea0fabbcSTim J. Robbins 
802ea0fabbcSTim J. Robbins 	/*
803ea0fabbcSTim J. Robbins 	* The interpreter for shell scripts run from a linux binary needs
804ea0fabbcSTim J. Robbins 	* to be located in /compat/linux if possible in order to recursively
805ea0fabbcSTim J. Robbins 	* maintain linux path emulation.
806ea0fabbcSTim J. Robbins 	*/
807ea0fabbcSTim J. Robbins 	if (((const short *)head)[0] == SHELLMAGIC) {
808ea0fabbcSTim J. Robbins 		/*
809ea0fabbcSTim J. Robbins 		* Run our normal shell image activator.  If it succeeds attempt
810d065e13dSDavid E. O'Brien 		* to use the alternate path for the interpreter.  If an
811d065e13dSDavid E. O'Brien 		* alternate * path is found, use our stringspace to store it.
812ea0fabbcSTim J. Robbins 		*/
813ea0fabbcSTim J. Robbins 		if ((error = exec_shell_imgact(imgp)) == 0) {
8141d15fdd9SJohn Baldwin 			linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
815d065e13dSDavid E. O'Brien 			    imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0,
816d065e13dSDavid E. O'Brien 			    AT_FDCWD);
817a14a9498SAlan Cox 			if (rpath != NULL)
818a14a9498SAlan Cox 				imgp->args->fname_buf =
819a14a9498SAlan Cox 				    imgp->interpreter_name = rpath;
820ea0fabbcSTim J. Robbins 		}
821ea0fabbcSTim J. Robbins 	}
822ea0fabbcSTim J. Robbins 	return (error);
823ea0fabbcSTim J. Robbins }
824ea0fabbcSTim J. Robbins 
825ea0fabbcSTim J. Robbins /*
826ea0fabbcSTim J. Robbins  * Clear registers on exec
827ea0fabbcSTim J. Robbins  * XXX copied from ia32_signal.c.
828ea0fabbcSTim J. Robbins  */
829ea0fabbcSTim J. Robbins static void
830a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack)
831ea0fabbcSTim J. Robbins {
832ea0fabbcSTim J. Robbins 	struct trapframe *regs = td->td_frame;
833ea0fabbcSTim J. Robbins 	struct pcb *pcb = td->td_pcb;
834ea0fabbcSTim J. Robbins 
8352c66cccaSKonstantin Belousov 	mtx_lock(&dt_lock);
8362c66cccaSKonstantin Belousov 	if (td->td_proc->p_md.md_ldt != NULL)
8372c66cccaSKonstantin Belousov 		user_ldt_free(td);
8382c66cccaSKonstantin Belousov 	else
8392c66cccaSKonstantin Belousov 		mtx_unlock(&dt_lock);
8402c66cccaSKonstantin Belousov 
8419c5b213eSJung-uk Kim 	critical_enter();
842ea0fabbcSTim J. Robbins 	wrmsr(MSR_FSBASE, 0);
843ea0fabbcSTim J. Robbins 	wrmsr(MSR_KGSBASE, 0);	/* User value while we're in the kernel */
844ea0fabbcSTim J. Robbins 	pcb->pcb_fsbase = 0;
845ea0fabbcSTim J. Robbins 	pcb->pcb_gsbase = 0;
8469c5b213eSJung-uk Kim 	critical_exit();
8472ee8325fSJohn Baldwin 	pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
848ea0fabbcSTim J. Robbins 
849ea0fabbcSTim J. Robbins 	bzero((char *)regs, sizeof(struct trapframe));
850a107d8aaSNathan Whitehorn 	regs->tf_rip = imgp->entry_addr;
851ea0fabbcSTim J. Robbins 	regs->tf_rsp = stack;
852ea0fabbcSTim J. Robbins 	regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
8532c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
8542c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
8552c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
8562c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
857ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
8582c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
859ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
860a107d8aaSNathan Whitehorn 	regs->tf_rbx = imgp->ps_strings;
861bdbf2db5SJung-uk Kim 
8622a988f7cSStephan Uphoff 	fpstate_drop(td);
863ea0fabbcSTim J. Robbins 
8641b3c3256SKonstantin Belousov 	/* Do full restore on return so that we can change to a different %cs */
865e6c006d9SJung-uk Kim 	set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET);
866ea0fabbcSTim J. Robbins 	td->td_retval[1] = 0;
867ea0fabbcSTim J. Robbins }
868ea0fabbcSTim J. Robbins 
869ea0fabbcSTim J. Robbins /*
870ea0fabbcSTim J. Robbins  * XXX copied from ia32_sysvec.c.
871ea0fabbcSTim J. Robbins  */
872ea0fabbcSTim J. Robbins static register_t *
873ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp)
874ea0fabbcSTim J. Robbins {
875ea0fabbcSTim J. Robbins 	int argc, envc;
876ea0fabbcSTim J. Robbins 	u_int32_t *vectp;
877ea0fabbcSTim J. Robbins 	char *stringp, *destp;
878ea0fabbcSTim J. Robbins 	u_int32_t *stack_base;
879ea0fabbcSTim J. Robbins 	struct linux32_ps_strings *arginfo;
880ea0fabbcSTim J. Robbins 
881ea0fabbcSTim J. Robbins 	/*
882ea0fabbcSTim J. Robbins 	 * Calculate string base and vector table pointers.
883ea0fabbcSTim J. Robbins 	 * Also deal with signal trampoline code for this exec type.
884ea0fabbcSTim J. Robbins 	 */
885ea0fabbcSTim J. Robbins 	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
8868f1e49a6SDmitry Chagin 	destp =	(caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform -
8878f1e49a6SDmitry Chagin 	    roundup((ARG_MAX - imgp->args->stringspace),
8884d7c2e8aSDmitry Chagin 	    sizeof(char *));
889ea0fabbcSTim J. Robbins 
890ea0fabbcSTim J. Robbins 	/*
8914d7c2e8aSDmitry Chagin 	 * Install LINUX_PLATFORM
8924d7c2e8aSDmitry Chagin 	 */
8938f1e49a6SDmitry Chagin 	copyout(linux_platform, ((caddr_t)arginfo - linux_szplatform),
8948f1e49a6SDmitry Chagin 	    linux_szplatform);
895ea0fabbcSTim J. Robbins 
896ea0fabbcSTim J. Robbins 	/*
897ea0fabbcSTim J. Robbins 	 * If we have a valid auxargs ptr, prepare some room
898ea0fabbcSTim J. Robbins 	 * on the stack.
899ea0fabbcSTim J. Robbins 	 */
900ea0fabbcSTim J. Robbins 	if (imgp->auxargs) {
901ea0fabbcSTim J. Robbins 		/*
902ea0fabbcSTim J. Robbins 		 * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
903ea0fabbcSTim J. Robbins 		 * lower compatibility.
904ea0fabbcSTim J. Robbins 		 */
905d065e13dSDavid E. O'Brien 		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
9064d7c2e8aSDmitry Chagin 		    (LINUX_AT_COUNT * 2);
907ea0fabbcSTim J. Robbins 		/*
908ea0fabbcSTim J. Robbins 		 * The '+ 2' is for the null pointers at the end of each of
909ea0fabbcSTim J. Robbins 		 * the arg and env vector sets,and imgp->auxarg_size is room
910ea0fabbcSTim J. Robbins 		 * for argument of Runtime loader.
911ea0fabbcSTim J. Robbins 		 */
912d065e13dSDavid E. O'Brien 		vectp = (u_int32_t *) (destp - (imgp->args->argc +
913d065e13dSDavid E. O'Brien 		    imgp->args->envc + 2 + imgp->auxarg_size) *
914d065e13dSDavid E. O'Brien 		    sizeof(u_int32_t));
915ea0fabbcSTim J. Robbins 
916ea0fabbcSTim J. Robbins 	} else
917ea0fabbcSTim J. Robbins 		/*
918ea0fabbcSTim J. Robbins 		 * The '+ 2' is for the null pointers at the end of each of
919ea0fabbcSTim J. Robbins 		 * the arg and env vector sets
920ea0fabbcSTim J. Robbins 		 */
921d065e13dSDavid E. O'Brien 		vectp = (u_int32_t *)(destp - (imgp->args->argc +
922d065e13dSDavid E. O'Brien 		    imgp->args->envc + 2) * sizeof(u_int32_t));
923ea0fabbcSTim J. Robbins 
924ea0fabbcSTim J. Robbins 	/*
925ea0fabbcSTim J. Robbins 	 * vectp also becomes our initial stack base
926ea0fabbcSTim J. Robbins 	 */
927ea0fabbcSTim J. Robbins 	stack_base = vectp;
928ea0fabbcSTim J. Robbins 
929610ecfe0SMaxim Sobolev 	stringp = imgp->args->begin_argv;
930610ecfe0SMaxim Sobolev 	argc = imgp->args->argc;
931610ecfe0SMaxim Sobolev 	envc = imgp->args->envc;
932ea0fabbcSTim J. Robbins 	/*
933ea0fabbcSTim J. Robbins 	 * Copy out strings - arguments and environment.
934ea0fabbcSTim J. Robbins 	 */
935610ecfe0SMaxim Sobolev 	copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
936ea0fabbcSTim J. Robbins 
937ea0fabbcSTim J. Robbins 	/*
938ea0fabbcSTim J. Robbins 	 * Fill in "ps_strings" struct for ps, w, etc.
939ea0fabbcSTim J. Robbins 	 */
9404d7c2e8aSDmitry Chagin 	suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp);
941ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_nargvstr, argc);
942ea0fabbcSTim J. Robbins 
943ea0fabbcSTim J. Robbins 	/*
944ea0fabbcSTim J. Robbins 	 * Fill in argument portion of vector table.
945ea0fabbcSTim J. Robbins 	 */
946ea0fabbcSTim J. Robbins 	for (; argc > 0; --argc) {
9474d7c2e8aSDmitry Chagin 		suword32(vectp++, (uint32_t)(intptr_t)destp);
948ea0fabbcSTim J. Robbins 		while (*stringp++ != 0)
949ea0fabbcSTim J. Robbins 			destp++;
950ea0fabbcSTim J. Robbins 		destp++;
951ea0fabbcSTim J. Robbins 	}
952ea0fabbcSTim J. Robbins 
953ea0fabbcSTim J. Robbins 	/* a null vector table pointer separates the argp's from the envp's */
954ea0fabbcSTim J. Robbins 	suword32(vectp++, 0);
955ea0fabbcSTim J. Robbins 
9564d7c2e8aSDmitry Chagin 	suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp);
957ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_nenvstr, envc);
958ea0fabbcSTim J. Robbins 
959ea0fabbcSTim J. Robbins 	/*
960ea0fabbcSTim J. Robbins 	 * Fill in environment portion of vector table.
961ea0fabbcSTim J. Robbins 	 */
962ea0fabbcSTim J. Robbins 	for (; envc > 0; --envc) {
9634d7c2e8aSDmitry Chagin 		suword32(vectp++, (uint32_t)(intptr_t)destp);
964ea0fabbcSTim J. Robbins 		while (*stringp++ != 0)
965ea0fabbcSTim J. Robbins 			destp++;
966ea0fabbcSTim J. Robbins 		destp++;
967ea0fabbcSTim J. Robbins 	}
968ea0fabbcSTim J. Robbins 
969ea0fabbcSTim J. Robbins 	/* end of vector table is a null pointer */
970ea0fabbcSTim J. Robbins 	suword32(vectp, 0);
971ea0fabbcSTim J. Robbins 
972ea0fabbcSTim J. Robbins 	return ((register_t *)stack_base);
973ea0fabbcSTim J. Robbins }
974ea0fabbcSTim J. Robbins 
9756472ac3dSEd Schouten static SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0,
976ea0fabbcSTim J. Robbins     "32-bit Linux emulation");
977ea0fabbcSTim J. Robbins 
978ea0fabbcSTim J. Robbins static u_long	linux32_maxdsiz = LINUX32_MAXDSIZ;
979ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW,
980ea0fabbcSTim J. Robbins     &linux32_maxdsiz, 0, "");
981ea0fabbcSTim J. Robbins static u_long	linux32_maxssiz = LINUX32_MAXSSIZ;
982ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW,
983ea0fabbcSTim J. Robbins     &linux32_maxssiz, 0, "");
984ea0fabbcSTim J. Robbins static u_long	linux32_maxvmem = LINUX32_MAXVMEM;
985ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW,
986ea0fabbcSTim J. Robbins     &linux32_maxvmem, 0, "");
987ea0fabbcSTim J. Robbins 
988ea0fabbcSTim J. Robbins static void
98919059a13SJohn Baldwin linux32_fixlimit(struct rlimit *rl, int which)
990ea0fabbcSTim J. Robbins {
991ea0fabbcSTim J. Robbins 
99219059a13SJohn Baldwin 	switch (which) {
99319059a13SJohn Baldwin 	case RLIMIT_DATA:
994ea0fabbcSTim J. Robbins 		if (linux32_maxdsiz != 0) {
99519059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxdsiz)
99619059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxdsiz;
99719059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxdsiz)
99819059a13SJohn Baldwin 				rl->rlim_max = linux32_maxdsiz;
999ea0fabbcSTim J. Robbins 		}
100019059a13SJohn Baldwin 		break;
100119059a13SJohn Baldwin 	case RLIMIT_STACK:
1002ea0fabbcSTim J. Robbins 		if (linux32_maxssiz != 0) {
100319059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxssiz)
100419059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxssiz;
100519059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxssiz)
100619059a13SJohn Baldwin 				rl->rlim_max = linux32_maxssiz;
1007ea0fabbcSTim J. Robbins 		}
100819059a13SJohn Baldwin 		break;
100919059a13SJohn Baldwin 	case RLIMIT_VMEM:
1010ea0fabbcSTim J. Robbins 		if (linux32_maxvmem != 0) {
101119059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxvmem)
101219059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxvmem;
101319059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxvmem)
101419059a13SJohn Baldwin 				rl->rlim_max = linux32_maxvmem;
1015ea0fabbcSTim J. Robbins 		}
101619059a13SJohn Baldwin 		break;
101719059a13SJohn Baldwin 	}
1018ea0fabbcSTim J. Robbins }
1019ea0fabbcSTim J. Robbins 
1020ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = {
1021a8d403e1SKonstantin Belousov 	.sv_size	= LINUX_SYS_MAXSYSCALL,
1022a8d403e1SKonstantin Belousov 	.sv_table	= linux_sysent,
1023a8d403e1SKonstantin Belousov 	.sv_mask	= 0,
1024a8d403e1SKonstantin Belousov 	.sv_sigsize	= LINUX_SIGTBLSZ,
1025a8d403e1SKonstantin Belousov 	.sv_sigtbl	= bsd_to_linux_signal,
1026a8d403e1SKonstantin Belousov 	.sv_errsize	= ELAST + 1,
1027a8d403e1SKonstantin Belousov 	.sv_errtbl	= bsd_to_linux_errno,
1028a8d403e1SKonstantin Belousov 	.sv_transtrap	= translate_traps,
1029a8d403e1SKonstantin Belousov 	.sv_fixup	= elf_linux_fixup,
1030a8d403e1SKonstantin Belousov 	.sv_sendsig	= linux_sendsig,
1031*bdc37934SDmitry Chagin 	.sv_sigcode	= &_binary_linux32_locore_o_start,
1032a8d403e1SKonstantin Belousov 	.sv_szsigcode	= &linux_szsigcode,
1033afe1a688SKonstantin Belousov 	.sv_prepsyscall	= NULL,
1034a8d403e1SKonstantin Belousov 	.sv_name	= "Linux ELF32",
1035a8d403e1SKonstantin Belousov 	.sv_coredump	= elf32_coredump,
1036a8d403e1SKonstantin Belousov 	.sv_imgact_try	= exec_linux_imgact_try,
1037a8d403e1SKonstantin Belousov 	.sv_minsigstksz	= LINUX_MINSIGSTKSZ,
1038a8d403e1SKonstantin Belousov 	.sv_pagesize	= PAGE_SIZE,
1039a8d403e1SKonstantin Belousov 	.sv_minuser	= VM_MIN_ADDRESS,
10408f1e49a6SDmitry Chagin 	.sv_maxuser	= LINUX32_MAXUSER,
1041a8d403e1SKonstantin Belousov 	.sv_usrstack	= LINUX32_USRSTACK,
1042a8d403e1SKonstantin Belousov 	.sv_psstrings	= LINUX32_PS_STRINGS,
1043a8d403e1SKonstantin Belousov 	.sv_stackprot	= VM_PROT_ALL,
1044a8d403e1SKonstantin Belousov 	.sv_copyout_strings = linux_copyout_strings,
1045a8d403e1SKonstantin Belousov 	.sv_setregs	= exec_linux_setregs,
1046a8d403e1SKonstantin Belousov 	.sv_fixlimit	= linux32_fixlimit,
1047a8d403e1SKonstantin Belousov 	.sv_maxssiz	= &linux32_maxssiz,
10488f1e49a6SDmitry Chagin 	.sv_flags	= SV_ABI_LINUX | SV_ILP32 | SV_IA32 | SV_SHP,
1049afe1a688SKonstantin Belousov 	.sv_set_syscall_retval = cpu_set_syscall_retval,
1050afe1a688SKonstantin Belousov 	.sv_fetch_syscall_args = linux32_fetch_syscall_args,
1051afe1a688SKonstantin Belousov 	.sv_syscallnames = NULL,
10528f1e49a6SDmitry Chagin 	.sv_shared_page_base = LINUX32_SHAREDPAGE,
10538f1e49a6SDmitry Chagin 	.sv_shared_page_len = PAGE_SIZE,
1054e5d81ef1SDmitry Chagin 	.sv_schedtail	= linux_schedtail,
105581338031SDmitry Chagin 	.sv_thread_detach = linux_thread_detach,
1056ea0fabbcSTim J. Robbins };
1057*bdc37934SDmitry Chagin 
1058*bdc37934SDmitry Chagin static void
1059*bdc37934SDmitry Chagin linux_vdso_install(void *param)
1060*bdc37934SDmitry Chagin {
1061*bdc37934SDmitry Chagin 
1062*bdc37934SDmitry Chagin 	linux_szsigcode = (&_binary_linux32_locore_o_end -
1063*bdc37934SDmitry Chagin 	    &_binary_linux32_locore_o_start);
1064*bdc37934SDmitry Chagin 
1065*bdc37934SDmitry Chagin 	if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len)
1066*bdc37934SDmitry Chagin 		panic("Linux invalid vdso size\n");
1067*bdc37934SDmitry Chagin 
1068*bdc37934SDmitry Chagin 	__elfN(linux_vdso_fixup)(&elf_linux_sysvec);
1069*bdc37934SDmitry Chagin 
1070*bdc37934SDmitry Chagin 	linux_shared_page_obj = __elfN(linux_shared_page_init)
1071*bdc37934SDmitry Chagin 	    (&linux_shared_page_mapping);
1072*bdc37934SDmitry Chagin 
1073*bdc37934SDmitry Chagin 	__elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX32_SHAREDPAGE);
1074*bdc37934SDmitry Chagin 
1075*bdc37934SDmitry Chagin 	bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping,
1076*bdc37934SDmitry Chagin 	    linux_szsigcode);
1077*bdc37934SDmitry Chagin 	elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj;
1078*bdc37934SDmitry Chagin }
1079*bdc37934SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY,
1080*bdc37934SDmitry Chagin     (sysinit_cfunc_t)linux_vdso_install, NULL);
1081*bdc37934SDmitry Chagin 
1082*bdc37934SDmitry Chagin static void
1083*bdc37934SDmitry Chagin linux_vdso_deinstall(void *param)
1084*bdc37934SDmitry Chagin {
1085*bdc37934SDmitry Chagin 
1086*bdc37934SDmitry Chagin 	__elfN(linux_shared_page_fini)(linux_shared_page_obj);
1087*bdc37934SDmitry Chagin };
1088*bdc37934SDmitry Chagin SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST,
1089*bdc37934SDmitry Chagin     (sysinit_cfunc_t)linux_vdso_deinstall, NULL);
1090ea0fabbcSTim J. Robbins 
109189ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU";
109289ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0;
109389ffc202SBjoern A. Zeeb 
109489ffc202SBjoern A. Zeeb static boolean_t
109589ffc202SBjoern A. Zeeb linux32_trans_osrel(const Elf_Note *note, int32_t *osrel)
109689ffc202SBjoern A. Zeeb {
109789ffc202SBjoern A. Zeeb 	const Elf32_Word *desc;
109889ffc202SBjoern A. Zeeb 	uintptr_t p;
109989ffc202SBjoern A. Zeeb 
110089ffc202SBjoern A. Zeeb 	p = (uintptr_t)(note + 1);
110189ffc202SBjoern A. Zeeb 	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
110289ffc202SBjoern A. Zeeb 
110389ffc202SBjoern A. Zeeb 	desc = (const Elf32_Word *)p;
110489ffc202SBjoern A. Zeeb 	if (desc[0] != GNULINUX_ABI_DESC)
110589ffc202SBjoern A. Zeeb 		return (FALSE);
110689ffc202SBjoern A. Zeeb 
110789ffc202SBjoern A. Zeeb 	/*
110889ffc202SBjoern A. Zeeb 	 * For linux we encode osrel as follows (see linux_mib.c):
110989ffc202SBjoern A. Zeeb 	 * VVVMMMIII (version, major, minor), see linux_mib.c.
111089ffc202SBjoern A. Zeeb 	 */
111189ffc202SBjoern A. Zeeb 	*osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3];
111289ffc202SBjoern A. Zeeb 
111389ffc202SBjoern A. Zeeb 	return (TRUE);
111489ffc202SBjoern A. Zeeb }
111532c01de2SDmitry Chagin 
111632c01de2SDmitry Chagin static Elf_Brandnote linux32_brandnote = {
111789ffc202SBjoern A. Zeeb 	.hdr.n_namesz	= sizeof(GNU_ABI_VENDOR),
111889ffc202SBjoern A. Zeeb 	.hdr.n_descsz	= 16,	/* XXX at least 16 */
111932c01de2SDmitry Chagin 	.hdr.n_type	= 1,
112089ffc202SBjoern A. Zeeb 	.vendor		= GNU_ABI_VENDOR,
112189ffc202SBjoern A. Zeeb 	.flags		= BN_TRANSLATE_OSREL,
112289ffc202SBjoern A. Zeeb 	.trans_osrel	= linux32_trans_osrel
112332c01de2SDmitry Chagin };
112432c01de2SDmitry Chagin 
1125ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = {
1126a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1127a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1128a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1129a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1130a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.1",
1131a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1132a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
113332c01de2SDmitry Chagin 	.brand_note	= &linux32_brandnote,
11342dedc128SDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
1135ea0fabbcSTim J. Robbins };
1136ea0fabbcSTim J. Robbins 
1137ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = {
1138a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1139a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1140a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1141a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1142a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.2",
1143a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1144a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
114532c01de2SDmitry Chagin 	.brand_note	= &linux32_brandnote,
11462dedc128SDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
1147ea0fabbcSTim J. Robbins };
1148ea0fabbcSTim J. Robbins 
1149ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = {
1150ea0fabbcSTim J. Robbins 	&linux_brand,
1151ea0fabbcSTim J. Robbins 	&linux_glibc2brand,
1152ea0fabbcSTim J. Robbins 	NULL
1153ea0fabbcSTim J. Robbins };
1154ea0fabbcSTim J. Robbins 
1155ea0fabbcSTim J. Robbins static int
1156ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data)
1157ea0fabbcSTim J. Robbins {
1158ea0fabbcSTim J. Robbins 	Elf32_Brandinfo **brandinfo;
1159ea0fabbcSTim J. Robbins 	int error;
1160ea0fabbcSTim J. Robbins 	struct linux_ioctl_handler **lihp;
1161387196bfSDoug Ambrisko 	struct linux_device_handler **ldhp;
1162ea0fabbcSTim J. Robbins 
1163ea0fabbcSTim J. Robbins 	error = 0;
1164ea0fabbcSTim J. Robbins 
1165ea0fabbcSTim J. Robbins 	switch(type) {
1166ea0fabbcSTim J. Robbins 	case MOD_LOAD:
1167ea0fabbcSTim J. Robbins 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1168ea0fabbcSTim J. Robbins 		     ++brandinfo)
1169ea0fabbcSTim J. Robbins 			if (elf32_insert_brand_entry(*brandinfo) < 0)
1170ea0fabbcSTim J. Robbins 				error = EINVAL;
1171ea0fabbcSTim J. Robbins 		if (error == 0) {
1172ea0fabbcSTim J. Robbins 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1173ea0fabbcSTim J. Robbins 				linux_ioctl_register_handler(*lihp);
1174387196bfSDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
1175387196bfSDoug Ambrisko 				linux_device_register_handler(*ldhp);
11767c09e6c0SAlexander Leidinger 			LIST_INIT(&futex_list);
117779262bf1SDmitry Chagin 			mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF);
1178d065e13dSDavid E. O'Brien 			linux_exit_tag = EVENTHANDLER_REGISTER(process_exit,
1179d065e13dSDavid E. O'Brien 			    linux_proc_exit, NULL, 1000);
1180d065e13dSDavid E. O'Brien 			linux_exec_tag = EVENTHANDLER_REGISTER(process_exec,
1181d065e13dSDavid E. O'Brien 			    linux_proc_exec, NULL, 1000);
118281338031SDmitry Chagin 			linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor,
118381338031SDmitry Chagin 			    linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
11844d7c2e8aSDmitry Chagin 			linux_szplatform = roundup(strlen(linux_platform) + 1,
11854d7c2e8aSDmitry Chagin 			    sizeof(char *));
11867ae27ff4SJamie Gritton 			linux_osd_jail_register();
11871ca16454SDmitry Chagin 			stclohz = (stathz ? stathz : hz);
1188ea0fabbcSTim J. Robbins 			if (bootverbose)
1189ea0fabbcSTim J. Robbins 				printf("Linux ELF exec handler installed\n");
1190ea0fabbcSTim J. Robbins 		} else
1191ea0fabbcSTim J. Robbins 			printf("cannot insert Linux ELF brand handler\n");
1192ea0fabbcSTim J. Robbins 		break;
1193ea0fabbcSTim J. Robbins 	case MOD_UNLOAD:
1194ea0fabbcSTim J. Robbins 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1195ea0fabbcSTim J. Robbins 		     ++brandinfo)
1196ea0fabbcSTim J. Robbins 			if (elf32_brand_inuse(*brandinfo))
1197ea0fabbcSTim J. Robbins 				error = EBUSY;
1198ea0fabbcSTim J. Robbins 		if (error == 0) {
1199ea0fabbcSTim J. Robbins 			for (brandinfo = &linux_brandlist[0];
1200ea0fabbcSTim J. Robbins 			     *brandinfo != NULL; ++brandinfo)
1201ea0fabbcSTim J. Robbins 				if (elf32_remove_brand_entry(*brandinfo) < 0)
1202ea0fabbcSTim J. Robbins 					error = EINVAL;
1203ea0fabbcSTim J. Robbins 		}
1204ea0fabbcSTim J. Robbins 		if (error == 0) {
1205ea0fabbcSTim J. Robbins 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1206ea0fabbcSTim J. Robbins 				linux_ioctl_unregister_handler(*lihp);
1207387196bfSDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
1208387196bfSDoug Ambrisko 				linux_device_unregister_handler(*ldhp);
120979262bf1SDmitry Chagin 			mtx_destroy(&futex_mtx);
12107c09e6c0SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
12117c09e6c0SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
121281338031SDmitry Chagin 			EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag);
12137ae27ff4SJamie Gritton 			linux_osd_jail_deregister();
1214ea0fabbcSTim J. Robbins 			if (bootverbose)
1215ea0fabbcSTim J. Robbins 				printf("Linux ELF exec handler removed\n");
1216ea0fabbcSTim J. Robbins 		} else
1217ea0fabbcSTim J. Robbins 			printf("Could not deinstall ELF interpreter entry\n");
1218ea0fabbcSTim J. Robbins 		break;
1219ea0fabbcSTim J. Robbins 	default:
1220af682d48SDmitry Chagin 		return (EOPNOTSUPP);
1221ea0fabbcSTim J. Robbins 	}
1222af682d48SDmitry Chagin 	return (error);
1223ea0fabbcSTim J. Robbins }
1224ea0fabbcSTim J. Robbins 
1225ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = {
1226ea0fabbcSTim J. Robbins 	"linuxelf",
1227ea0fabbcSTim J. Robbins 	linux_elf_modevent,
12289823d527SKevin Lo 	0
1229ea0fabbcSTim J. Robbins };
1230ea0fabbcSTim J. Robbins 
123178ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
1232