xref: /freebsd/sys/amd64/linux32/linux32_sysvec.c (revision 1b3c32568ab513ea2ba8ac39b0debdd39fd448b7)
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
6ea0fabbcSTim J. Robbins  * 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>
79d789bfd5SDmitry Chagin #include <compat/linux/linux_futex.h>
807c09e6c0SAlexander Leidinger #include <compat/linux/linux_emul.h>
81ea0fabbcSTim J. Robbins #include <compat/linux/linux_mib.h>
824d7c2e8aSDmitry Chagin #include <compat/linux/linux_misc.h>
83ea0fabbcSTim J. Robbins #include <compat/linux/linux_signal.h>
84ea0fabbcSTim J. Robbins #include <compat/linux/linux_util.h>
85ea0fabbcSTim J. Robbins 
86ea0fabbcSTim J. Robbins MODULE_VERSION(linux, 1);
87ea0fabbcSTim J. Robbins 
88ea0fabbcSTim J. Robbins MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
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 
1114d7c2e8aSDmitry Chagin const char *linux_platform = "i686";
1124d7c2e8aSDmitry Chagin static int linux_szplatform;
113ea0fabbcSTim J. Robbins extern char linux_sigcode[];
114ea0fabbcSTim J. Robbins extern int linux_szsigcode;
115ea0fabbcSTim J. Robbins 
116ea0fabbcSTim J. Robbins extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
117ea0fabbcSTim J. Robbins 
118ea0fabbcSTim J. Robbins SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
119387196bfSDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
120ea0fabbcSTim J. Robbins 
121ea0fabbcSTim J. Robbins static int	elf_linux_fixup(register_t **stack_base,
122ea0fabbcSTim J. Robbins 		    struct image_params *iparams);
123ea0fabbcSTim J. Robbins static register_t *linux_copyout_strings(struct image_params *imgp);
1249104847fSDavid Xu static void     linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
125a107d8aaSNathan Whitehorn static void	exec_linux_setregs(struct thread *td,
126a107d8aaSNathan Whitehorn 				   struct image_params *imgp, u_long stack);
12719059a13SJohn Baldwin static void	linux32_fixlimit(struct rlimit *rl, int which);
12889ffc202SBjoern A. Zeeb static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel);
129ea0fabbcSTim J. Robbins 
1307c09e6c0SAlexander Leidinger static eventhandler_tag linux_exit_tag;
1317c09e6c0SAlexander Leidinger static eventhandler_tag linux_schedtail_tag;
1327c09e6c0SAlexander Leidinger static eventhandler_tag linux_exec_tag;
1337c09e6c0SAlexander Leidinger 
134ea0fabbcSTim J. Robbins /*
135ea0fabbcSTim J. Robbins  * Linux syscalls return negative errno's, we do positive and map them
13650e422f0SAlexander Leidinger  * Reference:
13750e422f0SAlexander Leidinger  *   FreeBSD: src/sys/sys/errno.h
13850e422f0SAlexander Leidinger  *   Linux:   linux-2.6.17.8/include/asm-generic/errno-base.h
13950e422f0SAlexander Leidinger  *            linux-2.6.17.8/include/asm-generic/errno.h
140ea0fabbcSTim J. Robbins  */
141ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = {
142ea0fabbcSTim J. Robbins 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
143ea0fabbcSTim J. Robbins 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
144ea0fabbcSTim J. Robbins 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
145ea0fabbcSTim J. Robbins 	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
146ea0fabbcSTim J. Robbins 	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
147ea0fabbcSTim J. Robbins 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
148ea0fabbcSTim J. Robbins 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
149ea0fabbcSTim J. Robbins 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
15050e422f0SAlexander Leidinger 	  -6,  -6, -43, -42, -75,-125, -84, -95, -16, -74,
15150e422f0SAlexander Leidinger 	 -72, -67, -71
152ea0fabbcSTim J. Robbins };
153ea0fabbcSTim J. Robbins 
154ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
155ea0fabbcSTim J. Robbins 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
156ea0fabbcSTim J. Robbins 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
157ea0fabbcSTim J. Robbins 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
158ea0fabbcSTim J. Robbins 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
159ea0fabbcSTim J. Robbins 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
160ea0fabbcSTim J. Robbins 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
161ea0fabbcSTim J. Robbins 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
162ea0fabbcSTim J. Robbins 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
163ea0fabbcSTim J. Robbins };
164ea0fabbcSTim J. Robbins 
165ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
166ea0fabbcSTim J. Robbins 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
167ea0fabbcSTim J. Robbins 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
168ea0fabbcSTim J. Robbins 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
169ea0fabbcSTim J. Robbins 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
170ea0fabbcSTim J. Robbins 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
171ea0fabbcSTim J. Robbins 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
172ea0fabbcSTim J. Robbins 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
173ea0fabbcSTim J. Robbins 	SIGIO, SIGURG, SIGSYS
174ea0fabbcSTim J. Robbins };
175ea0fabbcSTim J. Robbins 
176ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN  255
177ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = {
178ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 0 */
179ea0fabbcSTim J. Robbins 	6,			/* 1  T_PRIVINFLT */
180ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 2 */
181ea0fabbcSTim J. Robbins 	3,			/* 3  T_BPTFLT */
182ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 4 */
183ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 5 */
184ea0fabbcSTim J. Robbins 	16,			/* 6  T_ARITHTRAP */
185ea0fabbcSTim J. Robbins 	254,			/* 7  T_ASTFLT */
186ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 8 */
187ea0fabbcSTim J. Robbins 	13,			/* 9  T_PROTFLT */
188ea0fabbcSTim J. Robbins 	1,			/* 10 T_TRCTRAP */
189ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 11 */
190ea0fabbcSTim J. Robbins 	14,			/* 12 T_PAGEFLT */
191ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 13 */
192ea0fabbcSTim J. Robbins 	17,			/* 14 T_ALIGNFLT */
193ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 15 */
194ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 16 */
195ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 17 */
196ea0fabbcSTim J. Robbins 	0,			/* 18 T_DIVIDE */
197ea0fabbcSTim J. Robbins 	2,			/* 19 T_NMI */
198ea0fabbcSTim J. Robbins 	4,			/* 20 T_OFLOW */
199ea0fabbcSTim J. Robbins 	5,			/* 21 T_BOUND */
200ea0fabbcSTim J. Robbins 	7,			/* 22 T_DNA */
201ea0fabbcSTim J. Robbins 	8,			/* 23 T_DOUBLEFLT */
202ea0fabbcSTim J. Robbins 	9,			/* 24 T_FPOPFLT */
203ea0fabbcSTim J. Robbins 	10,			/* 25 T_TSSFLT */
204ea0fabbcSTim J. Robbins 	11,			/* 26 T_SEGNPFLT */
205ea0fabbcSTim J. Robbins 	12,			/* 27 T_STKFLT */
206ea0fabbcSTim J. Robbins 	18,			/* 28 T_MCHK */
207ea0fabbcSTim J. Robbins 	19,			/* 29 T_XMMFLT */
208ea0fabbcSTim J. Robbins 	15			/* 30 T_RESERVED */
209ea0fabbcSTim J. Robbins };
210ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \
211ea0fabbcSTim J. Robbins     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
212ea0fabbcSTim J. Robbins      _bsd_to_linux_trapcode[(code)]: \
213ea0fabbcSTim J. Robbins      LINUX_T_UNKNOWN)
214ea0fabbcSTim J. Robbins 
215ea0fabbcSTim J. Robbins struct linux32_ps_strings {
216ea0fabbcSTim J. Robbins 	u_int32_t ps_argvstr;	/* first of 0 or more argument strings */
217f2c7668eSDavid Schultz 	u_int ps_nargvstr;	/* the number of argument strings */
218ea0fabbcSTim J. Robbins 	u_int32_t ps_envstr;	/* first of 0 or more environment strings */
219f2c7668eSDavid Schultz 	u_int ps_nenvstr;	/* the number of environment strings */
220ea0fabbcSTim J. Robbins };
221ea0fabbcSTim J. Robbins 
222ea0fabbcSTim J. Robbins /*
223ea0fabbcSTim J. Robbins  * If FreeBSD & Linux have a difference of opinion about what a trap
224ea0fabbcSTim J. Robbins  * means, deal with it here.
225ea0fabbcSTim J. Robbins  *
226ea0fabbcSTim J. Robbins  * MPSAFE
227ea0fabbcSTim J. Robbins  */
228ea0fabbcSTim J. Robbins static int
229ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code)
230ea0fabbcSTim J. Robbins {
231ea0fabbcSTim J. Robbins 	if (signal != SIGBUS)
232ea0fabbcSTim J. Robbins 		return signal;
233ea0fabbcSTim J. Robbins 	switch (trap_code) {
234ea0fabbcSTim J. Robbins 	case T_PROTFLT:
235ea0fabbcSTim J. Robbins 	case T_TSSFLT:
236ea0fabbcSTim J. Robbins 	case T_DOUBLEFLT:
237ea0fabbcSTim J. Robbins 	case T_PAGEFLT:
238ea0fabbcSTim J. Robbins 		return SIGSEGV;
239ea0fabbcSTim J. Robbins 	default:
240ea0fabbcSTim J. Robbins 		return signal;
241ea0fabbcSTim J. Robbins 	}
242ea0fabbcSTim J. Robbins }
243ea0fabbcSTim J. Robbins 
244ea0fabbcSTim J. Robbins static int
245ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
246ea0fabbcSTim J. Robbins {
247ea0fabbcSTim J. Robbins 	Elf32_Auxargs *args;
248ea0fabbcSTim J. Robbins 	Elf32_Addr *base;
2494d7c2e8aSDmitry Chagin 	Elf32_Addr *pos, *uplatform;
2504d7c2e8aSDmitry Chagin 	struct linux32_ps_strings *arginfo;
2514d7c2e8aSDmitry Chagin 
2524d7c2e8aSDmitry Chagin 	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
2534d7c2e8aSDmitry Chagin 	uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode -
2544d7c2e8aSDmitry Chagin 	    linux_szplatform);
255ea0fabbcSTim J. Robbins 
2566617724cSJeff Roberson 	KASSERT(curthread->td_proc == imgp->proc,
257ea0fabbcSTim J. Robbins 	    ("unsafe elf_linux_fixup(), should be curproc"));
258ea0fabbcSTim J. Robbins 	base = (Elf32_Addr *)*stack_base;
259ea0fabbcSTim J. Robbins 	args = (Elf32_Auxargs *)imgp->auxargs;
260610ecfe0SMaxim Sobolev 	pos = base + (imgp->args->argc + imgp->args->envc + 2);
261ea0fabbcSTim J. Robbins 
2624d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);
2638d30f381SDmitry Chagin 
2648d30f381SDmitry Chagin 	/*
2658d30f381SDmitry Chagin 	 * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0,
2668d30f381SDmitry Chagin 	 * as it has appeared in the 2.4.0-rc7 first time.
2678d30f381SDmitry Chagin 	 * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK),
2688d30f381SDmitry Chagin 	 * glibc falls back to the hard-coded CLK_TCK value when aux entry
2698d30f381SDmitry Chagin 	 * is not present.
2708d30f381SDmitry Chagin 	 * Also see linux_times() implementation.
2718d30f381SDmitry Chagin 	 */
2728d30f381SDmitry Chagin 	if (linux_kernver(curthread) >= LINUX_KERNVER_2004000)
2731ca16454SDmitry Chagin 		AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, stclohz);
274ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr);
275ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent);
276ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum);
277ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz);
278ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags);
279ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry);
280ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_BASE, args->base);
2814d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0);
282ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
283ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
284ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
285ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
2864d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
2874d7c2e8aSDmitry Chagin 	if (args->execfd != -1)
2884d7c2e8aSDmitry Chagin 		AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
289ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_NULL, 0);
290ea0fabbcSTim J. Robbins 
291ea0fabbcSTim J. Robbins 	free(imgp->auxargs, M_TEMP);
292ea0fabbcSTim J. Robbins 	imgp->auxargs = NULL;
293ea0fabbcSTim J. Robbins 
294ea0fabbcSTim J. Robbins 	base--;
295610ecfe0SMaxim Sobolev 	suword32(base, (uint32_t)imgp->args->argc);
296ea0fabbcSTim J. Robbins 	*stack_base = (register_t *)base;
297ea0fabbcSTim J. Robbins 	return 0;
298ea0fabbcSTim J. Robbins }
299ea0fabbcSTim J. Robbins 
300ea0fabbcSTim J. Robbins extern unsigned long linux_sznonrtsigcode;
301ea0fabbcSTim J. Robbins 
302ea0fabbcSTim J. Robbins static void
3039104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
304ea0fabbcSTim J. Robbins {
305ea0fabbcSTim J. Robbins 	struct thread *td = curthread;
306ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
307ea0fabbcSTim J. Robbins 	struct sigacts *psp;
308ea0fabbcSTim J. Robbins 	struct trapframe *regs;
309ea0fabbcSTim J. Robbins 	struct l_rt_sigframe *fp, frame;
310ea0fabbcSTim J. Robbins 	int oonstack;
3119104847fSDavid Xu 	int sig;
3129104847fSDavid Xu 	int code;
313ea0fabbcSTim J. Robbins 
3149104847fSDavid Xu 	sig = ksi->ksi_signo;
3159104847fSDavid Xu 	code = ksi->ksi_code;
316ea0fabbcSTim J. Robbins 	PROC_LOCK_ASSERT(p, MA_OWNED);
317ea0fabbcSTim J. Robbins 	psp = p->p_sigacts;
318ea0fabbcSTim J. Robbins 	mtx_assert(&psp->ps_mtx, MA_OWNED);
319ea0fabbcSTim J. Robbins 	regs = td->td_frame;
320ea0fabbcSTim J. Robbins 	oonstack = sigonstack(regs->tf_rsp);
321ea0fabbcSTim J. Robbins 
322ea0fabbcSTim J. Robbins #ifdef DEBUG
323ea0fabbcSTim J. Robbins 	if (ldebug(rt_sendsig))
324728ef954SJohn Baldwin 		printf(ARGS(rt_sendsig, "%p, %d, %p, %u"),
325ea0fabbcSTim J. Robbins 		    catcher, sig, (void*)mask, code);
326ea0fabbcSTim J. Robbins #endif
327ea0fabbcSTim J. Robbins 	/*
328ea0fabbcSTim J. Robbins 	 * Allocate space for the signal handler context.
329ea0fabbcSTim J. Robbins 	 */
330ea0fabbcSTim J. Robbins 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
331ea0fabbcSTim J. Robbins 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
332ea0fabbcSTim J. Robbins 		fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp +
333ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe));
334ea0fabbcSTim J. Robbins 	} else
335ea0fabbcSTim J. Robbins 		fp = (struct l_rt_sigframe *)regs->tf_rsp - 1;
336ea0fabbcSTim J. Robbins 	mtx_unlock(&psp->ps_mtx);
337ea0fabbcSTim J. Robbins 
338ea0fabbcSTim J. Robbins 	/*
339ea0fabbcSTim J. Robbins 	 * Build the argument list for the signal handler.
340ea0fabbcSTim J. Robbins 	 */
341ea0fabbcSTim J. Robbins 	if (p->p_sysent->sv_sigtbl)
342ea0fabbcSTim J. Robbins 		if (sig <= p->p_sysent->sv_sigsize)
343ea0fabbcSTim J. Robbins 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
344ea0fabbcSTim J. Robbins 
345ea0fabbcSTim J. Robbins 	bzero(&frame, sizeof(frame));
346ea0fabbcSTim J. Robbins 
347ea0fabbcSTim J. Robbins 	frame.sf_handler = PTROUT(catcher);
348ea0fabbcSTim J. Robbins 	frame.sf_sig = sig;
349ea0fabbcSTim J. Robbins 	frame.sf_siginfo = PTROUT(&fp->sf_si);
350ea0fabbcSTim J. Robbins 	frame.sf_ucontext = PTROUT(&fp->sf_sc);
351ea0fabbcSTim J. Robbins 
352ea0fabbcSTim J. Robbins 	/* Fill in POSIX parts */
353aa8b2011SKonstantin Belousov 	ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig);
354ea0fabbcSTim J. Robbins 
355ea0fabbcSTim J. Robbins 	/*
356ea0fabbcSTim J. Robbins 	 * Build the signal context to be used by sigreturn.
357ea0fabbcSTim J. Robbins 	 */
358ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
359ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_link = 0;		/* XXX ??? */
360ea0fabbcSTim J. Robbins 
361ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp);
362ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size;
363ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
364ea0fabbcSTim J. Robbins 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
365ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
366ea0fabbcSTim J. Robbins 
367ea0fabbcSTim J. Robbins 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
368ea0fabbcSTim J. Robbins 
369ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
370ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_rdi;
371ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_rsi;
372ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_rbp;
373ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_rbx;
374ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_rdx;
375ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_rcx;
376ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_rax;
377ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_rip;
378ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
3792c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_gs     = regs->tf_gs;
3802c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
3812c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
3822c66cccaSKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
383ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags;
384ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp;
385ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
386ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
38796a2b635SKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_cr2    = (u_int32_t)(uintptr_t)ksi->ksi_addr;
388ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
389ea0fabbcSTim J. Robbins 
390ea0fabbcSTim J. Robbins #ifdef DEBUG
391ea0fabbcSTim J. Robbins 	if (ldebug(rt_sendsig))
392c680f6b1SDavid E. O'Brien 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"),
393ea0fabbcSTim J. Robbins 		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
394ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
395ea0fabbcSTim J. Robbins #endif
396ea0fabbcSTim J. Robbins 
397ea0fabbcSTim J. Robbins 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
398ea0fabbcSTim J. Robbins 		/*
399ea0fabbcSTim J. Robbins 		 * Process has trashed its stack; give it an illegal
400ea0fabbcSTim J. Robbins 		 * instruction to halt it in its tracks.
401ea0fabbcSTim J. Robbins 		 */
402ea0fabbcSTim J. Robbins #ifdef DEBUG
403ea0fabbcSTim J. Robbins 		if (ldebug(rt_sendsig))
404ea0fabbcSTim J. Robbins 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
405ea0fabbcSTim J. Robbins 			    fp, oonstack);
406ea0fabbcSTim J. Robbins #endif
407ea0fabbcSTim J. Robbins 		PROC_LOCK(p);
408ea0fabbcSTim J. Robbins 		sigexit(td, SIGILL);
409ea0fabbcSTim J. Robbins 	}
410ea0fabbcSTim J. Robbins 
411ea0fabbcSTim J. Robbins 	/*
412ea0fabbcSTim J. Robbins 	 * Build context to run handler in.
413ea0fabbcSTim J. Robbins 	 */
414ea0fabbcSTim J. Robbins 	regs->tf_rsp = PTROUT(fp);
415ea0fabbcSTim J. Robbins 	regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode) +
416ea0fabbcSTim J. Robbins 	    linux_sznonrtsigcode;
41722eca0bfSKonstantin Belousov 	regs->tf_rflags &= ~(PSL_T | PSL_D);
418ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
419ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
4202c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
4212c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
4222c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
4232c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
4242c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
425a2622e5dSKonstantin Belousov 	td->td_pcb->pcb_full_iret = 1;
426ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
427ea0fabbcSTim J. Robbins 	mtx_lock(&psp->ps_mtx);
428ea0fabbcSTim J. Robbins }
429ea0fabbcSTim J. Robbins 
430ea0fabbcSTim J. Robbins 
431ea0fabbcSTim J. Robbins /*
432ea0fabbcSTim J. Robbins  * Send an interrupt to process.
433ea0fabbcSTim J. Robbins  *
434ea0fabbcSTim J. Robbins  * Stack is set up to allow sigcode stored
435ea0fabbcSTim J. Robbins  * in u. to call routine, followed by kcall
436ea0fabbcSTim J. Robbins  * to sigreturn routine below.  After sigreturn
437ea0fabbcSTim J. Robbins  * resets the signal mask, the stack, and the
438ea0fabbcSTim J. Robbins  * frame pointer, it returns to the user
439ea0fabbcSTim J. Robbins  * specified pc, psl.
440ea0fabbcSTim J. Robbins  */
441ea0fabbcSTim J. Robbins static void
4429104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
443ea0fabbcSTim J. Robbins {
444ea0fabbcSTim J. Robbins 	struct thread *td = curthread;
445ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
446ea0fabbcSTim J. Robbins 	struct sigacts *psp;
447ea0fabbcSTim J. Robbins 	struct trapframe *regs;
448ea0fabbcSTim J. Robbins 	struct l_sigframe *fp, frame;
449ea0fabbcSTim J. Robbins 	l_sigset_t lmask;
450ea0fabbcSTim J. Robbins 	int oonstack, i;
4519104847fSDavid Xu 	int sig, code;
452ea0fabbcSTim J. Robbins 
4539104847fSDavid Xu 	sig = ksi->ksi_signo;
4549104847fSDavid Xu 	code = ksi->ksi_code;
455ea0fabbcSTim J. Robbins 	PROC_LOCK_ASSERT(p, MA_OWNED);
456ea0fabbcSTim J. Robbins 	psp = p->p_sigacts;
457ea0fabbcSTim J. Robbins 	mtx_assert(&psp->ps_mtx, MA_OWNED);
458ea0fabbcSTim J. Robbins 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
459ea0fabbcSTim J. Robbins 		/* Signal handler installed with SA_SIGINFO. */
4609104847fSDavid Xu 		linux_rt_sendsig(catcher, ksi, mask);
461ea0fabbcSTim J. Robbins 		return;
462ea0fabbcSTim J. Robbins 	}
463ea0fabbcSTim J. Robbins 
464ea0fabbcSTim J. Robbins 	regs = td->td_frame;
465ea0fabbcSTim J. Robbins 	oonstack = sigonstack(regs->tf_rsp);
466ea0fabbcSTim J. Robbins 
467ea0fabbcSTim J. Robbins #ifdef DEBUG
468ea0fabbcSTim J. Robbins 	if (ldebug(sendsig))
469728ef954SJohn Baldwin 		printf(ARGS(sendsig, "%p, %d, %p, %u"),
470ea0fabbcSTim J. Robbins 		    catcher, sig, (void*)mask, code);
471ea0fabbcSTim J. Robbins #endif
472ea0fabbcSTim J. Robbins 
473ea0fabbcSTim J. Robbins 	/*
474ea0fabbcSTim J. Robbins 	 * Allocate space for the signal handler context.
475ea0fabbcSTim J. Robbins 	 */
476ea0fabbcSTim J. Robbins 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
477ea0fabbcSTim J. Robbins 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
478ea0fabbcSTim J. Robbins 		fp = (struct l_sigframe *)(td->td_sigstk.ss_sp +
479ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size - sizeof(struct l_sigframe));
480ea0fabbcSTim J. Robbins 	} else
481ea0fabbcSTim J. Robbins 		fp = (struct l_sigframe *)regs->tf_rsp - 1;
482ea0fabbcSTim J. Robbins 	mtx_unlock(&psp->ps_mtx);
483ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
484ea0fabbcSTim J. Robbins 
485ea0fabbcSTim J. Robbins 	/*
486ea0fabbcSTim J. Robbins 	 * Build the argument list for the signal handler.
487ea0fabbcSTim J. Robbins 	 */
488ea0fabbcSTim J. Robbins 	if (p->p_sysent->sv_sigtbl)
489ea0fabbcSTim J. Robbins 		if (sig <= p->p_sysent->sv_sigsize)
490ea0fabbcSTim J. Robbins 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
491ea0fabbcSTim J. Robbins 
492ea0fabbcSTim J. Robbins 	bzero(&frame, sizeof(frame));
493ea0fabbcSTim J. Robbins 
494ea0fabbcSTim J. Robbins 	frame.sf_handler = PTROUT(catcher);
495ea0fabbcSTim J. Robbins 	frame.sf_sig = sig;
496ea0fabbcSTim J. Robbins 
497ea0fabbcSTim J. Robbins 	bsd_to_linux_sigset(mask, &lmask);
498ea0fabbcSTim J. Robbins 
499ea0fabbcSTim J. Robbins 	/*
500ea0fabbcSTim J. Robbins 	 * Build the signal context to be used by sigreturn.
501ea0fabbcSTim J. Robbins 	 */
502ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_mask   = lmask.__bits[0];
5032c66cccaSKonstantin Belousov 	frame.sf_sc.sc_gs     = regs->tf_gs;
5042c66cccaSKonstantin Belousov 	frame.sf_sc.sc_fs     = regs->tf_fs;
5052c66cccaSKonstantin Belousov 	frame.sf_sc.sc_es     = regs->tf_es;
5062c66cccaSKonstantin Belousov 	frame.sf_sc.sc_ds     = regs->tf_ds;
507ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_edi    = regs->tf_rdi;
508ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_esi    = regs->tf_rsi;
509ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ebp    = regs->tf_rbp;
510ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ebx    = regs->tf_rbx;
511ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_edx    = regs->tf_rdx;
512ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ecx    = regs->tf_rcx;
513ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eax    = regs->tf_rax;
514ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eip    = regs->tf_rip;
515ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_cs     = regs->tf_cs;
516ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eflags = regs->tf_rflags;
517ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_esp_at_signal = regs->tf_rsp;
518ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ss     = regs->tf_ss;
519ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_err    = regs->tf_err;
52096a2b635SKonstantin Belousov 	frame.sf_sc.sc_cr2    = (u_int32_t)(uintptr_t)ksi->ksi_addr;
521ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code);
522ea0fabbcSTim J. Robbins 
523ea0fabbcSTim J. Robbins 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
524ea0fabbcSTim J. Robbins 		frame.sf_extramask[i] = lmask.__bits[i+1];
525ea0fabbcSTim J. Robbins 
526ea0fabbcSTim J. Robbins 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
527ea0fabbcSTim J. Robbins 		/*
528ea0fabbcSTim J. Robbins 		 * Process has trashed its stack; give it an illegal
529ea0fabbcSTim J. Robbins 		 * instruction to halt it in its tracks.
530ea0fabbcSTim J. Robbins 		 */
531ea0fabbcSTim J. Robbins 		PROC_LOCK(p);
532ea0fabbcSTim J. Robbins 		sigexit(td, SIGILL);
533ea0fabbcSTim J. Robbins 	}
534ea0fabbcSTim J. Robbins 
535ea0fabbcSTim J. Robbins 	/*
536ea0fabbcSTim J. Robbins 	 * Build context to run handler in.
537ea0fabbcSTim J. Robbins 	 */
538ea0fabbcSTim J. Robbins 	regs->tf_rsp = PTROUT(fp);
539ea0fabbcSTim J. Robbins 	regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode);
54022eca0bfSKonstantin Belousov 	regs->tf_rflags &= ~(PSL_T | PSL_D);
541ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
542ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
5432c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
5442c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
5452c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
5462c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
5472c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
548a2622e5dSKonstantin Belousov 	td->td_pcb->pcb_full_iret = 1;
549ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
550ea0fabbcSTim J. Robbins 	mtx_lock(&psp->ps_mtx);
551ea0fabbcSTim J. Robbins }
552ea0fabbcSTim J. Robbins 
553ea0fabbcSTim J. Robbins /*
554ea0fabbcSTim J. Robbins  * System call to cleanup state after a signal
555ea0fabbcSTim J. Robbins  * has been taken.  Reset signal mask and
556ea0fabbcSTim J. Robbins  * stack state from context left by sendsig (above).
557ea0fabbcSTim J. Robbins  * Return to previous pc and psl as specified by
558ea0fabbcSTim J. Robbins  * context left by sendsig. Check carefully to
559ea0fabbcSTim J. Robbins  * make sure that the user has not modified the
560ea0fabbcSTim J. Robbins  * psl to gain improper privileges or to cause
561ea0fabbcSTim J. Robbins  * a machine fault.
562ea0fabbcSTim J. Robbins  */
563ea0fabbcSTim J. Robbins int
564ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
565ea0fabbcSTim J. Robbins {
566ea0fabbcSTim J. Robbins 	struct l_sigframe frame;
567ea0fabbcSTim J. Robbins 	struct trapframe *regs;
568d6e029adSKonstantin Belousov 	sigset_t bmask;
569ea0fabbcSTim J. Robbins 	l_sigset_t lmask;
570ea0fabbcSTim J. Robbins 	int eflags, i;
5719104847fSDavid Xu 	ksiginfo_t ksi;
572ea0fabbcSTim J. Robbins 
573ea0fabbcSTim J. Robbins 	regs = td->td_frame;
574ea0fabbcSTim J. Robbins 
575ea0fabbcSTim J. Robbins #ifdef DEBUG
576ea0fabbcSTim J. Robbins 	if (ldebug(sigreturn))
577ea0fabbcSTim J. Robbins 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
578ea0fabbcSTim J. Robbins #endif
579ea0fabbcSTim J. Robbins 	/*
580ea0fabbcSTim J. Robbins 	 * The trampoline code hands us the sigframe.
581ea0fabbcSTim J. Robbins 	 * It is unsafe to keep track of it ourselves, in the event that a
582ea0fabbcSTim J. Robbins 	 * program jumps out of a signal handler.
583ea0fabbcSTim J. Robbins 	 */
584ea0fabbcSTim J. Robbins 	if (copyin(args->sfp, &frame, sizeof(frame)) != 0)
585ea0fabbcSTim J. Robbins 		return (EFAULT);
586ea0fabbcSTim J. Robbins 
587ea0fabbcSTim J. Robbins 	/*
588ea0fabbcSTim J. Robbins 	 * Check for security violations.
589ea0fabbcSTim J. Robbins 	 */
590ea0fabbcSTim J. Robbins #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
591ea0fabbcSTim J. Robbins 	eflags = frame.sf_sc.sc_eflags;
592ea0fabbcSTim J. Robbins 	/*
593ea0fabbcSTim J. Robbins 	 * XXX do allow users to change the privileged flag PSL_RF.  The
594ea0fabbcSTim J. Robbins 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
595ea0fabbcSTim J. Robbins 	 * sometimes set it there too.  tf_eflags is kept in the signal
596ea0fabbcSTim J. Robbins 	 * context during signal handling and there is no other place
597ea0fabbcSTim J. Robbins 	 * to remember it, so the PSL_RF bit may be corrupted by the
598ea0fabbcSTim J. Robbins 	 * signal handler without us knowing.  Corruption of the PSL_RF
599ea0fabbcSTim J. Robbins 	 * bit at worst causes one more or one less debugger trap, so
600ea0fabbcSTim J. Robbins 	 * allowing it is fairly harmless.
601ea0fabbcSTim J. Robbins 	 */
602ea0fabbcSTim J. Robbins 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF))
603ea0fabbcSTim J. Robbins 		return(EINVAL);
604ea0fabbcSTim J. Robbins 
605ea0fabbcSTim J. Robbins 	/*
606ea0fabbcSTim J. Robbins 	 * Don't allow users to load a valid privileged %cs.  Let the
607ea0fabbcSTim J. Robbins 	 * hardware check for invalid selectors, excess privilege in
608ea0fabbcSTim J. Robbins 	 * other selectors, invalid %eip's and invalid %esp's.
609ea0fabbcSTim J. Robbins 	 */
610ea0fabbcSTim J. Robbins #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
611ea0fabbcSTim J. Robbins 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
6129104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
6139104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
6149104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
6159104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
6169104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_rip;
6179104847fSDavid Xu 		trapsignal(td, &ksi);
618ea0fabbcSTim J. Robbins 		return(EINVAL);
619ea0fabbcSTim J. Robbins 	}
620ea0fabbcSTim J. Robbins 
621ea0fabbcSTim J. Robbins 	lmask.__bits[0] = frame.sf_sc.sc_mask;
622ea0fabbcSTim J. Robbins 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
623ea0fabbcSTim J. Robbins 		lmask.__bits[i+1] = frame.sf_extramask[i];
624d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&lmask, &bmask);
625d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
626ea0fabbcSTim J. Robbins 
627ea0fabbcSTim J. Robbins 	/*
628ea0fabbcSTim J. Robbins 	 * Restore signal context.
629ea0fabbcSTim J. Robbins 	 */
630ea0fabbcSTim J. Robbins 	regs->tf_rdi    = frame.sf_sc.sc_edi;
631ea0fabbcSTim J. Robbins 	regs->tf_rsi    = frame.sf_sc.sc_esi;
632ea0fabbcSTim J. Robbins 	regs->tf_rbp    = frame.sf_sc.sc_ebp;
633ea0fabbcSTim J. Robbins 	regs->tf_rbx    = frame.sf_sc.sc_ebx;
634ea0fabbcSTim J. Robbins 	regs->tf_rdx    = frame.sf_sc.sc_edx;
635ea0fabbcSTim J. Robbins 	regs->tf_rcx    = frame.sf_sc.sc_ecx;
636ea0fabbcSTim J. Robbins 	regs->tf_rax    = frame.sf_sc.sc_eax;
637ea0fabbcSTim J. Robbins 	regs->tf_rip    = frame.sf_sc.sc_eip;
638ea0fabbcSTim J. Robbins 	regs->tf_cs     = frame.sf_sc.sc_cs;
6392c66cccaSKonstantin Belousov 	regs->tf_ds     = frame.sf_sc.sc_ds;
6402c66cccaSKonstantin Belousov 	regs->tf_es     = frame.sf_sc.sc_es;
6412c66cccaSKonstantin Belousov 	regs->tf_fs     = frame.sf_sc.sc_fs;
6422c66cccaSKonstantin Belousov 	regs->tf_gs     = frame.sf_sc.sc_gs;
643ea0fabbcSTim J. Robbins 	regs->tf_rflags = eflags;
644ea0fabbcSTim J. Robbins 	regs->tf_rsp    = frame.sf_sc.sc_esp_at_signal;
645ea0fabbcSTim J. Robbins 	regs->tf_ss     = frame.sf_sc.sc_ss;
646a2622e5dSKonstantin Belousov 	td->td_pcb->pcb_full_iret = 1;
647ea0fabbcSTim J. Robbins 
648ea0fabbcSTim J. Robbins 	return (EJUSTRETURN);
649ea0fabbcSTim J. Robbins }
650ea0fabbcSTim J. Robbins 
651ea0fabbcSTim J. Robbins /*
652ea0fabbcSTim J. Robbins  * System call to cleanup state after a signal
653ea0fabbcSTim J. Robbins  * has been taken.  Reset signal mask and
654ea0fabbcSTim J. Robbins  * stack state from context left by rt_sendsig (above).
655ea0fabbcSTim J. Robbins  * Return to previous pc and psl as specified by
656ea0fabbcSTim J. Robbins  * context left by sendsig. Check carefully to
657ea0fabbcSTim J. Robbins  * make sure that the user has not modified the
658ea0fabbcSTim J. Robbins  * psl to gain improper privileges or to cause
659ea0fabbcSTim J. Robbins  * a machine fault.
660ea0fabbcSTim J. Robbins  */
661ea0fabbcSTim J. Robbins int
662ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
663ea0fabbcSTim J. Robbins {
664ea0fabbcSTim J. Robbins 	struct l_ucontext uc;
665ea0fabbcSTim J. Robbins 	struct l_sigcontext *context;
666d6e029adSKonstantin Belousov 	sigset_t bmask;
667ea0fabbcSTim J. Robbins 	l_stack_t *lss;
668ea0fabbcSTim J. Robbins 	stack_t ss;
669ea0fabbcSTim J. Robbins 	struct trapframe *regs;
670ea0fabbcSTim J. Robbins 	int eflags;
6719104847fSDavid Xu 	ksiginfo_t ksi;
672ea0fabbcSTim J. Robbins 
673ea0fabbcSTim J. Robbins 	regs = td->td_frame;
674ea0fabbcSTim J. Robbins 
675ea0fabbcSTim J. Robbins #ifdef DEBUG
676ea0fabbcSTim J. Robbins 	if (ldebug(rt_sigreturn))
677ea0fabbcSTim J. Robbins 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
678ea0fabbcSTim J. Robbins #endif
679ea0fabbcSTim J. Robbins 	/*
680ea0fabbcSTim J. Robbins 	 * The trampoline code hands us the ucontext.
681ea0fabbcSTim J. Robbins 	 * It is unsafe to keep track of it ourselves, in the event that a
682ea0fabbcSTim J. Robbins 	 * program jumps out of a signal handler.
683ea0fabbcSTim J. Robbins 	 */
684ea0fabbcSTim J. Robbins 	if (copyin(args->ucp, &uc, sizeof(uc)) != 0)
685ea0fabbcSTim J. Robbins 		return (EFAULT);
686ea0fabbcSTim J. Robbins 
687ea0fabbcSTim J. Robbins 	context = &uc.uc_mcontext;
688ea0fabbcSTim J. Robbins 
689ea0fabbcSTim J. Robbins 	/*
690ea0fabbcSTim J. Robbins 	 * Check for security violations.
691ea0fabbcSTim J. Robbins 	 */
692ea0fabbcSTim J. Robbins #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
693ea0fabbcSTim J. Robbins 	eflags = context->sc_eflags;
694ea0fabbcSTim J. Robbins 	/*
695ea0fabbcSTim J. Robbins 	 * XXX do allow users to change the privileged flag PSL_RF.  The
696ea0fabbcSTim J. Robbins 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
697ea0fabbcSTim J. Robbins 	 * sometimes set it there too.  tf_eflags is kept in the signal
698ea0fabbcSTim J. Robbins 	 * context during signal handling and there is no other place
699ea0fabbcSTim J. Robbins 	 * to remember it, so the PSL_RF bit may be corrupted by the
700ea0fabbcSTim J. Robbins 	 * signal handler without us knowing.  Corruption of the PSL_RF
701ea0fabbcSTim J. Robbins 	 * bit at worst causes one more or one less debugger trap, so
702ea0fabbcSTim J. Robbins 	 * allowing it is fairly harmless.
703ea0fabbcSTim J. Robbins 	 */
704ea0fabbcSTim J. Robbins 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF))
705ea0fabbcSTim J. Robbins 		return(EINVAL);
706ea0fabbcSTim J. Robbins 
707ea0fabbcSTim J. Robbins 	/*
708ea0fabbcSTim J. Robbins 	 * Don't allow users to load a valid privileged %cs.  Let the
709ea0fabbcSTim J. Robbins 	 * hardware check for invalid selectors, excess privilege in
710ea0fabbcSTim J. Robbins 	 * other selectors, invalid %eip's and invalid %esp's.
711ea0fabbcSTim J. Robbins 	 */
712ea0fabbcSTim J. Robbins #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
713ea0fabbcSTim J. Robbins 	if (!CS_SECURE(context->sc_cs)) {
7149104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
7159104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
7169104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
7179104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
7189104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_rip;
7199104847fSDavid Xu 		trapsignal(td, &ksi);
720ea0fabbcSTim J. Robbins 		return(EINVAL);
721ea0fabbcSTim J. Robbins 	}
722ea0fabbcSTim J. Robbins 
723d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&uc.uc_sigmask, &bmask);
724d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
725ea0fabbcSTim J. Robbins 
726ea0fabbcSTim J. Robbins 	/*
727ea0fabbcSTim J. Robbins 	 * Restore signal context
728ea0fabbcSTim J. Robbins 	 */
7292c66cccaSKonstantin Belousov 	regs->tf_gs	= context->sc_gs;
7302c66cccaSKonstantin Belousov 	regs->tf_fs	= context->sc_fs;
7312c66cccaSKonstantin Belousov 	regs->tf_es	= context->sc_es;
7322c66cccaSKonstantin Belousov 	regs->tf_ds	= context->sc_ds;
733ea0fabbcSTim J. Robbins 	regs->tf_rdi    = context->sc_edi;
734ea0fabbcSTim J. Robbins 	regs->tf_rsi    = context->sc_esi;
735ea0fabbcSTim J. Robbins 	regs->tf_rbp    = context->sc_ebp;
736ea0fabbcSTim J. Robbins 	regs->tf_rbx    = context->sc_ebx;
737ea0fabbcSTim J. Robbins 	regs->tf_rdx    = context->sc_edx;
738ea0fabbcSTim J. Robbins 	regs->tf_rcx    = context->sc_ecx;
739ea0fabbcSTim J. Robbins 	regs->tf_rax    = context->sc_eax;
740ea0fabbcSTim J. Robbins 	regs->tf_rip    = context->sc_eip;
741ea0fabbcSTim J. Robbins 	regs->tf_cs     = context->sc_cs;
742ea0fabbcSTim J. Robbins 	regs->tf_rflags = eflags;
743ea0fabbcSTim J. Robbins 	regs->tf_rsp    = context->sc_esp_at_signal;
744ea0fabbcSTim J. Robbins 	regs->tf_ss     = context->sc_ss;
745a2622e5dSKonstantin Belousov 	td->td_pcb->pcb_full_iret = 1;
746ea0fabbcSTim J. Robbins 
747ea0fabbcSTim J. Robbins 	/*
748ea0fabbcSTim J. Robbins 	 * call sigaltstack & ignore results..
749ea0fabbcSTim J. Robbins 	 */
750ea0fabbcSTim J. Robbins 	lss = &uc.uc_stack;
751ea0fabbcSTim J. Robbins 	ss.ss_sp = PTRIN(lss->ss_sp);
752ea0fabbcSTim J. Robbins 	ss.ss_size = lss->ss_size;
753ea0fabbcSTim J. Robbins 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
754ea0fabbcSTim J. Robbins 
755ea0fabbcSTim J. Robbins #ifdef DEBUG
756ea0fabbcSTim J. Robbins 	if (ldebug(rt_sigreturn))
757c680f6b1SDavid E. O'Brien 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"),
758ea0fabbcSTim J. Robbins 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
759ea0fabbcSTim J. Robbins #endif
760ea0fabbcSTim J. Robbins 	(void)kern_sigaltstack(td, &ss, NULL);
761ea0fabbcSTim J. Robbins 
762ea0fabbcSTim J. Robbins 	return (EJUSTRETURN);
763ea0fabbcSTim J. Robbins }
764ea0fabbcSTim J. Robbins 
765afe1a688SKonstantin Belousov static int
766afe1a688SKonstantin Belousov linux32_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
767ea0fabbcSTim J. Robbins {
768afe1a688SKonstantin Belousov 	struct proc *p;
769afe1a688SKonstantin Belousov 	struct trapframe *frame;
770afe1a688SKonstantin Belousov 
771afe1a688SKonstantin Belousov 	p = td->td_proc;
772afe1a688SKonstantin Belousov 	frame = td->td_frame;
773afe1a688SKonstantin Belousov 
774afe1a688SKonstantin Belousov 	sa->args[0] = frame->tf_rbx;
775afe1a688SKonstantin Belousov 	sa->args[1] = frame->tf_rcx;
776afe1a688SKonstantin Belousov 	sa->args[2] = frame->tf_rdx;
777afe1a688SKonstantin Belousov 	sa->args[3] = frame->tf_rsi;
778afe1a688SKonstantin Belousov 	sa->args[4] = frame->tf_rdi;
779afe1a688SKonstantin Belousov 	sa->args[5] = frame->tf_rbp;	/* Unconfirmed */
780afe1a688SKonstantin Belousov 	sa->code = frame->tf_rax;
781afe1a688SKonstantin Belousov 
782afe1a688SKonstantin Belousov 	if (sa->code >= p->p_sysent->sv_size)
783afe1a688SKonstantin Belousov 		sa->callp = &p->p_sysent->sv_table[0];
784afe1a688SKonstantin Belousov 	else
785afe1a688SKonstantin Belousov 		sa->callp = &p->p_sysent->sv_table[sa->code];
786afe1a688SKonstantin Belousov 	sa->narg = sa->callp->sy_narg;
787afe1a688SKonstantin Belousov 
788afe1a688SKonstantin Belousov 	td->td_retval[0] = 0;
789afe1a688SKonstantin Belousov 	td->td_retval[1] = frame->tf_rdx;
790afe1a688SKonstantin Belousov 
791afe1a688SKonstantin Belousov 	return (0);
792ea0fabbcSTim J. Robbins }
793ea0fabbcSTim J. Robbins 
794ea0fabbcSTim J. Robbins /*
795ea0fabbcSTim J. Robbins  * If a linux binary is exec'ing something, try this image activator
796ea0fabbcSTim J. Robbins  * first.  We override standard shell script execution in order to
797ea0fabbcSTim J. Robbins  * be able to modify the interpreter path.  We only do this if a linux
798ea0fabbcSTim J. Robbins  * binary is doing the exec, so we do not create an EXEC module for it.
799ea0fabbcSTim J. Robbins  */
800ea0fabbcSTim J. Robbins static int	exec_linux_imgact_try(struct image_params *iparams);
801ea0fabbcSTim J. Robbins 
802ea0fabbcSTim J. Robbins static int
803ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp)
804ea0fabbcSTim J. Robbins {
805ea0fabbcSTim J. Robbins 	const char *head = (const char *)imgp->image_header;
8061d15fdd9SJohn Baldwin 	char *rpath;
807a14a9498SAlan Cox 	int error = -1;
808ea0fabbcSTim J. Robbins 
809ea0fabbcSTim J. Robbins 	/*
810ea0fabbcSTim J. Robbins 	* The interpreter for shell scripts run from a linux binary needs
811ea0fabbcSTim J. Robbins 	* to be located in /compat/linux if possible in order to recursively
812ea0fabbcSTim J. Robbins 	* maintain linux path emulation.
813ea0fabbcSTim J. Robbins 	*/
814ea0fabbcSTim J. Robbins 	if (((const short *)head)[0] == SHELLMAGIC) {
815ea0fabbcSTim J. Robbins 		/*
816ea0fabbcSTim J. Robbins 		* Run our normal shell image activator.  If it succeeds attempt
817d065e13dSDavid E. O'Brien 		* to use the alternate path for the interpreter.  If an
818d065e13dSDavid E. O'Brien 		* alternate * path is found, use our stringspace to store it.
819ea0fabbcSTim J. Robbins 		*/
820ea0fabbcSTim J. Robbins 		if ((error = exec_shell_imgact(imgp)) == 0) {
8211d15fdd9SJohn Baldwin 			linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
822d065e13dSDavid E. O'Brien 			    imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0,
823d065e13dSDavid E. O'Brien 			    AT_FDCWD);
824a14a9498SAlan Cox 			if (rpath != NULL)
825a14a9498SAlan Cox 				imgp->args->fname_buf =
826a14a9498SAlan Cox 				    imgp->interpreter_name = rpath;
827ea0fabbcSTim J. Robbins 		}
828ea0fabbcSTim J. Robbins 	}
829ea0fabbcSTim J. Robbins 	return (error);
830ea0fabbcSTim J. Robbins }
831ea0fabbcSTim J. Robbins 
832ea0fabbcSTim J. Robbins /*
833ea0fabbcSTim J. Robbins  * Clear registers on exec
834ea0fabbcSTim J. Robbins  * XXX copied from ia32_signal.c.
835ea0fabbcSTim J. Robbins  */
836ea0fabbcSTim J. Robbins static void
837a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack)
838ea0fabbcSTim J. Robbins {
839ea0fabbcSTim J. Robbins 	struct trapframe *regs = td->td_frame;
840ea0fabbcSTim J. Robbins 	struct pcb *pcb = td->td_pcb;
841ea0fabbcSTim J. Robbins 
8422c66cccaSKonstantin Belousov 	mtx_lock(&dt_lock);
8432c66cccaSKonstantin Belousov 	if (td->td_proc->p_md.md_ldt != NULL)
8442c66cccaSKonstantin Belousov 		user_ldt_free(td);
8452c66cccaSKonstantin Belousov 	else
8462c66cccaSKonstantin Belousov 		mtx_unlock(&dt_lock);
8472c66cccaSKonstantin Belousov 
8489c5b213eSJung-uk Kim 	critical_enter();
849ea0fabbcSTim J. Robbins 	wrmsr(MSR_FSBASE, 0);
850ea0fabbcSTim J. Robbins 	wrmsr(MSR_KGSBASE, 0);	/* User value while we're in the kernel */
851ea0fabbcSTim J. Robbins 	pcb->pcb_fsbase = 0;
852ea0fabbcSTim J. Robbins 	pcb->pcb_gsbase = 0;
8539c5b213eSJung-uk Kim 	critical_exit();
8542ee8325fSJohn Baldwin 	pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
855ea0fabbcSTim J. Robbins 
856ea0fabbcSTim J. Robbins 	bzero((char *)regs, sizeof(struct trapframe));
857a107d8aaSNathan Whitehorn 	regs->tf_rip = imgp->entry_addr;
858ea0fabbcSTim J. Robbins 	regs->tf_rsp = stack;
859ea0fabbcSTim J. Robbins 	regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
8602c66cccaSKonstantin Belousov 	regs->tf_gs = _ugssel;
8612c66cccaSKonstantin Belousov 	regs->tf_fs = _ufssel;
8622c66cccaSKonstantin Belousov 	regs->tf_es = _udatasel;
8632c66cccaSKonstantin Belousov 	regs->tf_ds = _udatasel;
864ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
8652c66cccaSKonstantin Belousov 	regs->tf_flags = TF_HASSEGS;
866ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
867a107d8aaSNathan Whitehorn 	regs->tf_rbx = imgp->ps_strings;
868ea0fabbcSTim J. Robbins 	load_cr0(rcr0() | CR0_MP | CR0_TS);
8692a988f7cSStephan Uphoff 	fpstate_drop(td);
870ea0fabbcSTim J. Robbins 
871*1b3c3256SKonstantin Belousov 	/* Do full restore on return so that we can change to a different %cs */
8720f0170e6SKonstantin Belousov 	pcb->pcb_flags |= PCB_32BIT;
873f1f0dd9eSKonstantin Belousov 	pcb->pcb_flags &= ~PCB_GS32BIT;
874*1b3c3256SKonstantin Belousov 	pcb->pcb_full_iret = 1;
875ea0fabbcSTim J. Robbins 	td->td_retval[1] = 0;
876ea0fabbcSTim J. Robbins }
877ea0fabbcSTim J. Robbins 
878ea0fabbcSTim J. Robbins /*
879ea0fabbcSTim J. Robbins  * XXX copied from ia32_sysvec.c.
880ea0fabbcSTim J. Robbins  */
881ea0fabbcSTim J. Robbins static register_t *
882ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp)
883ea0fabbcSTim J. Robbins {
884ea0fabbcSTim J. Robbins 	int argc, envc;
885ea0fabbcSTim J. Robbins 	u_int32_t *vectp;
886ea0fabbcSTim J. Robbins 	char *stringp, *destp;
887ea0fabbcSTim J. Robbins 	u_int32_t *stack_base;
888ea0fabbcSTim J. Robbins 	struct linux32_ps_strings *arginfo;
889ea0fabbcSTim J. Robbins 
890ea0fabbcSTim J. Robbins 	/*
891ea0fabbcSTim J. Robbins 	 * Calculate string base and vector table pointers.
892ea0fabbcSTim J. Robbins 	 * Also deal with signal trampoline code for this exec type.
893ea0fabbcSTim J. Robbins 	 */
894ea0fabbcSTim J. Robbins 	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
8954d7c2e8aSDmitry Chagin 	destp =	(caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE -
8964d7c2e8aSDmitry Chagin 	    linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace),
8974d7c2e8aSDmitry Chagin 	    sizeof(char *));
898ea0fabbcSTim J. Robbins 
899ea0fabbcSTim J. Robbins 	/*
900ea0fabbcSTim J. Robbins 	 * install sigcode
901ea0fabbcSTim J. Robbins 	 */
902ea0fabbcSTim J. Robbins 	copyout(imgp->proc->p_sysent->sv_sigcode,
9034d7c2e8aSDmitry Chagin 	    ((caddr_t)arginfo - linux_szsigcode), linux_szsigcode);
9044d7c2e8aSDmitry Chagin 
9054d7c2e8aSDmitry Chagin 	/*
9064d7c2e8aSDmitry Chagin 	 * Install LINUX_PLATFORM
9074d7c2e8aSDmitry Chagin 	 */
9084d7c2e8aSDmitry Chagin 	copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode -
9094d7c2e8aSDmitry Chagin 	    linux_szplatform), linux_szplatform);
910ea0fabbcSTim J. Robbins 
911ea0fabbcSTim J. Robbins 	/*
912ea0fabbcSTim J. Robbins 	 * If we have a valid auxargs ptr, prepare some room
913ea0fabbcSTim J. Robbins 	 * on the stack.
914ea0fabbcSTim J. Robbins 	 */
915ea0fabbcSTim J. Robbins 	if (imgp->auxargs) {
916ea0fabbcSTim J. Robbins 		/*
917ea0fabbcSTim J. Robbins 		 * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
918ea0fabbcSTim J. Robbins 		 * lower compatibility.
919ea0fabbcSTim J. Robbins 		 */
920d065e13dSDavid E. O'Brien 		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
9214d7c2e8aSDmitry Chagin 		    (LINUX_AT_COUNT * 2);
922ea0fabbcSTim J. Robbins 		/*
923ea0fabbcSTim J. Robbins 		 * The '+ 2' is for the null pointers at the end of each of
924ea0fabbcSTim J. Robbins 		 * the arg and env vector sets,and imgp->auxarg_size is room
925ea0fabbcSTim J. Robbins 		 * for argument of Runtime loader.
926ea0fabbcSTim J. Robbins 		 */
927d065e13dSDavid E. O'Brien 		vectp = (u_int32_t *) (destp - (imgp->args->argc +
928d065e13dSDavid E. O'Brien 		    imgp->args->envc + 2 + imgp->auxarg_size) *
929d065e13dSDavid E. O'Brien 		    sizeof(u_int32_t));
930ea0fabbcSTim J. Robbins 
931ea0fabbcSTim J. Robbins 	} else
932ea0fabbcSTim J. Robbins 		/*
933ea0fabbcSTim J. Robbins 		 * The '+ 2' is for the null pointers at the end of each of
934ea0fabbcSTim J. Robbins 		 * the arg and env vector sets
935ea0fabbcSTim J. Robbins 		 */
936d065e13dSDavid E. O'Brien 		vectp = (u_int32_t *)(destp - (imgp->args->argc +
937d065e13dSDavid E. O'Brien 		    imgp->args->envc + 2) * sizeof(u_int32_t));
938ea0fabbcSTim J. Robbins 
939ea0fabbcSTim J. Robbins 	/*
940ea0fabbcSTim J. Robbins 	 * vectp also becomes our initial stack base
941ea0fabbcSTim J. Robbins 	 */
942ea0fabbcSTim J. Robbins 	stack_base = vectp;
943ea0fabbcSTim J. Robbins 
944610ecfe0SMaxim Sobolev 	stringp = imgp->args->begin_argv;
945610ecfe0SMaxim Sobolev 	argc = imgp->args->argc;
946610ecfe0SMaxim Sobolev 	envc = imgp->args->envc;
947ea0fabbcSTim J. Robbins 	/*
948ea0fabbcSTim J. Robbins 	 * Copy out strings - arguments and environment.
949ea0fabbcSTim J. Robbins 	 */
950610ecfe0SMaxim Sobolev 	copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
951ea0fabbcSTim J. Robbins 
952ea0fabbcSTim J. Robbins 	/*
953ea0fabbcSTim J. Robbins 	 * Fill in "ps_strings" struct for ps, w, etc.
954ea0fabbcSTim J. Robbins 	 */
9554d7c2e8aSDmitry Chagin 	suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp);
956ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_nargvstr, argc);
957ea0fabbcSTim J. Robbins 
958ea0fabbcSTim J. Robbins 	/*
959ea0fabbcSTim J. Robbins 	 * Fill in argument portion of vector table.
960ea0fabbcSTim J. Robbins 	 */
961ea0fabbcSTim J. Robbins 	for (; argc > 0; --argc) {
9624d7c2e8aSDmitry Chagin 		suword32(vectp++, (uint32_t)(intptr_t)destp);
963ea0fabbcSTim J. Robbins 		while (*stringp++ != 0)
964ea0fabbcSTim J. Robbins 			destp++;
965ea0fabbcSTim J. Robbins 		destp++;
966ea0fabbcSTim J. Robbins 	}
967ea0fabbcSTim J. Robbins 
968ea0fabbcSTim J. Robbins 	/* a null vector table pointer separates the argp's from the envp's */
969ea0fabbcSTim J. Robbins 	suword32(vectp++, 0);
970ea0fabbcSTim J. Robbins 
9714d7c2e8aSDmitry Chagin 	suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp);
972ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_nenvstr, envc);
973ea0fabbcSTim J. Robbins 
974ea0fabbcSTim J. Robbins 	/*
975ea0fabbcSTim J. Robbins 	 * Fill in environment portion of vector table.
976ea0fabbcSTim J. Robbins 	 */
977ea0fabbcSTim J. Robbins 	for (; envc > 0; --envc) {
9784d7c2e8aSDmitry Chagin 		suword32(vectp++, (uint32_t)(intptr_t)destp);
979ea0fabbcSTim J. Robbins 		while (*stringp++ != 0)
980ea0fabbcSTim J. Robbins 			destp++;
981ea0fabbcSTim J. Robbins 		destp++;
982ea0fabbcSTim J. Robbins 	}
983ea0fabbcSTim J. Robbins 
984ea0fabbcSTim J. Robbins 	/* end of vector table is a null pointer */
985ea0fabbcSTim J. Robbins 	suword32(vectp, 0);
986ea0fabbcSTim J. Robbins 
987ea0fabbcSTim J. Robbins 	return ((register_t *)stack_base);
988ea0fabbcSTim J. Robbins }
989ea0fabbcSTim J. Robbins 
990ea0fabbcSTim J. Robbins SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0,
991ea0fabbcSTim J. Robbins     "32-bit Linux emulation");
992ea0fabbcSTim J. Robbins 
993ea0fabbcSTim J. Robbins static u_long	linux32_maxdsiz = LINUX32_MAXDSIZ;
994ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW,
995ea0fabbcSTim J. Robbins     &linux32_maxdsiz, 0, "");
996ea0fabbcSTim J. Robbins static u_long	linux32_maxssiz = LINUX32_MAXSSIZ;
997ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW,
998ea0fabbcSTim J. Robbins     &linux32_maxssiz, 0, "");
999ea0fabbcSTim J. Robbins static u_long	linux32_maxvmem = LINUX32_MAXVMEM;
1000ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW,
1001ea0fabbcSTim J. Robbins     &linux32_maxvmem, 0, "");
1002ea0fabbcSTim J. Robbins 
1003ea0fabbcSTim J. Robbins static void
100419059a13SJohn Baldwin linux32_fixlimit(struct rlimit *rl, int which)
1005ea0fabbcSTim J. Robbins {
1006ea0fabbcSTim J. Robbins 
100719059a13SJohn Baldwin 	switch (which) {
100819059a13SJohn Baldwin 	case RLIMIT_DATA:
1009ea0fabbcSTim J. Robbins 		if (linux32_maxdsiz != 0) {
101019059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxdsiz)
101119059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxdsiz;
101219059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxdsiz)
101319059a13SJohn Baldwin 				rl->rlim_max = linux32_maxdsiz;
1014ea0fabbcSTim J. Robbins 		}
101519059a13SJohn Baldwin 		break;
101619059a13SJohn Baldwin 	case RLIMIT_STACK:
1017ea0fabbcSTim J. Robbins 		if (linux32_maxssiz != 0) {
101819059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxssiz)
101919059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxssiz;
102019059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxssiz)
102119059a13SJohn Baldwin 				rl->rlim_max = linux32_maxssiz;
1022ea0fabbcSTim J. Robbins 		}
102319059a13SJohn Baldwin 		break;
102419059a13SJohn Baldwin 	case RLIMIT_VMEM:
1025ea0fabbcSTim J. Robbins 		if (linux32_maxvmem != 0) {
102619059a13SJohn Baldwin 			if (rl->rlim_cur > linux32_maxvmem)
102719059a13SJohn Baldwin 				rl->rlim_cur = linux32_maxvmem;
102819059a13SJohn Baldwin 			if (rl->rlim_max > linux32_maxvmem)
102919059a13SJohn Baldwin 				rl->rlim_max = linux32_maxvmem;
1030ea0fabbcSTim J. Robbins 		}
103119059a13SJohn Baldwin 		break;
103219059a13SJohn Baldwin 	}
1033ea0fabbcSTim J. Robbins }
1034ea0fabbcSTim J. Robbins 
1035ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = {
1036a8d403e1SKonstantin Belousov 	.sv_size	= LINUX_SYS_MAXSYSCALL,
1037a8d403e1SKonstantin Belousov 	.sv_table	= linux_sysent,
1038a8d403e1SKonstantin Belousov 	.sv_mask	= 0,
1039a8d403e1SKonstantin Belousov 	.sv_sigsize	= LINUX_SIGTBLSZ,
1040a8d403e1SKonstantin Belousov 	.sv_sigtbl	= bsd_to_linux_signal,
1041a8d403e1SKonstantin Belousov 	.sv_errsize	= ELAST + 1,
1042a8d403e1SKonstantin Belousov 	.sv_errtbl	= bsd_to_linux_errno,
1043a8d403e1SKonstantin Belousov 	.sv_transtrap	= translate_traps,
1044a8d403e1SKonstantin Belousov 	.sv_fixup	= elf_linux_fixup,
1045a8d403e1SKonstantin Belousov 	.sv_sendsig	= linux_sendsig,
1046a8d403e1SKonstantin Belousov 	.sv_sigcode	= linux_sigcode,
1047a8d403e1SKonstantin Belousov 	.sv_szsigcode	= &linux_szsigcode,
1048afe1a688SKonstantin Belousov 	.sv_prepsyscall	= NULL,
1049a8d403e1SKonstantin Belousov 	.sv_name	= "Linux ELF32",
1050a8d403e1SKonstantin Belousov 	.sv_coredump	= elf32_coredump,
1051a8d403e1SKonstantin Belousov 	.sv_imgact_try	= exec_linux_imgact_try,
1052a8d403e1SKonstantin Belousov 	.sv_minsigstksz	= LINUX_MINSIGSTKSZ,
1053a8d403e1SKonstantin Belousov 	.sv_pagesize	= PAGE_SIZE,
1054a8d403e1SKonstantin Belousov 	.sv_minuser	= VM_MIN_ADDRESS,
1055a8d403e1SKonstantin Belousov 	.sv_maxuser	= LINUX32_USRSTACK,
1056a8d403e1SKonstantin Belousov 	.sv_usrstack	= LINUX32_USRSTACK,
1057a8d403e1SKonstantin Belousov 	.sv_psstrings	= LINUX32_PS_STRINGS,
1058a8d403e1SKonstantin Belousov 	.sv_stackprot	= VM_PROT_ALL,
1059a8d403e1SKonstantin Belousov 	.sv_copyout_strings = linux_copyout_strings,
1060a8d403e1SKonstantin Belousov 	.sv_setregs	= exec_linux_setregs,
1061a8d403e1SKonstantin Belousov 	.sv_fixlimit	= linux32_fixlimit,
1062a8d403e1SKonstantin Belousov 	.sv_maxssiz	= &linux32_maxssiz,
1063afe1a688SKonstantin Belousov 	.sv_flags	= SV_ABI_LINUX | SV_ILP32 | SV_IA32,
1064afe1a688SKonstantin Belousov 	.sv_set_syscall_retval = cpu_set_syscall_retval,
1065afe1a688SKonstantin Belousov 	.sv_fetch_syscall_args = linux32_fetch_syscall_args,
1066afe1a688SKonstantin Belousov 	.sv_syscallnames = NULL,
1067ea0fabbcSTim J. Robbins };
1068ea0fabbcSTim J. Robbins 
106989ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU";
107089ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0;
107189ffc202SBjoern A. Zeeb 
107289ffc202SBjoern A. Zeeb static boolean_t
107389ffc202SBjoern A. Zeeb linux32_trans_osrel(const Elf_Note *note, int32_t *osrel)
107489ffc202SBjoern A. Zeeb {
107589ffc202SBjoern A. Zeeb 	const Elf32_Word *desc;
107689ffc202SBjoern A. Zeeb 	uintptr_t p;
107789ffc202SBjoern A. Zeeb 
107889ffc202SBjoern A. Zeeb 	p = (uintptr_t)(note + 1);
107989ffc202SBjoern A. Zeeb 	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
108089ffc202SBjoern A. Zeeb 
108189ffc202SBjoern A. Zeeb 	desc = (const Elf32_Word *)p;
108289ffc202SBjoern A. Zeeb 	if (desc[0] != GNULINUX_ABI_DESC)
108389ffc202SBjoern A. Zeeb 		return (FALSE);
108489ffc202SBjoern A. Zeeb 
108589ffc202SBjoern A. Zeeb 	/*
108689ffc202SBjoern A. Zeeb 	 * For linux we encode osrel as follows (see linux_mib.c):
108789ffc202SBjoern A. Zeeb 	 * VVVMMMIII (version, major, minor), see linux_mib.c.
108889ffc202SBjoern A. Zeeb 	 */
108989ffc202SBjoern A. Zeeb 	*osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3];
109089ffc202SBjoern A. Zeeb 
109189ffc202SBjoern A. Zeeb 	return (TRUE);
109289ffc202SBjoern A. Zeeb }
109332c01de2SDmitry Chagin 
109432c01de2SDmitry Chagin static Elf_Brandnote linux32_brandnote = {
109589ffc202SBjoern A. Zeeb 	.hdr.n_namesz	= sizeof(GNU_ABI_VENDOR),
109689ffc202SBjoern A. Zeeb 	.hdr.n_descsz	= 16,	/* XXX at least 16 */
109732c01de2SDmitry Chagin 	.hdr.n_type	= 1,
109889ffc202SBjoern A. Zeeb 	.vendor		= GNU_ABI_VENDOR,
109989ffc202SBjoern A. Zeeb 	.flags		= BN_TRANSLATE_OSREL,
110089ffc202SBjoern A. Zeeb 	.trans_osrel	= linux32_trans_osrel
110132c01de2SDmitry Chagin };
110232c01de2SDmitry Chagin 
1103ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = {
1104a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1105a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1106a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1107a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1108a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.1",
1109a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1110a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
111132c01de2SDmitry Chagin 	.brand_note	= &linux32_brandnote,
1112cd899aadSDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
1113ea0fabbcSTim J. Robbins };
1114ea0fabbcSTim J. Robbins 
1115ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = {
1116a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1117a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1118a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1119a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1120a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.2",
1121a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1122a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
112332c01de2SDmitry Chagin 	.brand_note	= &linux32_brandnote,
1124cd899aadSDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
1125ea0fabbcSTim J. Robbins };
1126ea0fabbcSTim J. Robbins 
1127ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = {
1128ea0fabbcSTim J. Robbins 	&linux_brand,
1129ea0fabbcSTim J. Robbins 	&linux_glibc2brand,
1130ea0fabbcSTim J. Robbins 	NULL
1131ea0fabbcSTim J. Robbins };
1132ea0fabbcSTim J. Robbins 
1133ea0fabbcSTim J. Robbins static int
1134ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data)
1135ea0fabbcSTim J. Robbins {
1136ea0fabbcSTim J. Robbins 	Elf32_Brandinfo **brandinfo;
1137ea0fabbcSTim J. Robbins 	int error;
1138ea0fabbcSTim J. Robbins 	struct linux_ioctl_handler **lihp;
1139387196bfSDoug Ambrisko 	struct linux_device_handler **ldhp;
1140ea0fabbcSTim J. Robbins 
1141ea0fabbcSTim J. Robbins 	error = 0;
1142ea0fabbcSTim J. Robbins 
1143ea0fabbcSTim J. Robbins 	switch(type) {
1144ea0fabbcSTim J. Robbins 	case MOD_LOAD:
1145ea0fabbcSTim J. Robbins 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1146ea0fabbcSTim J. Robbins 		     ++brandinfo)
1147ea0fabbcSTim J. Robbins 			if (elf32_insert_brand_entry(*brandinfo) < 0)
1148ea0fabbcSTim J. Robbins 				error = EINVAL;
1149ea0fabbcSTim J. Robbins 		if (error == 0) {
1150ea0fabbcSTim J. Robbins 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1151ea0fabbcSTim J. Robbins 				linux_ioctl_register_handler(*lihp);
1152387196bfSDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
1153387196bfSDoug Ambrisko 				linux_device_register_handler(*ldhp);
1154357afa71SJung-uk Kim 			mtx_init(&emul_lock, "emuldata lock", NULL, MTX_DEF);
11557c09e6c0SAlexander Leidinger 			sx_init(&emul_shared_lock, "emuldata->shared lock");
11567c09e6c0SAlexander Leidinger 			LIST_INIT(&futex_list);
115779262bf1SDmitry Chagin 			mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF);
1158d065e13dSDavid E. O'Brien 			linux_exit_tag = EVENTHANDLER_REGISTER(process_exit,
1159d065e13dSDavid E. O'Brien 			    linux_proc_exit, NULL, 1000);
1160d065e13dSDavid E. O'Brien 			linux_schedtail_tag = EVENTHANDLER_REGISTER(schedtail,
1161d065e13dSDavid E. O'Brien 			    linux_schedtail, NULL, 1000);
1162d065e13dSDavid E. O'Brien 			linux_exec_tag = EVENTHANDLER_REGISTER(process_exec,
1163d065e13dSDavid E. O'Brien 			    linux_proc_exec, NULL, 1000);
11644d7c2e8aSDmitry Chagin 			linux_szplatform = roundup(strlen(linux_platform) + 1,
11654d7c2e8aSDmitry Chagin 			    sizeof(char *));
11667ae27ff4SJamie Gritton 			linux_osd_jail_register();
11671ca16454SDmitry Chagin 			stclohz = (stathz ? stathz : hz);
1168ea0fabbcSTim J. Robbins 			if (bootverbose)
1169ea0fabbcSTim J. Robbins 				printf("Linux ELF exec handler installed\n");
1170ea0fabbcSTim J. Robbins 		} else
1171ea0fabbcSTim J. Robbins 			printf("cannot insert Linux ELF brand handler\n");
1172ea0fabbcSTim J. Robbins 		break;
1173ea0fabbcSTim J. Robbins 	case MOD_UNLOAD:
1174ea0fabbcSTim J. Robbins 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1175ea0fabbcSTim J. Robbins 		     ++brandinfo)
1176ea0fabbcSTim J. Robbins 			if (elf32_brand_inuse(*brandinfo))
1177ea0fabbcSTim J. Robbins 				error = EBUSY;
1178ea0fabbcSTim J. Robbins 		if (error == 0) {
1179ea0fabbcSTim J. Robbins 			for (brandinfo = &linux_brandlist[0];
1180ea0fabbcSTim J. Robbins 			     *brandinfo != NULL; ++brandinfo)
1181ea0fabbcSTim J. Robbins 				if (elf32_remove_brand_entry(*brandinfo) < 0)
1182ea0fabbcSTim J. Robbins 					error = EINVAL;
1183ea0fabbcSTim J. Robbins 		}
1184ea0fabbcSTim J. Robbins 		if (error == 0) {
1185ea0fabbcSTim J. Robbins 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1186ea0fabbcSTim J. Robbins 				linux_ioctl_unregister_handler(*lihp);
1187387196bfSDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
1188387196bfSDoug Ambrisko 				linux_device_unregister_handler(*ldhp);
1189357afa71SJung-uk Kim 			mtx_destroy(&emul_lock);
11907c09e6c0SAlexander Leidinger 			sx_destroy(&emul_shared_lock);
119179262bf1SDmitry Chagin 			mtx_destroy(&futex_mtx);
11927c09e6c0SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
11937c09e6c0SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(schedtail, linux_schedtail_tag);
11947c09e6c0SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
11957ae27ff4SJamie Gritton 			linux_osd_jail_deregister();
1196ea0fabbcSTim J. Robbins 			if (bootverbose)
1197ea0fabbcSTim J. Robbins 				printf("Linux ELF exec handler removed\n");
1198ea0fabbcSTim J. Robbins 		} else
1199ea0fabbcSTim J. Robbins 			printf("Could not deinstall ELF interpreter entry\n");
1200ea0fabbcSTim J. Robbins 		break;
1201ea0fabbcSTim J. Robbins 	default:
1202786e4fc4SAlexander Leidinger 		return EOPNOTSUPP;
1203ea0fabbcSTim J. Robbins 	}
1204ea0fabbcSTim J. Robbins 	return error;
1205ea0fabbcSTim J. Robbins }
1206ea0fabbcSTim J. Robbins 
1207ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = {
1208ea0fabbcSTim J. Robbins 	"linuxelf",
1209ea0fabbcSTim J. Robbins 	linux_elf_modevent,
1210ea0fabbcSTim J. Robbins 	0
1211ea0fabbcSTim J. Robbins };
1212ea0fabbcSTim J. Robbins 
121378ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
1214