xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision af682d487b6c8ebba4858b2a6578b795c885e15b)
1d66a5066SPeter Wemm /*-
29a14aa01SUlrich Spörlein  * 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>
3557b4252eSKonstantin Belousov #include <sys/fcntl.h>
36d66a5066SPeter Wemm #include <sys/imgact.h>
3722d4b0fbSJohn Polstra #include <sys/imgact_aout.h>
38e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
39ff22c670SBruce Evans #include <sys/kernel.h>
407106ca0dSJohn Baldwin #include <sys/lock.h>
41e1743d02SSøren Schmidt #include <sys/malloc.h>
42ff22c670SBruce Evans #include <sys/module.h>
4323955314SAlfred Perlstein #include <sys/mutex.h>
44fb919e4dSMark Murray #include <sys/proc.h>
45fb919e4dSMark Murray #include <sys/signalvar.h>
46206a5d3aSIan Dowse #include <sys/syscallsubr.h>
47fb919e4dSMark Murray #include <sys/sysent.h>
48fb919e4dSMark Murray #include <sys/sysproto.h>
49a9148ab1SPeter Wemm #include <sys/vnode.h>
509b44bfc5SAlexander Leidinger #include <sys/eventhandler.h>
51fb919e4dSMark Murray 
52d66a5066SPeter Wemm #include <vm/vm.h>
53a9148ab1SPeter Wemm #include <vm/pmap.h>
54ff22c670SBruce Evans #include <vm/vm_extern.h>
55a9148ab1SPeter Wemm #include <vm/vm_map.h>
56a9148ab1SPeter Wemm #include <vm/vm_object.h>
57ff22c670SBruce Evans #include <vm/vm_page.h>
58ff22c670SBruce Evans #include <vm/vm_param.h>
59ff22c670SBruce Evans 
60ff22c670SBruce Evans #include <machine/cpu.h>
614d7c2e8aSDmitry Chagin #include <machine/cputypes.h>
62ff22c670SBruce Evans #include <machine/md_var.h>
63d3adf769SDavid Schultz #include <machine/pcb.h>
64a9148ab1SPeter Wemm 
65d66a5066SPeter Wemm #include <i386/linux/linux.h>
66ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h>
6794cb2ecfSAlexander Leidinger #include <compat/linux/linux_emul.h>
68fde63162SDmitry Chagin #include <compat/linux/linux_futex.h>
69d825ce0aSJohn Baldwin #include <compat/linux/linux_ioctl.h>
700f9d6538SJohn Baldwin #include <compat/linux/linux_mib.h>
714d7c2e8aSDmitry Chagin #include <compat/linux/linux_misc.h>
72b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h>
73322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h>
74e1743d02SSøren Schmidt 
751d91482dSPeter Wemm MODULE_VERSION(linux, 1);
761d91482dSPeter Wemm 
7743bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
7843bef515SMarcel Moolenaar 
79d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN
80d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2123 /* #! */
81d323ddf3SMatthew Dillon #else
82d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2321
83d323ddf3SMatthew Dillon #endif
84d323ddf3SMatthew Dillon 
85e061a6caSMarcel Moolenaar /*
86e061a6caSMarcel Moolenaar  * Allow the sendsig functions to use the ldebug() facility
87e061a6caSMarcel Moolenaar  * even though they are not syscalls themselves. Map them
88e061a6caSMarcel Moolenaar  * to syscall 0. This is slightly less bogus than using
89e061a6caSMarcel Moolenaar  * ldebug(sigreturn).
90e061a6caSMarcel Moolenaar  */
91e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_rt_sendsig	0
92e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_sendsig		0
93e061a6caSMarcel Moolenaar 
948f1e49a6SDmitry Chagin #define	LINUX_PS_STRINGS	(LINUX_USRSTACK - sizeof(struct ps_strings))
958f1e49a6SDmitry Chagin 
9643bef515SMarcel Moolenaar extern char linux_sigcode[];
9743bef515SMarcel Moolenaar extern int linux_szsigcode;
9843bef515SMarcel Moolenaar 
9943bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
10043bef515SMarcel Moolenaar 
101f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
102060e4882SDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
10343bef515SMarcel Moolenaar 
10489c9a483SAlfred Perlstein static int	linux_fixup(register_t **stack_base,
10589c9a483SAlfred Perlstein 		    struct image_params *iparams);
10689c9a483SAlfred Perlstein static int	elf_linux_fixup(register_t **stack_base,
10789c9a483SAlfred Perlstein 		    struct image_params *iparams);
1089104847fSDavid Xu static void     linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
109a107d8aaSNathan Whitehorn static void	exec_linux_setregs(struct thread *td,
110a107d8aaSNathan Whitehorn 		    struct image_params *imgp, u_long stack);
1114d7c2e8aSDmitry Chagin static register_t *linux_copyout_strings(struct image_params *imgp);
11289ffc202SBjoern A. Zeeb static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
1134d7c2e8aSDmitry Chagin 
1144d7c2e8aSDmitry Chagin static int linux_szplatform;
1154d7c2e8aSDmitry Chagin const char *linux_platform;
116d66a5066SPeter Wemm 
1179b44bfc5SAlexander Leidinger static eventhandler_tag linux_exit_tag;
1189b44bfc5SAlexander Leidinger static eventhandler_tag linux_exec_tag;
11981338031SDmitry Chagin static eventhandler_tag linux_thread_dtor_tag;
1209b44bfc5SAlexander Leidinger 
121d66a5066SPeter Wemm /*
122d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
12350e422f0SAlexander Leidinger  * Reference:
12450e422f0SAlexander Leidinger  *   FreeBSD: src/sys/sys/errno.h
12550e422f0SAlexander Leidinger  *   Linux:   linux-2.6.17.8/include/asm-generic/errno-base.h
12650e422f0SAlexander Leidinger  *            linux-2.6.17.8/include/asm-generic/errno.h
127d66a5066SPeter Wemm  */
12885f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
129d66a5066SPeter Wemm 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
130d66a5066SPeter Wemm 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
131d66a5066SPeter Wemm 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
132d66a5066SPeter Wemm 	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
133d66a5066SPeter Wemm 	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
134d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
135d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
136d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
13750e422f0SAlexander Leidinger 	  -6,  -6, -43, -42, -75,-125, -84, -95, -16, -74,
13850e422f0SAlexander Leidinger 	 -72, -67, -71
139d66a5066SPeter Wemm };
140d66a5066SPeter Wemm 
141956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
142956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
143956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
144ba873f4cSAlexander Kabaev 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
145956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
146956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
147956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
148956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
149956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
150d66a5066SPeter Wemm };
151d66a5066SPeter Wemm 
152956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
153956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
154956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
155956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
156956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
157956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
158956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
159956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
160ba873f4cSAlexander Kabaev 	SIGIO, SIGURG, SIGSYS
161d66a5066SPeter Wemm };
162d66a5066SPeter Wemm 
16327a828fcSPierre Beyssac #define LINUX_T_UNKNOWN  255
16427a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = {
16527a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 0 */
16627a828fcSPierre Beyssac 	6,			/* 1  T_PRIVINFLT */
16727a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 2 */
16827a828fcSPierre Beyssac 	3,			/* 3  T_BPTFLT */
16927a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 4 */
17027a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 5 */
17127a828fcSPierre Beyssac 	16,			/* 6  T_ARITHTRAP */
17227a828fcSPierre Beyssac 	254,			/* 7  T_ASTFLT */
17327a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 8 */
17427a828fcSPierre Beyssac 	13,			/* 9  T_PROTFLT */
17527a828fcSPierre Beyssac 	1,			/* 10 T_TRCTRAP */
17627a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 11 */
17727a828fcSPierre Beyssac 	14,			/* 12 T_PAGEFLT */
17827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 13 */
17927a828fcSPierre Beyssac 	17,			/* 14 T_ALIGNFLT */
18027a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 15 */
18127a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 16 */
18227a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 17 */
18327a828fcSPierre Beyssac 	0,			/* 18 T_DIVIDE */
18427a828fcSPierre Beyssac 	2,			/* 19 T_NMI */
18527a828fcSPierre Beyssac 	4,			/* 20 T_OFLOW */
18627a828fcSPierre Beyssac 	5,			/* 21 T_BOUND */
18727a828fcSPierre Beyssac 	7,			/* 22 T_DNA */
18827a828fcSPierre Beyssac 	8,			/* 23 T_DOUBLEFLT */
18927a828fcSPierre Beyssac 	9,			/* 24 T_FPOPFLT */
19027a828fcSPierre Beyssac 	10,			/* 25 T_TSSFLT */
19127a828fcSPierre Beyssac 	11,			/* 26 T_SEGNPFLT */
19227a828fcSPierre Beyssac 	12,			/* 27 T_STKFLT */
19327a828fcSPierre Beyssac 	18,			/* 28 T_MCHK */
19427a828fcSPierre Beyssac 	19,			/* 29 T_XMMFLT */
19527a828fcSPierre Beyssac 	15			/* 30 T_RESERVED */
19627a828fcSPierre Beyssac };
19727a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \
19827a828fcSPierre Beyssac     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
19927a828fcSPierre Beyssac      _bsd_to_linux_trapcode[(code)]: \
20027a828fcSPierre Beyssac      LINUX_T_UNKNOWN)
20127a828fcSPierre Beyssac 
202288078beSEivind Eklund /*
203288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
204288078beSEivind Eklund  * means, deal with it here.
205356861dbSMatthew Dillon  *
206356861dbSMatthew Dillon  * MPSAFE
207288078beSEivind Eklund  */
208288078beSEivind Eklund static int
209288078beSEivind Eklund translate_traps(int signal, int trap_code)
210288078beSEivind Eklund {
211d563a53aSEivind Eklund 	if (signal != SIGBUS)
212*af682d48SDmitry Chagin 		return (signal);
213288078beSEivind Eklund 	switch (trap_code) {
214288078beSEivind Eklund 	case T_PROTFLT:
215288078beSEivind Eklund 	case T_TSSFLT:
216288078beSEivind Eklund 	case T_DOUBLEFLT:
217288078beSEivind Eklund 	case T_PAGEFLT:
218*af682d48SDmitry Chagin 		return (SIGSEGV);
219288078beSEivind Eklund 	default:
220*af682d48SDmitry Chagin 		return (signal);
221288078beSEivind Eklund 	}
222288078beSEivind Eklund }
223288078beSEivind Eklund 
224303b270bSEivind Eklund static int
225654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp)
226d66a5066SPeter Wemm {
227654f6be1SBruce Evans 	register_t *argv, *envp;
228d66a5066SPeter Wemm 
229d66a5066SPeter Wemm 	argv = *stack_base;
230610ecfe0SMaxim Sobolev 	envp = *stack_base + (imgp->args->argc + 1);
231d66a5066SPeter Wemm 	(*stack_base)--;
232aa103453SKonstantin Belousov 	suword(*stack_base, (intptr_t)(void *)envp);
233d66a5066SPeter Wemm 	(*stack_base)--;
234aa103453SKonstantin Belousov 	suword(*stack_base, (intptr_t)(void *)argv);
235d66a5066SPeter Wemm 	(*stack_base)--;
236aa103453SKonstantin Belousov 	suword(*stack_base, imgp->args->argc);
2374d7c2e8aSDmitry Chagin 	return (0);
238d66a5066SPeter Wemm }
239d66a5066SPeter Wemm 
240303b270bSEivind Eklund static int
241654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
242e1743d02SSøren Schmidt {
2434d7c2e8aSDmitry Chagin 	struct proc *p;
24443cf129cSJohn Baldwin 	Elf32_Auxargs *args;
2454d7c2e8aSDmitry Chagin 	Elf32_Addr *uplatform;
2464d7c2e8aSDmitry Chagin 	struct ps_strings *arginfo;
247654f6be1SBruce Evans 	register_t *pos;
248d66a5066SPeter Wemm 
2496617724cSJeff Roberson 	KASSERT(curthread->td_proc == imgp->proc,
25043cf129cSJohn Baldwin 	    ("unsafe elf_linux_fixup(), should be curproc"));
2514d7c2e8aSDmitry Chagin 
2524d7c2e8aSDmitry Chagin 	p = imgp->proc;
2534d7c2e8aSDmitry Chagin 	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
254acface68SDmitry Chagin 	uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
25543cf129cSJohn Baldwin 	args = (Elf32_Auxargs *)imgp->auxargs;
256610ecfe0SMaxim Sobolev 	pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
257e1743d02SSøren Schmidt 
2584d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
2598d30f381SDmitry Chagin 
2608d30f381SDmitry Chagin 	/*
2618d30f381SDmitry Chagin 	 * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0,
2628d30f381SDmitry Chagin 	 * as it has appeared in the 2.4.0-rc7 first time.
2638d30f381SDmitry Chagin 	 * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK),
2648d30f381SDmitry Chagin 	 * glibc falls back to the hard-coded CLK_TCK value when aux entry
2658d30f381SDmitry Chagin 	 * is not present.
2668d30f381SDmitry Chagin 	 * Also see linux_times() implementation.
2678d30f381SDmitry Chagin 	 */
2688d30f381SDmitry Chagin 	if (linux_kernver(curthread) >= LINUX_KERNVER_2004000)
2691ca16454SDmitry Chagin 		AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz);
270e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
271e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
272e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
273e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
274e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
275e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
276e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
2774d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_SECURE, 0);
278b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
279b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
280b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
281b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
2824d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
2834d7c2e8aSDmitry Chagin 	if (args->execfd != -1)
2844d7c2e8aSDmitry Chagin 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
285e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
286e1743d02SSøren Schmidt 
287e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
288e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
289e1743d02SSøren Schmidt 
290e1743d02SSøren Schmidt 	(*stack_base)--;
291aa103453SKonstantin Belousov 	suword(*stack_base, (register_t)imgp->args->argc);
2924d7c2e8aSDmitry Chagin 	return (0);
293e1743d02SSøren Schmidt }
294d66a5066SPeter Wemm 
2954d7c2e8aSDmitry Chagin /*
2964d7c2e8aSDmitry Chagin  * Copied from kern/kern_exec.c
2974d7c2e8aSDmitry Chagin  */
2984d7c2e8aSDmitry Chagin static register_t *
2994d7c2e8aSDmitry Chagin linux_copyout_strings(struct image_params *imgp)
3004d7c2e8aSDmitry Chagin {
3014d7c2e8aSDmitry Chagin 	int argc, envc;
3024d7c2e8aSDmitry Chagin 	char **vectp;
3034d7c2e8aSDmitry Chagin 	char *stringp, *destp;
3044d7c2e8aSDmitry Chagin 	register_t *stack_base;
3054d7c2e8aSDmitry Chagin 	struct ps_strings *arginfo;
3064d7c2e8aSDmitry Chagin 	struct proc *p;
3074d7c2e8aSDmitry Chagin 
3084d7c2e8aSDmitry Chagin 	/*
3094d7c2e8aSDmitry Chagin 	 * Calculate string base and vector table pointers.
3104d7c2e8aSDmitry Chagin 	 * Also deal with signal trampoline code for this exec type.
3114d7c2e8aSDmitry Chagin 	 */
3124d7c2e8aSDmitry Chagin 	p = imgp->proc;
3134d7c2e8aSDmitry Chagin 	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
3148f1e49a6SDmitry Chagin 	destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform -
3158f1e49a6SDmitry Chagin 	    roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
3164d7c2e8aSDmitry Chagin 
3174d7c2e8aSDmitry Chagin 	/*
3184d7c2e8aSDmitry Chagin 	 * install LINUX_PLATFORM
3194d7c2e8aSDmitry Chagin 	 */
3208f1e49a6SDmitry Chagin 	copyout(linux_platform, ((caddr_t)arginfo - linux_szplatform),
3218f1e49a6SDmitry Chagin 	    linux_szplatform);
3224d7c2e8aSDmitry Chagin 
3234d7c2e8aSDmitry Chagin 	/*
3244d7c2e8aSDmitry Chagin 	 * If we have a valid auxargs ptr, prepare some room
3254d7c2e8aSDmitry Chagin 	 * on the stack.
3264d7c2e8aSDmitry Chagin 	 */
3274d7c2e8aSDmitry Chagin 	if (imgp->auxargs) {
3284d7c2e8aSDmitry Chagin 		/*
3294d7c2e8aSDmitry Chagin 		 * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
3304d7c2e8aSDmitry Chagin 		 * lower compatibility.
3314d7c2e8aSDmitry Chagin 		 */
3324d7c2e8aSDmitry Chagin 		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
3334d7c2e8aSDmitry Chagin 		    (LINUX_AT_COUNT * 2);
3344d7c2e8aSDmitry Chagin 		/*
3354d7c2e8aSDmitry Chagin 		 * The '+ 2' is for the null pointers at the end of each of
3364d7c2e8aSDmitry Chagin 		 * the arg and env vector sets,and imgp->auxarg_size is room
3374d7c2e8aSDmitry Chagin 		 * for argument of Runtime loader.
3384d7c2e8aSDmitry Chagin 		 */
3394d7c2e8aSDmitry Chagin 		vectp = (char **)(destp - (imgp->args->argc +
3404d7c2e8aSDmitry Chagin 		    imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(char *));
3414d7c2e8aSDmitry Chagin 	} else {
3424d7c2e8aSDmitry Chagin 		/*
3434d7c2e8aSDmitry Chagin 		 * The '+ 2' is for the null pointers at the end of each of
3444d7c2e8aSDmitry Chagin 		 * the arg and env vector sets
3454d7c2e8aSDmitry Chagin 		 */
3464d7c2e8aSDmitry Chagin 		vectp = (char **)(destp - (imgp->args->argc + imgp->args->envc + 2) *
3474d7c2e8aSDmitry Chagin 		    sizeof(char *));
3484d7c2e8aSDmitry Chagin 	}
3494d7c2e8aSDmitry Chagin 
3504d7c2e8aSDmitry Chagin 	/*
3514d7c2e8aSDmitry Chagin 	 * vectp also becomes our initial stack base
3524d7c2e8aSDmitry Chagin 	 */
3534d7c2e8aSDmitry Chagin 	stack_base = (register_t *)vectp;
3544d7c2e8aSDmitry Chagin 
3554d7c2e8aSDmitry Chagin 	stringp = imgp->args->begin_argv;
3564d7c2e8aSDmitry Chagin 	argc = imgp->args->argc;
3574d7c2e8aSDmitry Chagin 	envc = imgp->args->envc;
3584d7c2e8aSDmitry Chagin 
3594d7c2e8aSDmitry Chagin 	/*
3604d7c2e8aSDmitry Chagin 	 * Copy out strings - arguments and environment.
3614d7c2e8aSDmitry Chagin 	 */
3624d7c2e8aSDmitry Chagin 	copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
3634d7c2e8aSDmitry Chagin 
3644d7c2e8aSDmitry Chagin 	/*
3654d7c2e8aSDmitry Chagin 	 * Fill in "ps_strings" struct for ps, w, etc.
3664d7c2e8aSDmitry Chagin 	 */
3674d7c2e8aSDmitry Chagin 	suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp);
3684d7c2e8aSDmitry Chagin 	suword(&arginfo->ps_nargvstr, argc);
3694d7c2e8aSDmitry Chagin 
3704d7c2e8aSDmitry Chagin 	/*
3714d7c2e8aSDmitry Chagin 	 * Fill in argument portion of vector table.
3724d7c2e8aSDmitry Chagin 	 */
3734d7c2e8aSDmitry Chagin 	for (; argc > 0; --argc) {
3744d7c2e8aSDmitry Chagin 		suword(vectp++, (long)(intptr_t)destp);
3754d7c2e8aSDmitry Chagin 		while (*stringp++ != 0)
3764d7c2e8aSDmitry Chagin 			destp++;
3774d7c2e8aSDmitry Chagin 		destp++;
3784d7c2e8aSDmitry Chagin 	}
3794d7c2e8aSDmitry Chagin 
3804d7c2e8aSDmitry Chagin 	/* a null vector table pointer separates the argp's from the envp's */
3814d7c2e8aSDmitry Chagin 	suword(vectp++, 0);
3824d7c2e8aSDmitry Chagin 
3834d7c2e8aSDmitry Chagin 	suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
3844d7c2e8aSDmitry Chagin 	suword(&arginfo->ps_nenvstr, envc);
3854d7c2e8aSDmitry Chagin 
3864d7c2e8aSDmitry Chagin 	/*
3874d7c2e8aSDmitry Chagin 	 * Fill in environment portion of vector table.
3884d7c2e8aSDmitry Chagin 	 */
3894d7c2e8aSDmitry Chagin 	for (; envc > 0; --envc) {
3904d7c2e8aSDmitry Chagin 		suword(vectp++, (long)(intptr_t)destp);
3914d7c2e8aSDmitry Chagin 		while (*stringp++ != 0)
3924d7c2e8aSDmitry Chagin 			destp++;
3934d7c2e8aSDmitry Chagin 		destp++;
3944d7c2e8aSDmitry Chagin 	}
3954d7c2e8aSDmitry Chagin 
3964d7c2e8aSDmitry Chagin 	/* end of vector table is a null pointer */
3974d7c2e8aSDmitry Chagin 	suword(vectp, 0);
3984d7c2e8aSDmitry Chagin 
3994d7c2e8aSDmitry Chagin 	return (stack_base);
4004d7c2e8aSDmitry Chagin }
4014d7c2e8aSDmitry Chagin 
4024d7c2e8aSDmitry Chagin 
4034d7c2e8aSDmitry Chagin 
40402318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode;
40579363394SAndrew Gallatin 
40679363394SAndrew Gallatin static void
4079104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
40879363394SAndrew Gallatin {
4091d062e2bSDag-Erling Smørgrav 	struct thread *td = curthread;
4101d062e2bSDag-Erling Smørgrav 	struct proc *p = td->td_proc;
41190af4afaSJohn Baldwin 	struct sigacts *psp;
4121d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
4135002a60fSMarcel Moolenaar 	struct l_rt_sigframe *fp, frame;
4149104847fSDavid Xu 	int sig, code;
41579363394SAndrew Gallatin 	int oonstack;
41679363394SAndrew Gallatin 
4179104847fSDavid Xu 	sig = ksi->ksi_signo;
4189104847fSDavid Xu 	code = ksi->ksi_code;
419df53e91cSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
42090af4afaSJohn Baldwin 	psp = p->p_sigacts;
42190af4afaSJohn Baldwin 	mtx_assert(&psp->ps_mtx, MA_OWNED);
422b40ce416SJulian Elischer 	regs = td->td_frame;
423d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
42479363394SAndrew Gallatin 
42579363394SAndrew Gallatin #ifdef DEBUG
4265002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
427728ef954SJohn Baldwin 		printf(ARGS(rt_sendsig, "%p, %d, %p, %u"),
42824593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
42979363394SAndrew Gallatin #endif
43079363394SAndrew Gallatin 	/*
43179363394SAndrew Gallatin 	 * Allocate space for the signal handler context.
43279363394SAndrew Gallatin 	 */
433a30ec4b9SDavid Xu 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
43490af4afaSJohn Baldwin 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
435a30ec4b9SDavid Xu 		fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp +
436a30ec4b9SDavid Xu 		    td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe));
437d034d459SMarcel Moolenaar 	} else
4385002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)regs->tf_esp - 1;
43990af4afaSJohn Baldwin 	mtx_unlock(&psp->ps_mtx);
44079363394SAndrew Gallatin 
44179363394SAndrew Gallatin 	/*
44279363394SAndrew Gallatin 	 * Build the argument list for the signal handler.
44379363394SAndrew Gallatin 	 */
44479363394SAndrew Gallatin 	if (p->p_sysent->sv_sigtbl)
44579363394SAndrew Gallatin 		if (sig <= p->p_sysent->sv_sigsize)
44679363394SAndrew Gallatin 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
44779363394SAndrew Gallatin 
44899d45c5fSMarcel Moolenaar 	bzero(&frame, sizeof(frame));
44999d45c5fSMarcel Moolenaar 
45079363394SAndrew Gallatin 	frame.sf_handler = catcher;
45179363394SAndrew Gallatin 	frame.sf_sig = sig;
45279363394SAndrew Gallatin 	frame.sf_siginfo = &fp->sf_si;
45379363394SAndrew Gallatin 	frame.sf_ucontext = &fp->sf_sc;
454cc6ca9b3SMarcel Moolenaar 
4559d05b77dSJuli Mallett 	/* Fill in POSIX parts */
456aa8b2011SKonstantin Belousov 	ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig);
457cc6ca9b3SMarcel Moolenaar 
45879363394SAndrew Gallatin 	/*
45979363394SAndrew Gallatin 	 * Build the signal context to be used by sigreturn.
46079363394SAndrew Gallatin 	 */
461cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
462cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_link = NULL;		/* XXX ??? */
463cc6ca9b3SMarcel Moolenaar 
464a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp;
465a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size;
466a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
467d034d459SMarcel Moolenaar 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
468611d9407SJohn Baldwin 	PROC_UNLOCK(p);
469cc6ca9b3SMarcel Moolenaar 
470cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
471cc6ca9b3SMarcel Moolenaar 
472cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
47379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_gs     = rgs();
47479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
47579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
47679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
47779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_edi;
47879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_esi;
47979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_ebp;
48079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_ebx;
48179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_edx;
48279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_ecx;
48379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_eax;
48479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_eip;
48579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
48679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags;
48779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp;
48879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
48979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
49096a2b635SKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_cr2    = (register_t)ksi->ksi_addr;
49127a828fcSPierre Beyssac 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
49279363394SAndrew Gallatin 
49379363394SAndrew Gallatin #ifdef DEBUG
4945002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
49524593369SJonathan Lemon 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
4969b778a16SDavid Xu 		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
4979b778a16SDavid Xu 		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
49879363394SAndrew Gallatin #endif
49979363394SAndrew Gallatin 
50079363394SAndrew Gallatin 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
50179363394SAndrew Gallatin 		/*
50279363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
50379363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
50479363394SAndrew Gallatin 		 */
50589734883SAlan Cox #ifdef DEBUG
50689734883SAlan Cox 		if (ldebug(rt_sendsig))
50789734883SAlan Cox 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
50889734883SAlan Cox 			    fp, oonstack);
50989734883SAlan Cox #endif
51019eb87d2SJohn Baldwin 		PROC_LOCK(p);
511b40ce416SJulian Elischer 		sigexit(td, SIGILL);
51279363394SAndrew Gallatin 	}
51379363394SAndrew Gallatin 
51479363394SAndrew Gallatin 	/*
51579363394SAndrew Gallatin 	 * Build context to run handler in.
51679363394SAndrew Gallatin 	 */
51779363394SAndrew Gallatin 	regs->tf_esp = (int)fp;
5188f1e49a6SDmitry Chagin 	regs->tf_eip = p->p_sysent->sv_sigcode_base + linux_sznonrtsigcode;
51922eca0bfSKonstantin Belousov 	regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D);
52079363394SAndrew Gallatin 	regs->tf_cs = _ucodesel;
52179363394SAndrew Gallatin 	regs->tf_ds = _udatasel;
52279363394SAndrew Gallatin 	regs->tf_es = _udatasel;
52379363394SAndrew Gallatin 	regs->tf_fs = _udatasel;
52479363394SAndrew Gallatin 	regs->tf_ss = _udatasel;
525df53e91cSJohn Baldwin 	PROC_LOCK(p);
52690af4afaSJohn Baldwin 	mtx_lock(&psp->ps_mtx);
52779363394SAndrew Gallatin }
52879363394SAndrew Gallatin 
529d66a5066SPeter Wemm 
530d66a5066SPeter Wemm /*
531d66a5066SPeter Wemm  * Send an interrupt to process.
532d66a5066SPeter Wemm  *
533d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
534d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
535d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
536d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
537d66a5066SPeter Wemm  * frame pointer, it returns to the user
538d66a5066SPeter Wemm  * specified pc, psl.
539d66a5066SPeter Wemm  */
540303b270bSEivind Eklund static void
5419104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
542d66a5066SPeter Wemm {
5431d062e2bSDag-Erling Smørgrav 	struct thread *td = curthread;
5441d062e2bSDag-Erling Smørgrav 	struct proc *p = td->td_proc;
54590af4afaSJohn Baldwin 	struct sigacts *psp;
5461d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
5475002a60fSMarcel Moolenaar 	struct l_sigframe *fp, frame;
5485002a60fSMarcel Moolenaar 	l_sigset_t lmask;
5499104847fSDavid Xu 	int sig, code;
5502c4ab9ddSAndrew Gallatin 	int oonstack, i;
551d66a5066SPeter Wemm 
5522509e6c2SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
55390af4afaSJohn Baldwin 	psp = p->p_sigacts;
5549104847fSDavid Xu 	sig = ksi->ksi_signo;
5559104847fSDavid Xu 	code = ksi->ksi_code;
55690af4afaSJohn Baldwin 	mtx_assert(&psp->ps_mtx, MA_OWNED);
55790af4afaSJohn Baldwin 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
558cc6ca9b3SMarcel Moolenaar 		/* Signal handler installed with SA_SIGINFO. */
5599104847fSDavid Xu 		linux_rt_sendsig(catcher, ksi, mask);
560cc6ca9b3SMarcel Moolenaar 		return;
561cc6ca9b3SMarcel Moolenaar 	}
562b40ce416SJulian Elischer 	regs = td->td_frame;
563d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
564d66a5066SPeter Wemm 
565d66a5066SPeter Wemm #ifdef DEBUG
5665002a60fSMarcel Moolenaar 	if (ldebug(sendsig))
567728ef954SJohn Baldwin 		printf(ARGS(sendsig, "%p, %d, %p, %u"),
56824593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
569d66a5066SPeter Wemm #endif
57079363394SAndrew Gallatin 
571d66a5066SPeter Wemm 	/*
572d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
573d66a5066SPeter Wemm 	 */
574a30ec4b9SDavid Xu 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
57590af4afaSJohn Baldwin 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
576a30ec4b9SDavid Xu 		fp = (struct l_sigframe *)(td->td_sigstk.ss_sp +
577a30ec4b9SDavid Xu 		    td->td_sigstk.ss_size - sizeof(struct l_sigframe));
578d034d459SMarcel Moolenaar 	} else
5795002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)regs->tf_esp - 1;
58090af4afaSJohn Baldwin 	mtx_unlock(&psp->ps_mtx);
581611d9407SJohn Baldwin 	PROC_UNLOCK(p);
582d66a5066SPeter Wemm 
583d66a5066SPeter Wemm 	/*
584d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
585d66a5066SPeter Wemm 	 */
586956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
587956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
588956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
589d66a5066SPeter Wemm 
59099d45c5fSMarcel Moolenaar 	bzero(&frame, sizeof(frame));
59199d45c5fSMarcel Moolenaar 
592d66a5066SPeter Wemm 	frame.sf_handler = catcher;
593d66a5066SPeter Wemm 	frame.sf_sig = sig;
594d66a5066SPeter Wemm 
595cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &lmask);
596cc6ca9b3SMarcel Moolenaar 
597d66a5066SPeter Wemm 	/*
598d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
599d66a5066SPeter Wemm 	 */
600cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.sc_mask   = lmask.__bits[0];
6015206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
6025206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
603213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
604213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
605213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
606213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
607213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
608213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
609213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
610213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
611213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
612213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
613213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
614213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
615213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
616213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
617213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
61896a2b635SKonstantin Belousov 	frame.sf_sc.sc_cr2    = (register_t)ksi->ksi_addr;
6199104847fSDavid Xu 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(ksi->ksi_trapno);
620cc6ca9b3SMarcel Moolenaar 
6212c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
622cc6ca9b3SMarcel Moolenaar 		frame.sf_extramask[i] = lmask.__bits[i+1];
623d66a5066SPeter Wemm 
624d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
625d66a5066SPeter Wemm 		/*
626d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
627d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
628d66a5066SPeter Wemm 		 */
62919eb87d2SJohn Baldwin 		PROC_LOCK(p);
630b40ce416SJulian Elischer 		sigexit(td, SIGILL);
631d66a5066SPeter Wemm 	}
632d66a5066SPeter Wemm 
633d66a5066SPeter Wemm 	/*
634d66a5066SPeter Wemm 	 * Build context to run handler in.
635d66a5066SPeter Wemm 	 */
636213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
6378f1e49a6SDmitry Chagin 	regs->tf_eip = p->p_sysent->sv_sigcode_base;
63822eca0bfSKonstantin Belousov 	regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D);
639213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
640213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
641213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
6425206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
643213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
6445002a60fSMarcel Moolenaar 	PROC_LOCK(p);
64590af4afaSJohn Baldwin 	mtx_lock(&psp->ps_mtx);
646d66a5066SPeter Wemm }
647d66a5066SPeter Wemm 
648d66a5066SPeter Wemm /*
649d66a5066SPeter Wemm  * System call to cleanup state after a signal
650d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
651d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
652d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
653d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
654d66a5066SPeter Wemm  * make sure that the user has not modified the
655d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
656d66a5066SPeter Wemm  * a machine fault.
657d66a5066SPeter Wemm  */
658d66a5066SPeter Wemm int
659b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
660d66a5066SPeter Wemm {
6615002a60fSMarcel Moolenaar 	struct l_sigframe frame;
6621d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
6635002a60fSMarcel Moolenaar 	l_sigset_t lmask;
664d6e029adSKonstantin Belousov 	sigset_t bmask;
6652c4ab9ddSAndrew Gallatin 	int eflags, i;
6669104847fSDavid Xu 	ksiginfo_t ksi;
667d66a5066SPeter Wemm 
668b40ce416SJulian Elischer 	regs = td->td_frame;
669d66a5066SPeter Wemm 
670d66a5066SPeter Wemm #ifdef DEBUG
67124593369SJonathan Lemon 	if (ldebug(sigreturn))
67224593369SJonathan Lemon 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
673d66a5066SPeter Wemm #endif
674d66a5066SPeter Wemm 	/*
675cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the sigframe.
676d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
677d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
678d66a5066SPeter Wemm 	 */
6794b7ef73dSDag-Erling Smørgrav 	if (copyin(args->sfp, &frame, sizeof(frame)) != 0)
680d66a5066SPeter Wemm 		return (EFAULT);
681d66a5066SPeter Wemm 
682d66a5066SPeter Wemm 	/*
683d66a5066SPeter Wemm 	 * Check for security violations.
684d66a5066SPeter Wemm 	 */
685d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
686cc6ca9b3SMarcel Moolenaar 	eflags = frame.sf_sc.sc_eflags;
6873d271aaaSEd Maste 	if (!EFLAGS_SECURE(eflags, regs->tf_eflags))
688d66a5066SPeter Wemm 		return (EINVAL);
689d66a5066SPeter Wemm 
690d66a5066SPeter Wemm 	/*
691d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
692d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
693d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
694d66a5066SPeter Wemm 	 */
69540d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
696cc6ca9b3SMarcel Moolenaar 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
6979104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
6989104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
6999104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
7009104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
7019104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_eip;
7029104847fSDavid Xu 		trapsignal(td, &ksi);
703d66a5066SPeter Wemm 		return (EINVAL);
704d66a5066SPeter Wemm 	}
705d66a5066SPeter Wemm 
706cc6ca9b3SMarcel Moolenaar 	lmask.__bits[0] = frame.sf_sc.sc_mask;
7072c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
708cc6ca9b3SMarcel Moolenaar 		lmask.__bits[i+1] = frame.sf_extramask[i];
709d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&lmask, &bmask);
710d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
711956d3333SMarcel Moolenaar 
712d66a5066SPeter Wemm 	/*
713d66a5066SPeter Wemm 	 * Restore signal context.
714d66a5066SPeter Wemm 	 */
7155206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
716cc6ca9b3SMarcel Moolenaar 	regs->tf_fs     = frame.sf_sc.sc_fs;
717cc6ca9b3SMarcel Moolenaar 	regs->tf_es     = frame.sf_sc.sc_es;
718cc6ca9b3SMarcel Moolenaar 	regs->tf_ds     = frame.sf_sc.sc_ds;
719cc6ca9b3SMarcel Moolenaar 	regs->tf_edi    = frame.sf_sc.sc_edi;
720cc6ca9b3SMarcel Moolenaar 	regs->tf_esi    = frame.sf_sc.sc_esi;
721cc6ca9b3SMarcel Moolenaar 	regs->tf_ebp    = frame.sf_sc.sc_ebp;
722cc6ca9b3SMarcel Moolenaar 	regs->tf_ebx    = frame.sf_sc.sc_ebx;
723cc6ca9b3SMarcel Moolenaar 	regs->tf_edx    = frame.sf_sc.sc_edx;
724cc6ca9b3SMarcel Moolenaar 	regs->tf_ecx    = frame.sf_sc.sc_ecx;
725cc6ca9b3SMarcel Moolenaar 	regs->tf_eax    = frame.sf_sc.sc_eax;
726cc6ca9b3SMarcel Moolenaar 	regs->tf_eip    = frame.sf_sc.sc_eip;
727cc6ca9b3SMarcel Moolenaar 	regs->tf_cs     = frame.sf_sc.sc_cs;
728213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
729cc6ca9b3SMarcel Moolenaar 	regs->tf_esp    = frame.sf_sc.sc_esp_at_signal;
730cc6ca9b3SMarcel Moolenaar 	regs->tf_ss     = frame.sf_sc.sc_ss;
731d66a5066SPeter Wemm 
732d66a5066SPeter Wemm 	return (EJUSTRETURN);
733d66a5066SPeter Wemm }
734d66a5066SPeter Wemm 
73579363394SAndrew Gallatin /*
73679363394SAndrew Gallatin  * System call to cleanup state after a signal
73779363394SAndrew Gallatin  * has been taken.  Reset signal mask and
73879363394SAndrew Gallatin  * stack state from context left by rt_sendsig (above).
73979363394SAndrew Gallatin  * Return to previous pc and psl as specified by
74079363394SAndrew Gallatin  * context left by sendsig. Check carefully to
74179363394SAndrew Gallatin  * make sure that the user has not modified the
74279363394SAndrew Gallatin  * psl to gain improper privileges or to cause
74379363394SAndrew Gallatin  * a machine fault.
74479363394SAndrew Gallatin  */
74579363394SAndrew Gallatin int
746b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
74779363394SAndrew Gallatin {
7485002a60fSMarcel Moolenaar 	struct l_ucontext uc;
7495002a60fSMarcel Moolenaar 	struct l_sigcontext *context;
750d6e029adSKonstantin Belousov 	sigset_t bmask;
7515002a60fSMarcel Moolenaar 	l_stack_t *lss;
752206a5d3aSIan Dowse 	stack_t ss;
7531d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
75479363394SAndrew Gallatin 	int eflags;
7559104847fSDavid Xu 	ksiginfo_t ksi;
75679363394SAndrew Gallatin 
757b40ce416SJulian Elischer 	regs = td->td_frame;
75879363394SAndrew Gallatin 
75979363394SAndrew Gallatin #ifdef DEBUG
76024593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
76124593369SJonathan Lemon 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
76279363394SAndrew Gallatin #endif
76379363394SAndrew Gallatin 	/*
764cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the ucontext.
76579363394SAndrew Gallatin 	 * It is unsafe to keep track of it ourselves, in the event that a
76679363394SAndrew Gallatin 	 * program jumps out of a signal handler.
76779363394SAndrew Gallatin 	 */
7684b7ef73dSDag-Erling Smørgrav 	if (copyin(args->ucp, &uc, sizeof(uc)) != 0)
76979363394SAndrew Gallatin 		return (EFAULT);
77079363394SAndrew Gallatin 
77179363394SAndrew Gallatin 	context = &uc.uc_mcontext;
77279363394SAndrew Gallatin 
77379363394SAndrew Gallatin 	/*
77479363394SAndrew Gallatin 	 * Check for security violations.
77579363394SAndrew Gallatin 	 */
77679363394SAndrew Gallatin #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
77779363394SAndrew Gallatin 	eflags = context->sc_eflags;
7783d271aaaSEd Maste 	if (!EFLAGS_SECURE(eflags, regs->tf_eflags))
77979363394SAndrew Gallatin 		return (EINVAL);
78079363394SAndrew Gallatin 
78179363394SAndrew Gallatin 	/*
78279363394SAndrew Gallatin 	 * Don't allow users to load a valid privileged %cs.  Let the
78379363394SAndrew Gallatin 	 * hardware check for invalid selectors, excess privilege in
78479363394SAndrew Gallatin 	 * other selectors, invalid %eip's and invalid %esp's.
78579363394SAndrew Gallatin 	 */
78679363394SAndrew Gallatin #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
78779363394SAndrew Gallatin 	if (!CS_SECURE(context->sc_cs)) {
7889104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
7899104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
7909104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
7919104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
7929104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_eip;
7939104847fSDavid Xu 		trapsignal(td, &ksi);
79479363394SAndrew Gallatin 		return (EINVAL);
79579363394SAndrew Gallatin 	}
79679363394SAndrew Gallatin 
797d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&uc.uc_sigmask, &bmask);
798d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
79979363394SAndrew Gallatin 
80079363394SAndrew Gallatin 	/*
801cc6ca9b3SMarcel Moolenaar 	 * Restore signal context
80279363394SAndrew Gallatin 	 */
80379363394SAndrew Gallatin 	/* %gs was restored by the trampoline. */
80479363394SAndrew Gallatin 	regs->tf_fs     = context->sc_fs;
80579363394SAndrew Gallatin 	regs->tf_es     = context->sc_es;
80679363394SAndrew Gallatin 	regs->tf_ds     = context->sc_ds;
80779363394SAndrew Gallatin 	regs->tf_edi    = context->sc_edi;
80879363394SAndrew Gallatin 	regs->tf_esi    = context->sc_esi;
80979363394SAndrew Gallatin 	regs->tf_ebp    = context->sc_ebp;
81079363394SAndrew Gallatin 	regs->tf_ebx    = context->sc_ebx;
81179363394SAndrew Gallatin 	regs->tf_edx    = context->sc_edx;
81279363394SAndrew Gallatin 	regs->tf_ecx    = context->sc_ecx;
81379363394SAndrew Gallatin 	regs->tf_eax    = context->sc_eax;
81479363394SAndrew Gallatin 	regs->tf_eip    = context->sc_eip;
81579363394SAndrew Gallatin 	regs->tf_cs     = context->sc_cs;
81679363394SAndrew Gallatin 	regs->tf_eflags = eflags;
81779363394SAndrew Gallatin 	regs->tf_esp    = context->sc_esp_at_signal;
81879363394SAndrew Gallatin 	regs->tf_ss     = context->sc_ss;
81979363394SAndrew Gallatin 
82079363394SAndrew Gallatin 	/*
82179363394SAndrew Gallatin 	 * call sigaltstack & ignore results..
82279363394SAndrew Gallatin 	 */
82379363394SAndrew Gallatin 	lss = &uc.uc_stack;
824206a5d3aSIan Dowse 	ss.ss_sp = lss->ss_sp;
825206a5d3aSIan Dowse 	ss.ss_size = lss->ss_size;
826206a5d3aSIan Dowse 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
82779363394SAndrew Gallatin 
82879363394SAndrew Gallatin #ifdef DEBUG
82924593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
83024593369SJonathan Lemon 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
831206a5d3aSIan Dowse 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
83279363394SAndrew Gallatin #endif
833206a5d3aSIan Dowse 	(void)kern_sigaltstack(td, &ss, NULL);
83479363394SAndrew Gallatin 
83579363394SAndrew Gallatin 	return (EJUSTRETURN);
83679363394SAndrew Gallatin }
83779363394SAndrew Gallatin 
838afe1a688SKonstantin Belousov static int
839afe1a688SKonstantin Belousov linux_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
840d66a5066SPeter Wemm {
841afe1a688SKonstantin Belousov 	struct proc *p;
842afe1a688SKonstantin Belousov 	struct trapframe *frame;
843afe1a688SKonstantin Belousov 
844afe1a688SKonstantin Belousov 	p = td->td_proc;
845afe1a688SKonstantin Belousov 	frame = td->td_frame;
846afe1a688SKonstantin Belousov 
847afe1a688SKonstantin Belousov 	sa->code = frame->tf_eax;
848afe1a688SKonstantin Belousov 	sa->args[0] = frame->tf_ebx;
849afe1a688SKonstantin Belousov 	sa->args[1] = frame->tf_ecx;
850afe1a688SKonstantin Belousov 	sa->args[2] = frame->tf_edx;
851afe1a688SKonstantin Belousov 	sa->args[3] = frame->tf_esi;
852afe1a688SKonstantin Belousov 	sa->args[4] = frame->tf_edi;
853afe1a688SKonstantin Belousov 	sa->args[5] = frame->tf_ebp;	/* Unconfirmed */
854afe1a688SKonstantin Belousov 
855afe1a688SKonstantin Belousov 	if (sa->code >= p->p_sysent->sv_size)
856afe1a688SKonstantin Belousov 		sa->callp = &p->p_sysent->sv_table[0];
857afe1a688SKonstantin Belousov  	else
858afe1a688SKonstantin Belousov  		sa->callp = &p->p_sysent->sv_table[sa->code];
859afe1a688SKonstantin Belousov 	sa->narg = sa->callp->sy_narg;
860afe1a688SKonstantin Belousov 
861afe1a688SKonstantin Belousov 	td->td_retval[0] = 0;
862afe1a688SKonstantin Belousov 	td->td_retval[1] = frame->tf_edx;
863afe1a688SKonstantin Belousov 
864afe1a688SKonstantin Belousov 	return (0);
865d66a5066SPeter Wemm }
866d66a5066SPeter Wemm 
867d323ddf3SMatthew Dillon /*
868d323ddf3SMatthew Dillon  * If a linux binary is exec'ing something, try this image activator
869d323ddf3SMatthew Dillon  * first.  We override standard shell script execution in order to
870d323ddf3SMatthew Dillon  * be able to modify the interpreter path.  We only do this if a linux
871d323ddf3SMatthew Dillon  * binary is doing the exec, so we do not create an EXEC module for it.
872d323ddf3SMatthew Dillon  */
87389c9a483SAlfred Perlstein static int	exec_linux_imgact_try(struct image_params *iparams);
874d323ddf3SMatthew Dillon 
875d323ddf3SMatthew Dillon static int
876b07cd97eSMark Murray exec_linux_imgact_try(struct image_params *imgp)
877d323ddf3SMatthew Dillon {
878d323ddf3SMatthew Dillon     const char *head = (const char *)imgp->image_header;
8790311233eSJohn Baldwin     char *rpath;
880a14a9498SAlan Cox     int error = -1;
881d323ddf3SMatthew Dillon 
882d323ddf3SMatthew Dillon     /*
883d323ddf3SMatthew Dillon      * The interpreter for shell scripts run from a linux binary needs
884d323ddf3SMatthew Dillon      * to be located in /compat/linux if possible in order to recursively
885d323ddf3SMatthew Dillon      * maintain linux path emulation.
886d323ddf3SMatthew Dillon      */
887d323ddf3SMatthew Dillon     if (((const short *)head)[0] == SHELLMAGIC) {
888d323ddf3SMatthew Dillon 	    /*
889d323ddf3SMatthew Dillon 	     * Run our normal shell image activator.  If it succeeds attempt
890d323ddf3SMatthew Dillon 	     * to use the alternate path for the interpreter.  If an alternate
891d323ddf3SMatthew Dillon 	     * path is found, use our stringspace to store it.
892d323ddf3SMatthew Dillon 	     */
893d323ddf3SMatthew Dillon 	    if ((error = exec_shell_imgact(imgp)) == 0) {
8940311233eSJohn Baldwin 		    linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
89548b05c3fSKonstantin Belousov 			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD);
896a14a9498SAlan Cox 		    if (rpath != NULL)
897a14a9498SAlan Cox 			    imgp->args->fname_buf =
898a14a9498SAlan Cox 				imgp->interpreter_name = rpath;
899d323ddf3SMatthew Dillon 	    }
900d323ddf3SMatthew Dillon     }
901d323ddf3SMatthew Dillon     return (error);
902d323ddf3SMatthew Dillon }
903d323ddf3SMatthew Dillon 
904598d45beSMatthew N. Dodd /*
905598d45beSMatthew N. Dodd  * exec_setregs may initialize some registers differently than Linux
906598d45beSMatthew N. Dodd  * does, thus potentially confusing Linux binaries. If necessary, we
907598d45beSMatthew N. Dodd  * override the exec_setregs default(s) here.
908598d45beSMatthew N. Dodd  */
909598d45beSMatthew N. Dodd static void
910a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack)
911598d45beSMatthew N. Dodd {
912598d45beSMatthew N. Dodd 	struct pcb *pcb = td->td_pcb;
913598d45beSMatthew N. Dodd 
914a107d8aaSNathan Whitehorn 	exec_setregs(td, imgp, stack);
915598d45beSMatthew N. Dodd 
916598d45beSMatthew N. Dodd 	/* Linux sets %gs to 0, we default to _udatasel */
9172ee8325fSJohn Baldwin 	pcb->pcb_gs = 0;
9182ee8325fSJohn Baldwin 	load_gs(0);
9192a51b9b0SDavid Schultz 
9202ee8325fSJohn Baldwin 	pcb->pcb_initial_npxcw = __LINUX_NPXCW__;
921598d45beSMatthew N. Dodd }
922598d45beSMatthew N. Dodd 
9234d7c2e8aSDmitry Chagin static void
9244d7c2e8aSDmitry Chagin linux_get_machine(const char **dst)
9254d7c2e8aSDmitry Chagin {
9264d7c2e8aSDmitry Chagin 
9274d7c2e8aSDmitry Chagin 	switch (cpu_class) {
9284d7c2e8aSDmitry Chagin 	case CPUCLASS_686:
9294d7c2e8aSDmitry Chagin 		*dst = "i686";
9304d7c2e8aSDmitry Chagin 		break;
9314d7c2e8aSDmitry Chagin 	case CPUCLASS_586:
9324d7c2e8aSDmitry Chagin 		*dst = "i586";
9334d7c2e8aSDmitry Chagin 		break;
9344d7c2e8aSDmitry Chagin 	case CPUCLASS_486:
9354d7c2e8aSDmitry Chagin 		*dst = "i486";
9364d7c2e8aSDmitry Chagin 		break;
9374d7c2e8aSDmitry Chagin 	default:
9384d7c2e8aSDmitry Chagin 		*dst = "i386";
9394d7c2e8aSDmitry Chagin 	}
9404d7c2e8aSDmitry Chagin }
9414d7c2e8aSDmitry Chagin 
942d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
943a8d403e1SKonstantin Belousov 	.sv_size	= LINUX_SYS_MAXSYSCALL,
944a8d403e1SKonstantin Belousov 	.sv_table	= linux_sysent,
945a8d403e1SKonstantin Belousov 	.sv_mask	= 0,
946a8d403e1SKonstantin Belousov 	.sv_sigsize	= LINUX_SIGTBLSZ,
947a8d403e1SKonstantin Belousov 	.sv_sigtbl	= bsd_to_linux_signal,
948a8d403e1SKonstantin Belousov 	.sv_errsize	= ELAST + 1,
949a8d403e1SKonstantin Belousov 	.sv_errtbl	= bsd_to_linux_errno,
950a8d403e1SKonstantin Belousov 	.sv_transtrap	= translate_traps,
951a8d403e1SKonstantin Belousov 	.sv_fixup	= linux_fixup,
952a8d403e1SKonstantin Belousov 	.sv_sendsig	= linux_sendsig,
953a8d403e1SKonstantin Belousov 	.sv_sigcode	= linux_sigcode,
954a8d403e1SKonstantin Belousov 	.sv_szsigcode	= &linux_szsigcode,
955afe1a688SKonstantin Belousov 	.sv_prepsyscall	= NULL,
956a8d403e1SKonstantin Belousov 	.sv_name	= "Linux a.out",
957a8d403e1SKonstantin Belousov 	.sv_coredump	= NULL,
958a8d403e1SKonstantin Belousov 	.sv_imgact_try	= exec_linux_imgact_try,
959a8d403e1SKonstantin Belousov 	.sv_minsigstksz	= LINUX_MINSIGSTKSZ,
960a8d403e1SKonstantin Belousov 	.sv_pagesize	= PAGE_SIZE,
961a8d403e1SKonstantin Belousov 	.sv_minuser	= VM_MIN_ADDRESS,
962a8d403e1SKonstantin Belousov 	.sv_maxuser	= VM_MAXUSER_ADDRESS,
9638f1e49a6SDmitry Chagin 	.sv_usrstack	= LINUX_USRSTACK,
964a8d403e1SKonstantin Belousov 	.sv_psstrings	= PS_STRINGS,
965a8d403e1SKonstantin Belousov 	.sv_stackprot	= VM_PROT_ALL,
966a8d403e1SKonstantin Belousov 	.sv_copyout_strings = exec_copyout_strings,
967a8d403e1SKonstantin Belousov 	.sv_setregs	= exec_linux_setregs,
968a8d403e1SKonstantin Belousov 	.sv_fixlimit	= NULL,
969b4cf0e62SKonstantin Belousov 	.sv_maxssiz	= NULL,
970afe1a688SKonstantin Belousov 	.sv_flags	= SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32,
971afe1a688SKonstantin Belousov 	.sv_set_syscall_retval = cpu_set_syscall_retval,
972afe1a688SKonstantin Belousov 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
973afe1a688SKonstantin Belousov 	.sv_syscallnames = NULL,
9748f1e49a6SDmitry Chagin 	.sv_shared_page_base = LINUX_SHAREDPAGE,
9758f1e49a6SDmitry Chagin 	.sv_shared_page_len = PAGE_SIZE,
976e5d81ef1SDmitry Chagin 	.sv_schedtail	= linux_schedtail,
97781338031SDmitry Chagin 	.sv_thread_detach = linux_thread_detach,
978d66a5066SPeter Wemm };
9798f1e49a6SDmitry Chagin INIT_SYSENTVEC(aout_sysvec, &linux_sysvec);
980e1743d02SSøren Schmidt 
981e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
982a8d403e1SKonstantin Belousov 	.sv_size	= LINUX_SYS_MAXSYSCALL,
983a8d403e1SKonstantin Belousov 	.sv_table	= linux_sysent,
984a8d403e1SKonstantin Belousov 	.sv_mask	= 0,
985a8d403e1SKonstantin Belousov 	.sv_sigsize	= LINUX_SIGTBLSZ,
986a8d403e1SKonstantin Belousov 	.sv_sigtbl	= bsd_to_linux_signal,
987a8d403e1SKonstantin Belousov 	.sv_errsize	= ELAST + 1,
988a8d403e1SKonstantin Belousov 	.sv_errtbl	= bsd_to_linux_errno,
989a8d403e1SKonstantin Belousov 	.sv_transtrap	= translate_traps,
990a8d403e1SKonstantin Belousov 	.sv_fixup	= elf_linux_fixup,
991a8d403e1SKonstantin Belousov 	.sv_sendsig	= linux_sendsig,
992a8d403e1SKonstantin Belousov 	.sv_sigcode	= linux_sigcode,
993a8d403e1SKonstantin Belousov 	.sv_szsigcode	= &linux_szsigcode,
994afe1a688SKonstantin Belousov 	.sv_prepsyscall	= NULL,
995a8d403e1SKonstantin Belousov 	.sv_name	= "Linux ELF",
996a8d403e1SKonstantin Belousov 	.sv_coredump	= elf32_coredump,
997a8d403e1SKonstantin Belousov 	.sv_imgact_try	= exec_linux_imgact_try,
998a8d403e1SKonstantin Belousov 	.sv_minsigstksz	= LINUX_MINSIGSTKSZ,
999a8d403e1SKonstantin Belousov 	.sv_pagesize	= PAGE_SIZE,
1000a8d403e1SKonstantin Belousov 	.sv_minuser	= VM_MIN_ADDRESS,
1001a8d403e1SKonstantin Belousov 	.sv_maxuser	= VM_MAXUSER_ADDRESS,
10028f1e49a6SDmitry Chagin 	.sv_usrstack	= LINUX_USRSTACK,
10038f1e49a6SDmitry Chagin 	.sv_psstrings	= LINUX_PS_STRINGS,
1004a8d403e1SKonstantin Belousov 	.sv_stackprot	= VM_PROT_ALL,
10054d7c2e8aSDmitry Chagin 	.sv_copyout_strings = linux_copyout_strings,
1006a8d403e1SKonstantin Belousov 	.sv_setregs	= exec_linux_setregs,
1007a8d403e1SKonstantin Belousov 	.sv_fixlimit	= NULL,
1008b4cf0e62SKonstantin Belousov 	.sv_maxssiz	= NULL,
10098f1e49a6SDmitry Chagin 	.sv_flags	= SV_ABI_LINUX | SV_IA32 | SV_ILP32 | SV_SHP,
1010afe1a688SKonstantin Belousov 	.sv_set_syscall_retval = cpu_set_syscall_retval,
1011afe1a688SKonstantin Belousov 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
1012afe1a688SKonstantin Belousov 	.sv_syscallnames = NULL,
10138f1e49a6SDmitry Chagin 	.sv_shared_page_base = LINUX_SHAREDPAGE,
10148f1e49a6SDmitry Chagin 	.sv_shared_page_len = PAGE_SIZE,
1015e5d81ef1SDmitry Chagin 	.sv_schedtail	= linux_schedtail,
101681338031SDmitry Chagin 	.sv_thread_detach = linux_thread_detach,
1017e1743d02SSøren Schmidt };
10188f1e49a6SDmitry Chagin INIT_SYSENTVEC(elf_sysvec, &elf_linux_sysvec);
1019e1743d02SSøren Schmidt 
102089ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU";
102189ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0;
102289ffc202SBjoern A. Zeeb 
102389ffc202SBjoern A. Zeeb static boolean_t
102489ffc202SBjoern A. Zeeb linux_trans_osrel(const Elf_Note *note, int32_t *osrel)
102589ffc202SBjoern A. Zeeb {
102689ffc202SBjoern A. Zeeb 	const Elf32_Word *desc;
102789ffc202SBjoern A. Zeeb 	uintptr_t p;
102889ffc202SBjoern A. Zeeb 
102989ffc202SBjoern A. Zeeb 	p = (uintptr_t)(note + 1);
103089ffc202SBjoern A. Zeeb 	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
103189ffc202SBjoern A. Zeeb 
103289ffc202SBjoern A. Zeeb 	desc = (const Elf32_Word *)p;
103389ffc202SBjoern A. Zeeb 	if (desc[0] != GNULINUX_ABI_DESC)
103489ffc202SBjoern A. Zeeb 		return (FALSE);
103589ffc202SBjoern A. Zeeb 
103689ffc202SBjoern A. Zeeb 	/*
103789ffc202SBjoern A. Zeeb 	 * For linux we encode osrel as follows (see linux_mib.c):
103889ffc202SBjoern A. Zeeb 	 * VVVMMMIII (version, major, minor), see linux_mib.c.
103989ffc202SBjoern A. Zeeb 	 */
104089ffc202SBjoern A. Zeeb 	*osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3];
104189ffc202SBjoern A. Zeeb 
104289ffc202SBjoern A. Zeeb 	return (TRUE);
104389ffc202SBjoern A. Zeeb }
104432c01de2SDmitry Chagin 
104532c01de2SDmitry Chagin static Elf_Brandnote linux_brandnote = {
104689ffc202SBjoern A. Zeeb 	.hdr.n_namesz	= sizeof(GNU_ABI_VENDOR),
104789ffc202SBjoern A. Zeeb 	.hdr.n_descsz	= 16,	/* XXX at least 16 */
104832c01de2SDmitry Chagin 	.hdr.n_type	= 1,
104989ffc202SBjoern A. Zeeb 	.vendor		= GNU_ABI_VENDOR,
105089ffc202SBjoern A. Zeeb 	.flags		= BN_TRANSLATE_OSREL,
105189ffc202SBjoern A. Zeeb 	.trans_osrel	= linux_trans_osrel
105232c01de2SDmitry Chagin };
105332c01de2SDmitry Chagin 
1054514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
1055a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1056a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1057a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1058a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1059a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.1",
1060a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1061a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
106232c01de2SDmitry Chagin 	.brand_note	= &linux_brandnote,
10632dedc128SDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
10645cf588ebSPeter Wemm };
10655cf588ebSPeter Wemm 
1066514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
1067a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1068a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1069a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1070a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1071a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.2",
1072a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1073a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
107432c01de2SDmitry Chagin 	.brand_note	= &linux_brandnote,
10752dedc128SDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
10764e138a28SMike Smith };
10774e138a28SMike Smith 
1078514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
1079514058dcSAlexander Langer 	&linux_brand,
1080514058dcSAlexander Langer 	&linux_glibc2brand,
1081514058dcSAlexander Langer 	NULL
1082514058dcSAlexander Langer };
1083514058dcSAlexander Langer 
1084aa855a59SPeter Wemm static int
1085c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
1086d30ea4f5SPeter Wemm {
1087514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
1088514058dcSAlexander Langer 	int error;
1089f41325dbSPeter Wemm 	struct linux_ioctl_handler **lihp;
1090060e4882SDoug Ambrisko 	struct linux_device_handler **ldhp;
1091514058dcSAlexander Langer 
1092514058dcSAlexander Langer 	error = 0;
1093514058dcSAlexander Langer 
1094aa855a59SPeter Wemm 	switch(type) {
1095aa855a59SPeter Wemm 	case MOD_LOAD:
1096aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1097aa855a59SPeter Wemm 		     ++brandinfo)
10983ebc1248SPeter Wemm 			if (elf32_insert_brand_entry(*brandinfo) < 0)
1099aa855a59SPeter Wemm 				error = EINVAL;
1100466b14d7SMarcel Moolenaar 		if (error == 0) {
1101f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1102f41325dbSPeter Wemm 				linux_ioctl_register_handler(*lihp);
1103060e4882SDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
1104060e4882SDoug Ambrisko 				linux_device_register_handler(*ldhp);
11059b44bfc5SAlexander Leidinger 			LIST_INIT(&futex_list);
110679262bf1SDmitry Chagin 			mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF);
11079b44bfc5SAlexander Leidinger 			linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, linux_proc_exit,
11089b44bfc5SAlexander Leidinger 			      NULL, 1000);
11099b44bfc5SAlexander Leidinger 			linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec,
11109b44bfc5SAlexander Leidinger 			      NULL, 1000);
111181338031SDmitry Chagin 			linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor,
111281338031SDmitry Chagin 			    linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
11134d7c2e8aSDmitry Chagin 			linux_get_machine(&linux_platform);
11144d7c2e8aSDmitry Chagin 			linux_szplatform = roundup(strlen(linux_platform) + 1,
11154d7c2e8aSDmitry Chagin 			    sizeof(char *));
11167ae27ff4SJamie Gritton 			linux_osd_jail_register();
11171ca16454SDmitry Chagin 			stclohz = (stathz ? stathz : hz);
111843bef515SMarcel Moolenaar 			if (bootverbose)
1119466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler installed\n");
1120466b14d7SMarcel Moolenaar 		} else
1121466b14d7SMarcel Moolenaar 			printf("cannot insert Linux ELF brand handler\n");
1122aa855a59SPeter Wemm 		break;
1123aa855a59SPeter Wemm 	case MOD_UNLOAD:
1124aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1125aa855a59SPeter Wemm 		     ++brandinfo)
11263ebc1248SPeter Wemm 			if (elf32_brand_inuse(*brandinfo))
1127d2758342SMark Newton 				error = EBUSY;
1128d2758342SMark Newton 		if (error == 0) {
1129d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
1130d2758342SMark Newton 			     *brandinfo != NULL; ++brandinfo)
11313ebc1248SPeter Wemm 				if (elf32_remove_brand_entry(*brandinfo) < 0)
1132aa855a59SPeter Wemm 					error = EINVAL;
1133d2758342SMark Newton 		}
1134466b14d7SMarcel Moolenaar 		if (error == 0) {
1135f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1136f41325dbSPeter Wemm 				linux_ioctl_unregister_handler(*lihp);
1137060e4882SDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
1138060e4882SDoug Ambrisko 				linux_device_unregister_handler(*ldhp);
113979262bf1SDmitry Chagin 			mtx_destroy(&futex_mtx);
11409b44bfc5SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
11419b44bfc5SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
114281338031SDmitry Chagin 			EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag);
11437ae27ff4SJamie Gritton 			linux_osd_jail_deregister();
1144466b14d7SMarcel Moolenaar 			if (bootverbose)
1145466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler removed\n");
1146466b14d7SMarcel Moolenaar 		} else
1147aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
1148aa855a59SPeter Wemm 		break;
1149aa855a59SPeter Wemm 	default:
1150*af682d48SDmitry Chagin 		return (EOPNOTSUPP);
1151d30ea4f5SPeter Wemm 	}
1152*af682d48SDmitry Chagin 	return (error);
1153aa855a59SPeter Wemm }
1154466b14d7SMarcel Moolenaar 
1155aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
1156aa855a59SPeter Wemm 	"linuxelf",
1157aa855a59SPeter Wemm 	linux_elf_modevent,
11589823d527SKevin Lo 	0
1159aa855a59SPeter Wemm };
1160466b14d7SMarcel Moolenaar 
116178ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
1162