xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision 96a2b63525c3b22336e51fdf00467219fc94b215)
1d66a5066SPeter Wemm /*-
2e1743d02SSøren Schmidt  * Copyright (c) 1994-1996 S�ren Schmidt
3d66a5066SPeter Wemm  * All rights reserved.
4d66a5066SPeter Wemm  *
5d66a5066SPeter Wemm  * Redistribution and use in source and binary forms, with or without
6d66a5066SPeter Wemm  * modification, are permitted provided that the following conditions
7d66a5066SPeter Wemm  * are met:
8d66a5066SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
9d66a5066SPeter Wemm  *    notice, this list of conditions and the following disclaimer
10d66a5066SPeter Wemm  *    in this position and unchanged.
11d66a5066SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
12d66a5066SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
13d66a5066SPeter Wemm  *    documentation and/or other materials provided with the distribution.
14d66a5066SPeter Wemm  * 3. The name of the author may not be used to endorse or promote products
1521dc7d4fSJens Schweikhardt  *    derived from this software without specific prior written permission
16d66a5066SPeter Wemm  *
17d66a5066SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18d66a5066SPeter Wemm  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19d66a5066SPeter Wemm  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20d66a5066SPeter Wemm  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21d66a5066SPeter Wemm  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22d66a5066SPeter Wemm  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23d66a5066SPeter Wemm  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24d66a5066SPeter Wemm  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25d66a5066SPeter Wemm  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26d66a5066SPeter Wemm  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27d66a5066SPeter Wemm  */
28d66a5066SPeter Wemm 
2927e0099cSDavid E. O'Brien #include <sys/cdefs.h>
3027e0099cSDavid E. O'Brien __FBSDID("$FreeBSD$");
3127e0099cSDavid E. O'Brien 
32d66a5066SPeter Wemm #include <sys/param.h>
3375f83872SPeter Wemm #include <sys/systm.h>
34ff22c670SBruce Evans #include <sys/exec.h>
35d66a5066SPeter Wemm #include <sys/imgact.h>
3622d4b0fbSJohn Polstra #include <sys/imgact_aout.h>
37e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
38ff22c670SBruce Evans #include <sys/kernel.h>
397106ca0dSJohn Baldwin #include <sys/lock.h>
40e1743d02SSøren Schmidt #include <sys/malloc.h>
41ff22c670SBruce Evans #include <sys/module.h>
4223955314SAlfred Perlstein #include <sys/mutex.h>
43fb919e4dSMark Murray #include <sys/proc.h>
44fb919e4dSMark Murray #include <sys/signalvar.h>
45206a5d3aSIan Dowse #include <sys/syscallsubr.h>
46fb919e4dSMark Murray #include <sys/sysent.h>
47fb919e4dSMark Murray #include <sys/sysproto.h>
48a9148ab1SPeter Wemm #include <sys/vnode.h>
499b44bfc5SAlexander Leidinger #include <sys/eventhandler.h>
50fb919e4dSMark Murray 
51d66a5066SPeter Wemm #include <vm/vm.h>
52a9148ab1SPeter Wemm #include <vm/pmap.h>
53ff22c670SBruce Evans #include <vm/vm_extern.h>
54a9148ab1SPeter Wemm #include <vm/vm_map.h>
55a9148ab1SPeter Wemm #include <vm/vm_object.h>
56ff22c670SBruce Evans #include <vm/vm_page.h>
57ff22c670SBruce Evans #include <vm/vm_param.h>
58ff22c670SBruce Evans 
59ff22c670SBruce Evans #include <machine/cpu.h>
60ff22c670SBruce Evans #include <machine/md_var.h>
61d3adf769SDavid Schultz #include <machine/pcb.h>
62a9148ab1SPeter Wemm 
63d66a5066SPeter Wemm #include <i386/linux/linux.h>
64ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h>
6594cb2ecfSAlexander Leidinger #include <compat/linux/linux_emul.h>
660f9d6538SJohn Baldwin #include <compat/linux/linux_mib.h>
67b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h>
68322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h>
69e1743d02SSøren Schmidt 
701d91482dSPeter Wemm MODULE_VERSION(linux, 1);
711d91482dSPeter Wemm 
7243bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
7343bef515SMarcel Moolenaar 
74d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN
75d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2123 /* #! */
76d323ddf3SMatthew Dillon #else
77d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2321
78d323ddf3SMatthew Dillon #endif
79d323ddf3SMatthew Dillon 
80e061a6caSMarcel Moolenaar /*
81e061a6caSMarcel Moolenaar  * Allow the sendsig functions to use the ldebug() facility
82e061a6caSMarcel Moolenaar  * even though they are not syscalls themselves. Map them
83e061a6caSMarcel Moolenaar  * to syscall 0. This is slightly less bogus than using
84e061a6caSMarcel Moolenaar  * ldebug(sigreturn).
85e061a6caSMarcel Moolenaar  */
86e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_rt_sendsig	0
87e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_sendsig		0
88e061a6caSMarcel Moolenaar 
892a51b9b0SDavid Schultz #define	fldcw(addr)		__asm("fldcw %0" : : "m" (*(addr)))
902a51b9b0SDavid Schultz #define	__LINUX_NPXCW__		0x37f
912a51b9b0SDavid Schultz 
9243bef515SMarcel Moolenaar extern char linux_sigcode[];
9343bef515SMarcel Moolenaar extern int linux_szsigcode;
9443bef515SMarcel Moolenaar 
9543bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
9643bef515SMarcel Moolenaar 
97f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
98060e4882SDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
9943bef515SMarcel Moolenaar 
10089c9a483SAlfred Perlstein static int	linux_fixup(register_t **stack_base,
10189c9a483SAlfred Perlstein 		    struct image_params *iparams);
10289c9a483SAlfred Perlstein static int	elf_linux_fixup(register_t **stack_base,
10389c9a483SAlfred Perlstein 		    struct image_params *iparams);
104bda2a3afSBruce Evans static void	linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
105bda2a3afSBruce Evans 		    caddr_t *params);
1069104847fSDavid Xu static void     linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
107598d45beSMatthew N. Dodd static void	exec_linux_setregs(struct thread *td, u_long entry,
108598d45beSMatthew N. Dodd 				   u_long stack, u_long ps_strings);
109d66a5066SPeter Wemm 
1109b44bfc5SAlexander Leidinger extern LIST_HEAD(futex_list, futex) futex_list;
111bb59e63fSAlexander Leidinger extern struct sx futex_sx;
1129b44bfc5SAlexander Leidinger 
1139b44bfc5SAlexander Leidinger static eventhandler_tag linux_exit_tag;
1149b44bfc5SAlexander Leidinger static eventhandler_tag linux_schedtail_tag;
1159b44bfc5SAlexander Leidinger static eventhandler_tag linux_exec_tag;
1169b44bfc5SAlexander Leidinger 
117d66a5066SPeter Wemm /*
118d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
11950e422f0SAlexander Leidinger  * Reference:
12050e422f0SAlexander Leidinger  *   FreeBSD: src/sys/sys/errno.h
12150e422f0SAlexander Leidinger  *   Linux:   linux-2.6.17.8/include/asm-generic/errno-base.h
12250e422f0SAlexander Leidinger  *            linux-2.6.17.8/include/asm-generic/errno.h
123d66a5066SPeter Wemm  */
12485f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
125d66a5066SPeter Wemm 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
126d66a5066SPeter Wemm 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
127d66a5066SPeter Wemm 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
128d66a5066SPeter Wemm 	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
129d66a5066SPeter Wemm 	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
130d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
131d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
132d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
13350e422f0SAlexander Leidinger 	  -6,  -6, -43, -42, -75,-125, -84, -95, -16, -74,
13450e422f0SAlexander Leidinger 	 -72, -67, -71
135d66a5066SPeter Wemm };
136d66a5066SPeter Wemm 
137956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
138956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
139956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
140ba873f4cSAlexander Kabaev 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
141956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
142956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
143956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
144956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
145956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
146d66a5066SPeter Wemm };
147d66a5066SPeter Wemm 
148956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
149956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
150956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
151956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
152956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
153956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
154956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
155956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
156ba873f4cSAlexander Kabaev 	SIGIO, SIGURG, SIGSYS
157d66a5066SPeter Wemm };
158d66a5066SPeter Wemm 
15927a828fcSPierre Beyssac #define LINUX_T_UNKNOWN  255
16027a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = {
16127a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 0 */
16227a828fcSPierre Beyssac 	6,			/* 1  T_PRIVINFLT */
16327a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 2 */
16427a828fcSPierre Beyssac 	3,			/* 3  T_BPTFLT */
16527a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 4 */
16627a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 5 */
16727a828fcSPierre Beyssac 	16,			/* 6  T_ARITHTRAP */
16827a828fcSPierre Beyssac 	254,			/* 7  T_ASTFLT */
16927a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 8 */
17027a828fcSPierre Beyssac 	13,			/* 9  T_PROTFLT */
17127a828fcSPierre Beyssac 	1,			/* 10 T_TRCTRAP */
17227a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 11 */
17327a828fcSPierre Beyssac 	14,			/* 12 T_PAGEFLT */
17427a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 13 */
17527a828fcSPierre Beyssac 	17,			/* 14 T_ALIGNFLT */
17627a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 15 */
17727a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 16 */
17827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 17 */
17927a828fcSPierre Beyssac 	0,			/* 18 T_DIVIDE */
18027a828fcSPierre Beyssac 	2,			/* 19 T_NMI */
18127a828fcSPierre Beyssac 	4,			/* 20 T_OFLOW */
18227a828fcSPierre Beyssac 	5,			/* 21 T_BOUND */
18327a828fcSPierre Beyssac 	7,			/* 22 T_DNA */
18427a828fcSPierre Beyssac 	8,			/* 23 T_DOUBLEFLT */
18527a828fcSPierre Beyssac 	9,			/* 24 T_FPOPFLT */
18627a828fcSPierre Beyssac 	10,			/* 25 T_TSSFLT */
18727a828fcSPierre Beyssac 	11,			/* 26 T_SEGNPFLT */
18827a828fcSPierre Beyssac 	12,			/* 27 T_STKFLT */
18927a828fcSPierre Beyssac 	18,			/* 28 T_MCHK */
19027a828fcSPierre Beyssac 	19,			/* 29 T_XMMFLT */
19127a828fcSPierre Beyssac 	15			/* 30 T_RESERVED */
19227a828fcSPierre Beyssac };
19327a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \
19427a828fcSPierre Beyssac     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
19527a828fcSPierre Beyssac      _bsd_to_linux_trapcode[(code)]: \
19627a828fcSPierre Beyssac      LINUX_T_UNKNOWN)
19727a828fcSPierre Beyssac 
198288078beSEivind Eklund /*
199288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
200288078beSEivind Eklund  * means, deal with it here.
201356861dbSMatthew Dillon  *
202356861dbSMatthew Dillon  * MPSAFE
203288078beSEivind Eklund  */
204288078beSEivind Eklund static int
205288078beSEivind Eklund translate_traps(int signal, int trap_code)
206288078beSEivind Eklund {
207d563a53aSEivind Eklund 	if (signal != SIGBUS)
208d563a53aSEivind Eklund 		return signal;
209288078beSEivind Eklund 	switch (trap_code) {
210288078beSEivind Eklund 	case T_PROTFLT:
211288078beSEivind Eklund 	case T_TSSFLT:
212288078beSEivind Eklund 	case T_DOUBLEFLT:
213288078beSEivind Eklund 	case T_PAGEFLT:
214288078beSEivind Eklund 		return SIGSEGV;
215288078beSEivind Eklund 	default:
216288078beSEivind Eklund 		return signal;
217288078beSEivind Eklund 	}
218288078beSEivind Eklund }
219288078beSEivind Eklund 
220303b270bSEivind Eklund static int
221654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp)
222d66a5066SPeter Wemm {
223654f6be1SBruce Evans 	register_t *argv, *envp;
224d66a5066SPeter Wemm 
225d66a5066SPeter Wemm 	argv = *stack_base;
226610ecfe0SMaxim Sobolev 	envp = *stack_base + (imgp->args->argc + 1);
227d66a5066SPeter Wemm 	(*stack_base)--;
22886a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
229d66a5066SPeter Wemm 	(*stack_base)--;
23086a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
231d66a5066SPeter Wemm 	(*stack_base)--;
232610ecfe0SMaxim Sobolev 	**stack_base = imgp->args->argc;
233e1743d02SSøren Schmidt 	return 0;
234d66a5066SPeter Wemm }
235d66a5066SPeter Wemm 
236303b270bSEivind Eklund static int
237654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
238e1743d02SSøren Schmidt {
23943cf129cSJohn Baldwin 	Elf32_Auxargs *args;
240654f6be1SBruce Evans 	register_t *pos;
241d66a5066SPeter Wemm 
24243cf129cSJohn Baldwin 	KASSERT(curthread->td_proc == imgp->proc &&
2430e2a4d3aSDavid Xu 	    (curthread->td_proc->p_flag & P_SA) == 0,
24443cf129cSJohn Baldwin 	    ("unsafe elf_linux_fixup(), should be curproc"));
24543cf129cSJohn Baldwin 	args = (Elf32_Auxargs *)imgp->auxargs;
246610ecfe0SMaxim Sobolev 	pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
247e1743d02SSøren Schmidt 
248b07cd97eSMark Murray 	if (args->trace)
249e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
250b07cd97eSMark Murray 	if (args->execfd != -1)
251e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
252e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
253e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
254e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
255e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
256e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
257e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
258e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
259b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
260b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
261b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
262b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
263e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
264e1743d02SSøren Schmidt 
265e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
266e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
267e1743d02SSøren Schmidt 
268e1743d02SSøren Schmidt 	(*stack_base)--;
269610ecfe0SMaxim Sobolev 	**stack_base = (register_t)imgp->args->argc;
270e1743d02SSøren Schmidt 	return 0;
271e1743d02SSøren Schmidt }
272d66a5066SPeter Wemm 
273d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
27402318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode;
27579363394SAndrew Gallatin 
27679363394SAndrew Gallatin static void
2779104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
27879363394SAndrew Gallatin {
2791d062e2bSDag-Erling Smørgrav 	struct thread *td = curthread;
2801d062e2bSDag-Erling Smørgrav 	struct proc *p = td->td_proc;
28190af4afaSJohn Baldwin 	struct sigacts *psp;
2821d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
2835002a60fSMarcel Moolenaar 	struct l_rt_sigframe *fp, frame;
2849104847fSDavid Xu 	int sig, code;
28579363394SAndrew Gallatin 	int oonstack;
28679363394SAndrew Gallatin 
2879104847fSDavid Xu 	sig = ksi->ksi_signo;
2889104847fSDavid Xu 	code = ksi->ksi_code;
289df53e91cSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
29090af4afaSJohn Baldwin 	psp = p->p_sigacts;
29190af4afaSJohn Baldwin 	mtx_assert(&psp->ps_mtx, MA_OWNED);
292b40ce416SJulian Elischer 	regs = td->td_frame;
293d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
29479363394SAndrew Gallatin 
29579363394SAndrew Gallatin #ifdef DEBUG
2965002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
297728ef954SJohn Baldwin 		printf(ARGS(rt_sendsig, "%p, %d, %p, %u"),
29824593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
29979363394SAndrew Gallatin #endif
30079363394SAndrew Gallatin 	/*
30179363394SAndrew Gallatin 	 * Allocate space for the signal handler context.
30279363394SAndrew Gallatin 	 */
303a30ec4b9SDavid Xu 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
30490af4afaSJohn Baldwin 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
305a30ec4b9SDavid Xu 		fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp +
306a30ec4b9SDavid Xu 		    td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe));
307d034d459SMarcel Moolenaar 	} else
3085002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)regs->tf_esp - 1;
30990af4afaSJohn Baldwin 	mtx_unlock(&psp->ps_mtx);
31079363394SAndrew Gallatin 
31179363394SAndrew Gallatin 	/*
31279363394SAndrew Gallatin 	 * Build the argument list for the signal handler.
31379363394SAndrew Gallatin 	 */
31479363394SAndrew Gallatin 	if (p->p_sysent->sv_sigtbl)
31579363394SAndrew Gallatin 		if (sig <= p->p_sysent->sv_sigsize)
31679363394SAndrew Gallatin 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
31779363394SAndrew Gallatin 
31899d45c5fSMarcel Moolenaar 	bzero(&frame, sizeof(frame));
31999d45c5fSMarcel Moolenaar 
32079363394SAndrew Gallatin 	frame.sf_handler = catcher;
32179363394SAndrew Gallatin 	frame.sf_sig = sig;
32279363394SAndrew Gallatin 	frame.sf_siginfo = &fp->sf_si;
32379363394SAndrew Gallatin 	frame.sf_ucontext = &fp->sf_sc;
324cc6ca9b3SMarcel Moolenaar 
3259d05b77dSJuli Mallett 	/* Fill in POSIX parts */
32679363394SAndrew Gallatin 	frame.sf_si.lsi_signo = sig;
32779363394SAndrew Gallatin 	frame.sf_si.lsi_code = code;
3289104847fSDavid Xu 	frame.sf_si.lsi_addr = ksi->ksi_addr;
329cc6ca9b3SMarcel Moolenaar 
33079363394SAndrew Gallatin 	/*
33179363394SAndrew Gallatin 	 * Build the signal context to be used by sigreturn.
33279363394SAndrew Gallatin 	 */
333cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
334cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_link = NULL;		/* XXX ??? */
335cc6ca9b3SMarcel Moolenaar 
336a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp;
337a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size;
338a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
339d034d459SMarcel Moolenaar 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
340611d9407SJohn Baldwin 	PROC_UNLOCK(p);
341cc6ca9b3SMarcel Moolenaar 
342cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
343cc6ca9b3SMarcel Moolenaar 
344cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
34579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_gs     = rgs();
34679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
34779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
34879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
34979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_edi;
35079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_esi;
35179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_ebp;
35279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_ebx;
35379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_edx;
35479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_ecx;
35579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_eax;
35679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_eip;
35779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
35879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags;
35979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp;
36079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
36179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
36296a2b635SKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_cr2    = (register_t)ksi->ksi_addr;
36327a828fcSPierre Beyssac 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
36479363394SAndrew Gallatin 
36579363394SAndrew Gallatin #ifdef DEBUG
3665002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
36724593369SJonathan Lemon 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
3689b778a16SDavid Xu 		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
3699b778a16SDavid Xu 		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
37079363394SAndrew Gallatin #endif
37179363394SAndrew Gallatin 
37279363394SAndrew Gallatin 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
37379363394SAndrew Gallatin 		/*
37479363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
37579363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
37679363394SAndrew Gallatin 		 */
37789734883SAlan Cox #ifdef DEBUG
37889734883SAlan Cox 		if (ldebug(rt_sendsig))
37989734883SAlan Cox 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
38089734883SAlan Cox 			    fp, oonstack);
38189734883SAlan Cox #endif
38219eb87d2SJohn Baldwin 		PROC_LOCK(p);
383b40ce416SJulian Elischer 		sigexit(td, SIGILL);
38479363394SAndrew Gallatin 	}
38579363394SAndrew Gallatin 
38679363394SAndrew Gallatin 	/*
38779363394SAndrew Gallatin 	 * Build context to run handler in.
38879363394SAndrew Gallatin 	 */
38979363394SAndrew Gallatin 	regs->tf_esp = (int)fp;
39079363394SAndrew Gallatin 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) +
39102318dacSJake Burkholder 	    linux_sznonrtsigcode;
392846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
39379363394SAndrew Gallatin 	regs->tf_cs = _ucodesel;
39479363394SAndrew Gallatin 	regs->tf_ds = _udatasel;
39579363394SAndrew Gallatin 	regs->tf_es = _udatasel;
39679363394SAndrew Gallatin 	regs->tf_fs = _udatasel;
39779363394SAndrew Gallatin 	regs->tf_ss = _udatasel;
398df53e91cSJohn Baldwin 	PROC_LOCK(p);
39990af4afaSJohn Baldwin 	mtx_lock(&psp->ps_mtx);
40079363394SAndrew Gallatin }
40179363394SAndrew Gallatin 
402d66a5066SPeter Wemm 
403d66a5066SPeter Wemm /*
404d66a5066SPeter Wemm  * Send an interrupt to process.
405d66a5066SPeter Wemm  *
406d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
407d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
408d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
409d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
410d66a5066SPeter Wemm  * frame pointer, it returns to the user
411d66a5066SPeter Wemm  * specified pc, psl.
412d66a5066SPeter Wemm  */
413303b270bSEivind Eklund static void
4149104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
415d66a5066SPeter Wemm {
4161d062e2bSDag-Erling Smørgrav 	struct thread *td = curthread;
4171d062e2bSDag-Erling Smørgrav 	struct proc *p = td->td_proc;
41890af4afaSJohn Baldwin 	struct sigacts *psp;
4191d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
4205002a60fSMarcel Moolenaar 	struct l_sigframe *fp, frame;
4215002a60fSMarcel Moolenaar 	l_sigset_t lmask;
4229104847fSDavid Xu 	int sig, code;
4232c4ab9ddSAndrew Gallatin 	int oonstack, i;
424d66a5066SPeter Wemm 
4252509e6c2SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
42690af4afaSJohn Baldwin 	psp = p->p_sigacts;
4279104847fSDavid Xu 	sig = ksi->ksi_signo;
4289104847fSDavid Xu 	code = ksi->ksi_code;
42990af4afaSJohn Baldwin 	mtx_assert(&psp->ps_mtx, MA_OWNED);
43090af4afaSJohn Baldwin 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
431cc6ca9b3SMarcel Moolenaar 		/* Signal handler installed with SA_SIGINFO. */
4329104847fSDavid Xu 		linux_rt_sendsig(catcher, ksi, mask);
433cc6ca9b3SMarcel Moolenaar 		return;
434cc6ca9b3SMarcel Moolenaar 	}
435b40ce416SJulian Elischer 	regs = td->td_frame;
436d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
437d66a5066SPeter Wemm 
438d66a5066SPeter Wemm #ifdef DEBUG
4395002a60fSMarcel Moolenaar 	if (ldebug(sendsig))
440728ef954SJohn Baldwin 		printf(ARGS(sendsig, "%p, %d, %p, %u"),
44124593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
442d66a5066SPeter Wemm #endif
44379363394SAndrew Gallatin 
444d66a5066SPeter Wemm 	/*
445d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
446d66a5066SPeter Wemm 	 */
447a30ec4b9SDavid Xu 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
44890af4afaSJohn Baldwin 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
449a30ec4b9SDavid Xu 		fp = (struct l_sigframe *)(td->td_sigstk.ss_sp +
450a30ec4b9SDavid Xu 		    td->td_sigstk.ss_size - sizeof(struct l_sigframe));
451d034d459SMarcel Moolenaar 	} else
4525002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)regs->tf_esp - 1;
45390af4afaSJohn Baldwin 	mtx_unlock(&psp->ps_mtx);
454611d9407SJohn Baldwin 	PROC_UNLOCK(p);
455d66a5066SPeter Wemm 
456d66a5066SPeter Wemm 	/*
457d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
458d66a5066SPeter Wemm 	 */
459956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
460956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
461956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
462d66a5066SPeter Wemm 
46399d45c5fSMarcel Moolenaar 	bzero(&frame, sizeof(frame));
46499d45c5fSMarcel Moolenaar 
465d66a5066SPeter Wemm 	frame.sf_handler = catcher;
466d66a5066SPeter Wemm 	frame.sf_sig = sig;
467d66a5066SPeter Wemm 
468cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &lmask);
469cc6ca9b3SMarcel Moolenaar 
470d66a5066SPeter Wemm 	/*
471d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
472d66a5066SPeter Wemm 	 */
473cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.sc_mask   = lmask.__bits[0];
4745206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
4755206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
476213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
477213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
478213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
479213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
480213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
481213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
482213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
483213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
484213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
485213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
486213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
487213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
488213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
489213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
490213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
49196a2b635SKonstantin Belousov 	frame.sf_sc.sc_cr2    = (register_t)ksi->ksi_addr;
4929104847fSDavid Xu 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(ksi->ksi_trapno);
493cc6ca9b3SMarcel Moolenaar 
4942c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
495cc6ca9b3SMarcel Moolenaar 		frame.sf_extramask[i] = lmask.__bits[i+1];
496d66a5066SPeter Wemm 
497d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
498d66a5066SPeter Wemm 		/*
499d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
500d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
501d66a5066SPeter Wemm 		 */
50219eb87d2SJohn Baldwin 		PROC_LOCK(p);
503b40ce416SJulian Elischer 		sigexit(td, SIGILL);
504d66a5066SPeter Wemm 	}
505d66a5066SPeter Wemm 
506d66a5066SPeter Wemm 	/*
507d66a5066SPeter Wemm 	 * Build context to run handler in.
508d66a5066SPeter Wemm 	 */
509213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
5104c56fcdeSBruce Evans 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
511846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
512213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
513213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
514213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
5155206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
516213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
5175002a60fSMarcel Moolenaar 	PROC_LOCK(p);
51890af4afaSJohn Baldwin 	mtx_lock(&psp->ps_mtx);
519d66a5066SPeter Wemm }
520d66a5066SPeter Wemm 
521d66a5066SPeter Wemm /*
522d66a5066SPeter Wemm  * System call to cleanup state after a signal
523d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
524d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
525d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
526d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
527d66a5066SPeter Wemm  * make sure that the user has not modified the
528d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
529d66a5066SPeter Wemm  * a machine fault.
530d66a5066SPeter Wemm  */
531d66a5066SPeter Wemm int
532b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
533d66a5066SPeter Wemm {
534b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
5355002a60fSMarcel Moolenaar 	struct l_sigframe frame;
5361d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
5375002a60fSMarcel Moolenaar 	l_sigset_t lmask;
5382c4ab9ddSAndrew Gallatin 	int eflags, i;
5399104847fSDavid Xu 	ksiginfo_t ksi;
540d66a5066SPeter Wemm 
541b40ce416SJulian Elischer 	regs = td->td_frame;
542d66a5066SPeter Wemm 
543d66a5066SPeter Wemm #ifdef DEBUG
54424593369SJonathan Lemon 	if (ldebug(sigreturn))
54524593369SJonathan Lemon 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
546d66a5066SPeter Wemm #endif
547d66a5066SPeter Wemm 	/*
548cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the sigframe.
549d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
550d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
551d66a5066SPeter Wemm 	 */
5524b7ef73dSDag-Erling Smørgrav 	if (copyin(args->sfp, &frame, sizeof(frame)) != 0)
553d66a5066SPeter Wemm 		return (EFAULT);
554d66a5066SPeter Wemm 
555d66a5066SPeter Wemm 	/*
556d66a5066SPeter Wemm 	 * Check for security violations.
557d66a5066SPeter Wemm 	 */
558d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
559cc6ca9b3SMarcel Moolenaar 	eflags = frame.sf_sc.sc_eflags;
560d66a5066SPeter Wemm 	/*
561d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
562d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
563d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
564d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
565d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
566d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
567d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
568d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
569d66a5066SPeter Wemm 	 */
570b07cd97eSMark Murray 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF))
571d66a5066SPeter Wemm 		return(EINVAL);
572d66a5066SPeter Wemm 
573d66a5066SPeter Wemm 	/*
574d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
575d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
576d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
577d66a5066SPeter Wemm 	 */
57840d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
579cc6ca9b3SMarcel Moolenaar 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
5809104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
5819104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
5829104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
5839104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
5849104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_eip;
5859104847fSDavid Xu 		trapsignal(td, &ksi);
586d66a5066SPeter Wemm 		return(EINVAL);
587d66a5066SPeter Wemm 	}
588d66a5066SPeter Wemm 
589cc6ca9b3SMarcel Moolenaar 	lmask.__bits[0] = frame.sf_sc.sc_mask;
5902c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
591cc6ca9b3SMarcel Moolenaar 		lmask.__bits[i+1] = frame.sf_extramask[i];
592611d9407SJohn Baldwin 	PROC_LOCK(p);
5934093529dSJeff Roberson 	linux_to_bsd_sigset(&lmask, &td->td_sigmask);
5944093529dSJeff Roberson 	SIG_CANTMASK(td->td_sigmask);
5954093529dSJeff Roberson 	signotify(td);
596611d9407SJohn Baldwin 	PROC_UNLOCK(p);
597956d3333SMarcel Moolenaar 
598d66a5066SPeter Wemm 	/*
599d66a5066SPeter Wemm 	 * Restore signal context.
600d66a5066SPeter Wemm 	 */
6015206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
602cc6ca9b3SMarcel Moolenaar 	regs->tf_fs     = frame.sf_sc.sc_fs;
603cc6ca9b3SMarcel Moolenaar 	regs->tf_es     = frame.sf_sc.sc_es;
604cc6ca9b3SMarcel Moolenaar 	regs->tf_ds     = frame.sf_sc.sc_ds;
605cc6ca9b3SMarcel Moolenaar 	regs->tf_edi    = frame.sf_sc.sc_edi;
606cc6ca9b3SMarcel Moolenaar 	regs->tf_esi    = frame.sf_sc.sc_esi;
607cc6ca9b3SMarcel Moolenaar 	regs->tf_ebp    = frame.sf_sc.sc_ebp;
608cc6ca9b3SMarcel Moolenaar 	regs->tf_ebx    = frame.sf_sc.sc_ebx;
609cc6ca9b3SMarcel Moolenaar 	regs->tf_edx    = frame.sf_sc.sc_edx;
610cc6ca9b3SMarcel Moolenaar 	regs->tf_ecx    = frame.sf_sc.sc_ecx;
611cc6ca9b3SMarcel Moolenaar 	regs->tf_eax    = frame.sf_sc.sc_eax;
612cc6ca9b3SMarcel Moolenaar 	regs->tf_eip    = frame.sf_sc.sc_eip;
613cc6ca9b3SMarcel Moolenaar 	regs->tf_cs     = frame.sf_sc.sc_cs;
614213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
615cc6ca9b3SMarcel Moolenaar 	regs->tf_esp    = frame.sf_sc.sc_esp_at_signal;
616cc6ca9b3SMarcel Moolenaar 	regs->tf_ss     = frame.sf_sc.sc_ss;
617d66a5066SPeter Wemm 
618d66a5066SPeter Wemm 	return (EJUSTRETURN);
619d66a5066SPeter Wemm }
620d66a5066SPeter Wemm 
62179363394SAndrew Gallatin /*
62279363394SAndrew Gallatin  * System call to cleanup state after a signal
62379363394SAndrew Gallatin  * has been taken.  Reset signal mask and
62479363394SAndrew Gallatin  * stack state from context left by rt_sendsig (above).
62579363394SAndrew Gallatin  * Return to previous pc and psl as specified by
62679363394SAndrew Gallatin  * context left by sendsig. Check carefully to
62779363394SAndrew Gallatin  * make sure that the user has not modified the
62879363394SAndrew Gallatin  * psl to gain improper privileges or to cause
62979363394SAndrew Gallatin  * a machine fault.
63079363394SAndrew Gallatin  */
63179363394SAndrew Gallatin int
632b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
63379363394SAndrew Gallatin {
634b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
6355002a60fSMarcel Moolenaar 	struct l_ucontext uc;
6365002a60fSMarcel Moolenaar 	struct l_sigcontext *context;
6375002a60fSMarcel Moolenaar 	l_stack_t *lss;
638206a5d3aSIan Dowse 	stack_t ss;
6391d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
64079363394SAndrew Gallatin 	int eflags;
6419104847fSDavid Xu 	ksiginfo_t ksi;
64279363394SAndrew Gallatin 
643b40ce416SJulian Elischer 	regs = td->td_frame;
64479363394SAndrew Gallatin 
64579363394SAndrew Gallatin #ifdef DEBUG
64624593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
64724593369SJonathan Lemon 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
64879363394SAndrew Gallatin #endif
64979363394SAndrew Gallatin 	/*
650cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the ucontext.
65179363394SAndrew Gallatin 	 * It is unsafe to keep track of it ourselves, in the event that a
65279363394SAndrew Gallatin 	 * program jumps out of a signal handler.
65379363394SAndrew Gallatin 	 */
6544b7ef73dSDag-Erling Smørgrav 	if (copyin(args->ucp, &uc, sizeof(uc)) != 0)
65579363394SAndrew Gallatin 		return (EFAULT);
65679363394SAndrew Gallatin 
65779363394SAndrew Gallatin 	context = &uc.uc_mcontext;
65879363394SAndrew Gallatin 
65979363394SAndrew Gallatin 	/*
66079363394SAndrew Gallatin 	 * Check for security violations.
66179363394SAndrew Gallatin 	 */
66279363394SAndrew Gallatin #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
66379363394SAndrew Gallatin 	eflags = context->sc_eflags;
66479363394SAndrew Gallatin 	/*
66579363394SAndrew Gallatin 	 * XXX do allow users to change the privileged flag PSL_RF.  The
66679363394SAndrew Gallatin 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
66779363394SAndrew Gallatin 	 * sometimes set it there too.  tf_eflags is kept in the signal
66879363394SAndrew Gallatin 	 * context during signal handling and there is no other place
66979363394SAndrew Gallatin 	 * to remember it, so the PSL_RF bit may be corrupted by the
67079363394SAndrew Gallatin 	 * signal handler without us knowing.  Corruption of the PSL_RF
67179363394SAndrew Gallatin 	 * bit at worst causes one more or one less debugger trap, so
67279363394SAndrew Gallatin 	 * allowing it is fairly harmless.
67379363394SAndrew Gallatin 	 */
674b07cd97eSMark Murray 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF))
67579363394SAndrew Gallatin 		return(EINVAL);
67679363394SAndrew Gallatin 
67779363394SAndrew Gallatin 	/*
67879363394SAndrew Gallatin 	 * Don't allow users to load a valid privileged %cs.  Let the
67979363394SAndrew Gallatin 	 * hardware check for invalid selectors, excess privilege in
68079363394SAndrew Gallatin 	 * other selectors, invalid %eip's and invalid %esp's.
68179363394SAndrew Gallatin 	 */
68279363394SAndrew Gallatin #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
68379363394SAndrew Gallatin 	if (!CS_SECURE(context->sc_cs)) {
6849104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
6859104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
6869104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
6879104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
6889104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_eip;
6899104847fSDavid Xu 		trapsignal(td, &ksi);
69079363394SAndrew Gallatin 		return(EINVAL);
69179363394SAndrew Gallatin 	}
69279363394SAndrew Gallatin 
693611d9407SJohn Baldwin 	PROC_LOCK(p);
6944093529dSJeff Roberson 	linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask);
6954093529dSJeff Roberson 	SIG_CANTMASK(td->td_sigmask);
6964093529dSJeff Roberson 	signotify(td);
697611d9407SJohn Baldwin 	PROC_UNLOCK(p);
69879363394SAndrew Gallatin 
69979363394SAndrew Gallatin 	/*
700cc6ca9b3SMarcel Moolenaar 	 * Restore signal context
70179363394SAndrew Gallatin 	 */
70279363394SAndrew Gallatin 	/* %gs was restored by the trampoline. */
70379363394SAndrew Gallatin 	regs->tf_fs     = context->sc_fs;
70479363394SAndrew Gallatin 	regs->tf_es     = context->sc_es;
70579363394SAndrew Gallatin 	regs->tf_ds     = context->sc_ds;
70679363394SAndrew Gallatin 	regs->tf_edi    = context->sc_edi;
70779363394SAndrew Gallatin 	regs->tf_esi    = context->sc_esi;
70879363394SAndrew Gallatin 	regs->tf_ebp    = context->sc_ebp;
70979363394SAndrew Gallatin 	regs->tf_ebx    = context->sc_ebx;
71079363394SAndrew Gallatin 	regs->tf_edx    = context->sc_edx;
71179363394SAndrew Gallatin 	regs->tf_ecx    = context->sc_ecx;
71279363394SAndrew Gallatin 	regs->tf_eax    = context->sc_eax;
71379363394SAndrew Gallatin 	regs->tf_eip    = context->sc_eip;
71479363394SAndrew Gallatin 	regs->tf_cs     = context->sc_cs;
71579363394SAndrew Gallatin 	regs->tf_eflags = eflags;
71679363394SAndrew Gallatin 	regs->tf_esp    = context->sc_esp_at_signal;
71779363394SAndrew Gallatin 	regs->tf_ss     = context->sc_ss;
71879363394SAndrew Gallatin 
71979363394SAndrew Gallatin 	/*
72079363394SAndrew Gallatin 	 * call sigaltstack & ignore results..
72179363394SAndrew Gallatin 	 */
72279363394SAndrew Gallatin 	lss = &uc.uc_stack;
723206a5d3aSIan Dowse 	ss.ss_sp = lss->ss_sp;
724206a5d3aSIan Dowse 	ss.ss_size = lss->ss_size;
725206a5d3aSIan Dowse 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
72679363394SAndrew Gallatin 
72779363394SAndrew Gallatin #ifdef DEBUG
72824593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
72924593369SJonathan Lemon 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
730206a5d3aSIan Dowse 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
73179363394SAndrew Gallatin #endif
732206a5d3aSIan Dowse 	(void)kern_sigaltstack(td, &ss, NULL);
73379363394SAndrew Gallatin 
73479363394SAndrew Gallatin 	return (EJUSTRETURN);
73579363394SAndrew Gallatin }
73679363394SAndrew Gallatin 
737356861dbSMatthew Dillon /*
738356861dbSMatthew Dillon  * MPSAFE
739356861dbSMatthew Dillon  */
740303b270bSEivind Eklund static void
741d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
742d66a5066SPeter Wemm {
743d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
744d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
745d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
746d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
747d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
7487646aefcSPeter Wemm 	args[5] = tf->tf_ebp;	/* Unconfirmed */
749d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
750d66a5066SPeter Wemm }
751d66a5066SPeter Wemm 
752d323ddf3SMatthew Dillon /*
753d323ddf3SMatthew Dillon  * If a linux binary is exec'ing something, try this image activator
754d323ddf3SMatthew Dillon  * first.  We override standard shell script execution in order to
755d323ddf3SMatthew Dillon  * be able to modify the interpreter path.  We only do this if a linux
756d323ddf3SMatthew Dillon  * binary is doing the exec, so we do not create an EXEC module for it.
757d323ddf3SMatthew Dillon  */
75889c9a483SAlfred Perlstein static int	exec_linux_imgact_try(struct image_params *iparams);
759d323ddf3SMatthew Dillon 
760d323ddf3SMatthew Dillon static int
761b07cd97eSMark Murray exec_linux_imgact_try(struct image_params *imgp)
762d323ddf3SMatthew Dillon {
763d323ddf3SMatthew Dillon     const char *head = (const char *)imgp->image_header;
7640311233eSJohn Baldwin     char *rpath;
7650311233eSJohn Baldwin     int error = -1, len;
766d323ddf3SMatthew Dillon 
767d323ddf3SMatthew Dillon     /*
768d323ddf3SMatthew Dillon      * The interpreter for shell scripts run from a linux binary needs
769d323ddf3SMatthew Dillon      * to be located in /compat/linux if possible in order to recursively
770d323ddf3SMatthew Dillon      * maintain linux path emulation.
771d323ddf3SMatthew Dillon      */
772d323ddf3SMatthew Dillon     if (((const short *)head)[0] == SHELLMAGIC) {
773d323ddf3SMatthew Dillon 	    /*
774d323ddf3SMatthew Dillon 	     * Run our normal shell image activator.  If it succeeds attempt
775d323ddf3SMatthew Dillon 	     * to use the alternate path for the interpreter.  If an alternate
776d323ddf3SMatthew Dillon 	     * path is found, use our stringspace to store it.
777d323ddf3SMatthew Dillon 	     */
778d323ddf3SMatthew Dillon 	    if ((error = exec_shell_imgact(imgp)) == 0) {
7790311233eSJohn Baldwin 		    linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
7800311233eSJohn Baldwin 			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0);
7810311233eSJohn Baldwin 		    if (rpath != NULL) {
7820311233eSJohn Baldwin 			    len = strlen(rpath) + 1;
783d323ddf3SMatthew Dillon 
784d323ddf3SMatthew Dillon 			    if (len <= MAXSHELLCMDLEN) {
785d323ddf3SMatthew Dillon 				    memcpy(imgp->interpreter_name, rpath, len);
786d323ddf3SMatthew Dillon 			    }
787d323ddf3SMatthew Dillon 			    free(rpath, M_TEMP);
788d323ddf3SMatthew Dillon 		    }
789d323ddf3SMatthew Dillon 	    }
790d323ddf3SMatthew Dillon     }
791d323ddf3SMatthew Dillon     return(error);
792d323ddf3SMatthew Dillon }
793d323ddf3SMatthew Dillon 
794598d45beSMatthew N. Dodd /*
795598d45beSMatthew N. Dodd  * exec_setregs may initialize some registers differently than Linux
796598d45beSMatthew N. Dodd  * does, thus potentially confusing Linux binaries. If necessary, we
797598d45beSMatthew N. Dodd  * override the exec_setregs default(s) here.
798598d45beSMatthew N. Dodd  */
799598d45beSMatthew N. Dodd static void
800598d45beSMatthew N. Dodd exec_linux_setregs(struct thread *td, u_long entry,
801598d45beSMatthew N. Dodd 		   u_long stack, u_long ps_strings)
802598d45beSMatthew N. Dodd {
8032a51b9b0SDavid Schultz 	static const u_short control = __LINUX_NPXCW__;
804598d45beSMatthew N. Dodd 	struct pcb *pcb = td->td_pcb;
805598d45beSMatthew N. Dodd 
806598d45beSMatthew N. Dodd 	exec_setregs(td, entry, stack, ps_strings);
807598d45beSMatthew N. Dodd 
808598d45beSMatthew N. Dodd 	/* Linux sets %gs to 0, we default to _udatasel */
809598d45beSMatthew N. Dodd 	pcb->pcb_gs = 0; load_gs(0);
8102a51b9b0SDavid Schultz 
8112a51b9b0SDavid Schultz 	/* Linux sets the i387 to extended precision. */
8122a51b9b0SDavid Schultz 	fldcw(&control);
813598d45beSMatthew N. Dodd }
814598d45beSMatthew N. Dodd 
815d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
816e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
817d66a5066SPeter Wemm 	linux_sysent,
8189b44bfc5SAlexander Leidinger 	0,
819956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
820d66a5066SPeter Wemm 	bsd_to_linux_signal,
82185f118c8SDmitrij Tejblum 	ELAST + 1,
822d66a5066SPeter Wemm 	bsd_to_linux_errno,
823288078beSEivind Eklund 	translate_traps,
824d66a5066SPeter Wemm 	linux_fixup,
825d66a5066SPeter Wemm 	linux_sendsig,
826d66a5066SPeter Wemm 	linux_sigcode,
827d66a5066SPeter Wemm 	&linux_szsigcode,
828d66a5066SPeter Wemm 	linux_prepsyscall,
82922d4b0fbSJohn Polstra 	"Linux a.out",
830d3adf769SDavid Schultz 	NULL,
831806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
832f36ba452SJake Burkholder 	LINUX_MINSIGSTKSZ,
833f36ba452SJake Burkholder 	PAGE_SIZE,
834f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
835f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
836f36ba452SJake Burkholder 	USRSTACK,
837f36ba452SJake Burkholder 	PS_STRINGS,
838f36ba452SJake Burkholder 	VM_PROT_ALL,
839f36ba452SJake Burkholder 	exec_copyout_strings,
840c460ac3aSPeter Wemm 	exec_linux_setregs,
841c460ac3aSPeter Wemm 	NULL
842d66a5066SPeter Wemm };
843e1743d02SSøren Schmidt 
844e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
845e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
846e1743d02SSøren Schmidt 	linux_sysent,
8479b44bfc5SAlexander Leidinger 	0,
848956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
849e1743d02SSøren Schmidt 	bsd_to_linux_signal,
85085f118c8SDmitrij Tejblum 	ELAST + 1,
851e1743d02SSøren Schmidt 	bsd_to_linux_errno,
852288078beSEivind Eklund 	translate_traps,
853e1743d02SSøren Schmidt 	elf_linux_fixup,
854e1743d02SSøren Schmidt 	linux_sendsig,
855e1743d02SSøren Schmidt 	linux_sigcode,
856e1743d02SSøren Schmidt 	&linux_szsigcode,
857e1743d02SSøren Schmidt 	linux_prepsyscall,
85822d4b0fbSJohn Polstra 	"Linux ELF",
8593ebc1248SPeter Wemm 	elf32_coredump,
860806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
861f36ba452SJake Burkholder 	LINUX_MINSIGSTKSZ,
862f36ba452SJake Burkholder 	PAGE_SIZE,
863f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
864f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
865f36ba452SJake Burkholder 	USRSTACK,
866f36ba452SJake Burkholder 	PS_STRINGS,
867f36ba452SJake Burkholder 	VM_PROT_ALL,
868f36ba452SJake Burkholder 	exec_copyout_strings,
869c460ac3aSPeter Wemm 	exec_linux_setregs,
870c460ac3aSPeter Wemm 	NULL
871e1743d02SSøren Schmidt };
872e1743d02SSøren Schmidt 
873514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
874c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
8753ebc1248SPeter Wemm 					EM_386,
87621a3ee0eSDavid E. O'Brien 					"Linux",
877ea5a2b2eSSøren Schmidt 					"/compat/linux",
8785cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
8799b68618dSPeter Wemm 					&elf_linux_sysvec,
8809b68618dSPeter Wemm 					NULL,
881900b28f9SMaxim Sobolev 					BI_CAN_EXEC_DYN,
8825cf588ebSPeter Wemm 				 };
8835cf588ebSPeter Wemm 
884514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
885c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
8863ebc1248SPeter Wemm 					EM_386,
88721a3ee0eSDavid E. O'Brien 					"Linux",
8884e138a28SMike Smith 					"/compat/linux",
8894e138a28SMike Smith 					"/lib/ld-linux.so.2",
8909b68618dSPeter Wemm 					&elf_linux_sysvec,
8919b68618dSPeter Wemm 					NULL,
892900b28f9SMaxim Sobolev 					BI_CAN_EXEC_DYN,
8934e138a28SMike Smith 				 };
8944e138a28SMike Smith 
895514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
896514058dcSAlexander Langer 					&linux_brand,
897514058dcSAlexander Langer 					&linux_glibc2brand,
898514058dcSAlexander Langer 					NULL
899514058dcSAlexander Langer 				};
900514058dcSAlexander Langer 
901aa855a59SPeter Wemm static int
902c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
903d30ea4f5SPeter Wemm {
904514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
905514058dcSAlexander Langer 	int error;
906f41325dbSPeter Wemm 	struct linux_ioctl_handler **lihp;
907060e4882SDoug Ambrisko 	struct linux_device_handler **ldhp;
908514058dcSAlexander Langer 
909514058dcSAlexander Langer 	error = 0;
910514058dcSAlexander Langer 
911aa855a59SPeter Wemm 	switch(type) {
912aa855a59SPeter Wemm 	case MOD_LOAD:
913aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
914aa855a59SPeter Wemm 		     ++brandinfo)
9153ebc1248SPeter Wemm 			if (elf32_insert_brand_entry(*brandinfo) < 0)
916aa855a59SPeter Wemm 				error = EINVAL;
917466b14d7SMarcel Moolenaar 		if (error == 0) {
918f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
919f41325dbSPeter Wemm 				linux_ioctl_register_handler(*lihp);
920060e4882SDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
921060e4882SDoug Ambrisko 				linux_device_register_handler(*ldhp);
922357afa71SJung-uk Kim 			mtx_init(&emul_lock, "emuldata lock", NULL, MTX_DEF);
9239b44bfc5SAlexander Leidinger 			sx_init(&emul_shared_lock, "emuldata->shared lock");
9249b44bfc5SAlexander Leidinger 			LIST_INIT(&futex_list);
925bb59e63fSAlexander Leidinger 			sx_init(&futex_sx, "futex protection lock");
9269b44bfc5SAlexander Leidinger 			linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, linux_proc_exit,
9279b44bfc5SAlexander Leidinger 			      NULL, 1000);
9289b44bfc5SAlexander Leidinger 			linux_schedtail_tag = EVENTHANDLER_REGISTER(schedtail, linux_schedtail,
9299b44bfc5SAlexander Leidinger 			      NULL, 1000);
9309b44bfc5SAlexander Leidinger 			linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec,
9319b44bfc5SAlexander Leidinger 			      NULL, 1000);
93243bef515SMarcel Moolenaar 			if (bootverbose)
933466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler installed\n");
934466b14d7SMarcel Moolenaar 		} else
935466b14d7SMarcel Moolenaar 			printf("cannot insert Linux ELF brand handler\n");
936aa855a59SPeter Wemm 		break;
937aa855a59SPeter Wemm 	case MOD_UNLOAD:
938aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
939aa855a59SPeter Wemm 		     ++brandinfo)
9403ebc1248SPeter Wemm 			if (elf32_brand_inuse(*brandinfo))
941d2758342SMark Newton 				error = EBUSY;
942d2758342SMark Newton 		if (error == 0) {
943d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
944d2758342SMark Newton 			     *brandinfo != NULL; ++brandinfo)
9453ebc1248SPeter Wemm 				if (elf32_remove_brand_entry(*brandinfo) < 0)
946aa855a59SPeter Wemm 					error = EINVAL;
947d2758342SMark Newton 		}
948466b14d7SMarcel Moolenaar 		if (error == 0) {
949f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
950f41325dbSPeter Wemm 				linux_ioctl_unregister_handler(*lihp);
951060e4882SDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
952060e4882SDoug Ambrisko 				linux_device_unregister_handler(*ldhp);
953357afa71SJung-uk Kim 			mtx_destroy(&emul_lock);
9549b44bfc5SAlexander Leidinger 			sx_destroy(&emul_shared_lock);
955bb59e63fSAlexander Leidinger 			sx_destroy(&futex_sx);
9569b44bfc5SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
9579b44bfc5SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(schedtail, linux_schedtail_tag);
9589b44bfc5SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
959466b14d7SMarcel Moolenaar 			if (bootverbose)
960466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler removed\n");
961466b14d7SMarcel Moolenaar 		} else
962aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
963aa855a59SPeter Wemm 		break;
964aa855a59SPeter Wemm 	default:
9653e019deaSPoul-Henning Kamp 		return EOPNOTSUPP;
966d30ea4f5SPeter Wemm 	}
967aa855a59SPeter Wemm 	return error;
968aa855a59SPeter Wemm }
969466b14d7SMarcel Moolenaar 
970aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
971aa855a59SPeter Wemm 	"linuxelf",
972aa855a59SPeter Wemm 	linux_elf_modevent,
973aa855a59SPeter Wemm 	0
974aa855a59SPeter Wemm };
975466b14d7SMarcel Moolenaar 
976aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
977