xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision bdc379344aee7b07ea84d4da61a4f228b72f8079)
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>
74*bdc37934SDmitry Chagin #include <compat/linux/linux_vdso.h>
75e1743d02SSøren Schmidt 
761d91482dSPeter Wemm MODULE_VERSION(linux, 1);
771d91482dSPeter Wemm 
7843bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
7943bef515SMarcel Moolenaar 
80d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN
81d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2123 /* #! */
82d323ddf3SMatthew Dillon #else
83d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2321
84d323ddf3SMatthew Dillon #endif
85d323ddf3SMatthew Dillon 
86e061a6caSMarcel Moolenaar /*
87e061a6caSMarcel Moolenaar  * Allow the sendsig functions to use the ldebug() facility
88e061a6caSMarcel Moolenaar  * even though they are not syscalls themselves. Map them
89e061a6caSMarcel Moolenaar  * to syscall 0. This is slightly less bogus than using
90e061a6caSMarcel Moolenaar  * ldebug(sigreturn).
91e061a6caSMarcel Moolenaar  */
92e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_rt_sendsig	0
93e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_sendsig		0
94e061a6caSMarcel Moolenaar 
958f1e49a6SDmitry Chagin #define	LINUX_PS_STRINGS	(LINUX_USRSTACK - sizeof(struct ps_strings))
968f1e49a6SDmitry Chagin 
97*bdc37934SDmitry Chagin static int linux_szsigcode;
98*bdc37934SDmitry Chagin static vm_object_t linux_shared_page_obj;
99*bdc37934SDmitry Chagin static char *linux_shared_page_mapping;
100*bdc37934SDmitry Chagin extern char _binary_linux_locore_o_start;
101*bdc37934SDmitry Chagin extern char _binary_linux_locore_o_end;
10243bef515SMarcel Moolenaar 
10343bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
10443bef515SMarcel Moolenaar 
105f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
106060e4882SDoug Ambrisko SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
10743bef515SMarcel Moolenaar 
10889c9a483SAlfred Perlstein static int	linux_fixup(register_t **stack_base,
10989c9a483SAlfred Perlstein 		    struct image_params *iparams);
11089c9a483SAlfred Perlstein static int	elf_linux_fixup(register_t **stack_base,
11189c9a483SAlfred Perlstein 		    struct image_params *iparams);
1129104847fSDavid Xu static void     linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
113a107d8aaSNathan Whitehorn static void	exec_linux_setregs(struct thread *td,
114a107d8aaSNathan Whitehorn 		    struct image_params *imgp, u_long stack);
1154d7c2e8aSDmitry Chagin static register_t *linux_copyout_strings(struct image_params *imgp);
11689ffc202SBjoern A. Zeeb static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
117*bdc37934SDmitry Chagin static void	linux_vdso_install(void *param);
118*bdc37934SDmitry Chagin static void	linux_vdso_deinstall(void *param);
1194d7c2e8aSDmitry Chagin 
1204d7c2e8aSDmitry Chagin static int linux_szplatform;
1214d7c2e8aSDmitry Chagin const char *linux_platform;
122d66a5066SPeter Wemm 
1239b44bfc5SAlexander Leidinger static eventhandler_tag linux_exit_tag;
1249b44bfc5SAlexander Leidinger static eventhandler_tag linux_exec_tag;
12581338031SDmitry Chagin static eventhandler_tag linux_thread_dtor_tag;
1269b44bfc5SAlexander Leidinger 
127d66a5066SPeter Wemm /*
128d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
12950e422f0SAlexander Leidinger  * Reference:
13050e422f0SAlexander Leidinger  *   FreeBSD: src/sys/sys/errno.h
13150e422f0SAlexander Leidinger  *   Linux:   linux-2.6.17.8/include/asm-generic/errno-base.h
13250e422f0SAlexander Leidinger  *            linux-2.6.17.8/include/asm-generic/errno.h
133d66a5066SPeter Wemm  */
13485f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
135d66a5066SPeter Wemm 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
136d66a5066SPeter Wemm 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
137d66a5066SPeter Wemm 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
138d66a5066SPeter Wemm 	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
139d66a5066SPeter Wemm 	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
140d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
141d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
142d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
14350e422f0SAlexander Leidinger 	  -6,  -6, -43, -42, -75,-125, -84, -95, -16, -74,
14450e422f0SAlexander Leidinger 	 -72, -67, -71
145d66a5066SPeter Wemm };
146d66a5066SPeter Wemm 
147956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
148956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
149956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
150ba873f4cSAlexander Kabaev 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
151956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
152956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
153956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
154956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
155956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
156d66a5066SPeter Wemm };
157d66a5066SPeter Wemm 
158956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
159956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
160956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
161956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
162956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
163956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
164956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
165956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
166ba873f4cSAlexander Kabaev 	SIGIO, SIGURG, SIGSYS
167d66a5066SPeter Wemm };
168d66a5066SPeter Wemm 
16927a828fcSPierre Beyssac #define LINUX_T_UNKNOWN  255
17027a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = {
17127a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 0 */
17227a828fcSPierre Beyssac 	6,			/* 1  T_PRIVINFLT */
17327a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 2 */
17427a828fcSPierre Beyssac 	3,			/* 3  T_BPTFLT */
17527a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 4 */
17627a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 5 */
17727a828fcSPierre Beyssac 	16,			/* 6  T_ARITHTRAP */
17827a828fcSPierre Beyssac 	254,			/* 7  T_ASTFLT */
17927a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 8 */
18027a828fcSPierre Beyssac 	13,			/* 9  T_PROTFLT */
18127a828fcSPierre Beyssac 	1,			/* 10 T_TRCTRAP */
18227a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 11 */
18327a828fcSPierre Beyssac 	14,			/* 12 T_PAGEFLT */
18427a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 13 */
18527a828fcSPierre Beyssac 	17,			/* 14 T_ALIGNFLT */
18627a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 15 */
18727a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 16 */
18827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 17 */
18927a828fcSPierre Beyssac 	0,			/* 18 T_DIVIDE */
19027a828fcSPierre Beyssac 	2,			/* 19 T_NMI */
19127a828fcSPierre Beyssac 	4,			/* 20 T_OFLOW */
19227a828fcSPierre Beyssac 	5,			/* 21 T_BOUND */
19327a828fcSPierre Beyssac 	7,			/* 22 T_DNA */
19427a828fcSPierre Beyssac 	8,			/* 23 T_DOUBLEFLT */
19527a828fcSPierre Beyssac 	9,			/* 24 T_FPOPFLT */
19627a828fcSPierre Beyssac 	10,			/* 25 T_TSSFLT */
19727a828fcSPierre Beyssac 	11,			/* 26 T_SEGNPFLT */
19827a828fcSPierre Beyssac 	12,			/* 27 T_STKFLT */
19927a828fcSPierre Beyssac 	18,			/* 28 T_MCHK */
20027a828fcSPierre Beyssac 	19,			/* 29 T_XMMFLT */
20127a828fcSPierre Beyssac 	15			/* 30 T_RESERVED */
20227a828fcSPierre Beyssac };
20327a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \
20427a828fcSPierre Beyssac     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
20527a828fcSPierre Beyssac      _bsd_to_linux_trapcode[(code)]: \
20627a828fcSPierre Beyssac      LINUX_T_UNKNOWN)
20727a828fcSPierre Beyssac 
208*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_sigcode);
209*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_rt_sigcode);
210*bdc37934SDmitry Chagin LINUX_VDSO_SYM_INTPTR(linux_vsyscall);
211*bdc37934SDmitry Chagin 
212288078beSEivind Eklund /*
213288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
214288078beSEivind Eklund  * means, deal with it here.
215356861dbSMatthew Dillon  *
216356861dbSMatthew Dillon  * MPSAFE
217288078beSEivind Eklund  */
218288078beSEivind Eklund static int
219288078beSEivind Eklund translate_traps(int signal, int trap_code)
220288078beSEivind Eklund {
221d563a53aSEivind Eklund 	if (signal != SIGBUS)
222af682d48SDmitry Chagin 		return (signal);
223288078beSEivind Eklund 	switch (trap_code) {
224288078beSEivind Eklund 	case T_PROTFLT:
225288078beSEivind Eklund 	case T_TSSFLT:
226288078beSEivind Eklund 	case T_DOUBLEFLT:
227288078beSEivind Eklund 	case T_PAGEFLT:
228af682d48SDmitry Chagin 		return (SIGSEGV);
229288078beSEivind Eklund 	default:
230af682d48SDmitry Chagin 		return (signal);
231288078beSEivind Eklund 	}
232288078beSEivind Eklund }
233288078beSEivind Eklund 
234303b270bSEivind Eklund static int
235654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp)
236d66a5066SPeter Wemm {
237654f6be1SBruce Evans 	register_t *argv, *envp;
238d66a5066SPeter Wemm 
239d66a5066SPeter Wemm 	argv = *stack_base;
240610ecfe0SMaxim Sobolev 	envp = *stack_base + (imgp->args->argc + 1);
241d66a5066SPeter Wemm 	(*stack_base)--;
242aa103453SKonstantin Belousov 	suword(*stack_base, (intptr_t)(void *)envp);
243d66a5066SPeter Wemm 	(*stack_base)--;
244aa103453SKonstantin Belousov 	suword(*stack_base, (intptr_t)(void *)argv);
245d66a5066SPeter Wemm 	(*stack_base)--;
246aa103453SKonstantin Belousov 	suword(*stack_base, imgp->args->argc);
2474d7c2e8aSDmitry Chagin 	return (0);
248d66a5066SPeter Wemm }
249d66a5066SPeter Wemm 
250303b270bSEivind Eklund static int
251654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
252e1743d02SSøren Schmidt {
2534d7c2e8aSDmitry Chagin 	struct proc *p;
25443cf129cSJohn Baldwin 	Elf32_Auxargs *args;
2554d7c2e8aSDmitry Chagin 	Elf32_Addr *uplatform;
2564d7c2e8aSDmitry Chagin 	struct ps_strings *arginfo;
257654f6be1SBruce Evans 	register_t *pos;
258d66a5066SPeter Wemm 
2596617724cSJeff Roberson 	KASSERT(curthread->td_proc == imgp->proc,
26043cf129cSJohn Baldwin 	    ("unsafe elf_linux_fixup(), should be curproc"));
2614d7c2e8aSDmitry Chagin 
2624d7c2e8aSDmitry Chagin 	p = imgp->proc;
2634d7c2e8aSDmitry Chagin 	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
264acface68SDmitry Chagin 	uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szplatform);
26543cf129cSJohn Baldwin 	args = (Elf32_Auxargs *)imgp->auxargs;
266610ecfe0SMaxim Sobolev 	pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
267e1743d02SSøren Schmidt 
268*bdc37934SDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO_EHDR,
269*bdc37934SDmitry Chagin 	    imgp->proc->p_sysent->sv_shared_page_base);
270*bdc37934SDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_SYSINFO, linux_vsyscall);
2714d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
2728d30f381SDmitry Chagin 
2738d30f381SDmitry Chagin 	/*
2748d30f381SDmitry Chagin 	 * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0,
2758d30f381SDmitry Chagin 	 * as it has appeared in the 2.4.0-rc7 first time.
2768d30f381SDmitry Chagin 	 * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK),
2778d30f381SDmitry Chagin 	 * glibc falls back to the hard-coded CLK_TCK value when aux entry
2788d30f381SDmitry Chagin 	 * is not present.
2798d30f381SDmitry Chagin 	 * Also see linux_times() implementation.
2808d30f381SDmitry Chagin 	 */
2818d30f381SDmitry Chagin 	if (linux_kernver(curthread) >= LINUX_KERNVER_2004000)
2821ca16454SDmitry Chagin 		AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz);
283e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
284e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
285e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
286e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
287e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
288e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
289e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
2904d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_SECURE, 0);
291b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
292b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
293b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
294b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
2954d7c2e8aSDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
2964d7c2e8aSDmitry Chagin 	if (args->execfd != -1)
2974d7c2e8aSDmitry Chagin 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
298e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
299e1743d02SSøren Schmidt 
300e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
301e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
302e1743d02SSøren Schmidt 
303e1743d02SSøren Schmidt 	(*stack_base)--;
304aa103453SKonstantin Belousov 	suword(*stack_base, (register_t)imgp->args->argc);
3054d7c2e8aSDmitry Chagin 	return (0);
306e1743d02SSøren Schmidt }
307d66a5066SPeter Wemm 
3084d7c2e8aSDmitry Chagin /*
3094d7c2e8aSDmitry Chagin  * Copied from kern/kern_exec.c
3104d7c2e8aSDmitry Chagin  */
3114d7c2e8aSDmitry Chagin static register_t *
3124d7c2e8aSDmitry Chagin linux_copyout_strings(struct image_params *imgp)
3134d7c2e8aSDmitry Chagin {
3144d7c2e8aSDmitry Chagin 	int argc, envc;
3154d7c2e8aSDmitry Chagin 	char **vectp;
3164d7c2e8aSDmitry Chagin 	char *stringp, *destp;
3174d7c2e8aSDmitry Chagin 	register_t *stack_base;
3184d7c2e8aSDmitry Chagin 	struct ps_strings *arginfo;
3194d7c2e8aSDmitry Chagin 	struct proc *p;
3204d7c2e8aSDmitry Chagin 
3214d7c2e8aSDmitry Chagin 	/*
3224d7c2e8aSDmitry Chagin 	 * Calculate string base and vector table pointers.
3234d7c2e8aSDmitry Chagin 	 * Also deal with signal trampoline code for this exec type.
3244d7c2e8aSDmitry Chagin 	 */
3254d7c2e8aSDmitry Chagin 	p = imgp->proc;
3264d7c2e8aSDmitry Chagin 	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
3278f1e49a6SDmitry Chagin 	destp = (caddr_t)arginfo - SPARE_USRSPACE - linux_szplatform -
3288f1e49a6SDmitry Chagin 	    roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
3294d7c2e8aSDmitry Chagin 
3304d7c2e8aSDmitry Chagin 	/*
3314d7c2e8aSDmitry Chagin 	 * install LINUX_PLATFORM
3324d7c2e8aSDmitry Chagin 	 */
3338f1e49a6SDmitry Chagin 	copyout(linux_platform, ((caddr_t)arginfo - linux_szplatform),
3348f1e49a6SDmitry Chagin 	    linux_szplatform);
3354d7c2e8aSDmitry Chagin 
3364d7c2e8aSDmitry Chagin 	/*
3374d7c2e8aSDmitry Chagin 	 * If we have a valid auxargs ptr, prepare some room
3384d7c2e8aSDmitry Chagin 	 * on the stack.
3394d7c2e8aSDmitry Chagin 	 */
3404d7c2e8aSDmitry Chagin 	if (imgp->auxargs) {
3414d7c2e8aSDmitry Chagin 		/*
3424d7c2e8aSDmitry Chagin 		 * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
3434d7c2e8aSDmitry Chagin 		 * lower compatibility.
3444d7c2e8aSDmitry Chagin 		 */
3454d7c2e8aSDmitry Chagin 		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
3464d7c2e8aSDmitry Chagin 		    (LINUX_AT_COUNT * 2);
3474d7c2e8aSDmitry Chagin 		/*
3484d7c2e8aSDmitry Chagin 		 * The '+ 2' is for the null pointers at the end of each of
3494d7c2e8aSDmitry Chagin 		 * the arg and env vector sets,and imgp->auxarg_size is room
3504d7c2e8aSDmitry Chagin 		 * for argument of Runtime loader.
3514d7c2e8aSDmitry Chagin 		 */
3524d7c2e8aSDmitry Chagin 		vectp = (char **)(destp - (imgp->args->argc +
3534d7c2e8aSDmitry Chagin 		    imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(char *));
3544d7c2e8aSDmitry Chagin 	} else {
3554d7c2e8aSDmitry Chagin 		/*
3564d7c2e8aSDmitry Chagin 		 * The '+ 2' is for the null pointers at the end of each of
3574d7c2e8aSDmitry Chagin 		 * the arg and env vector sets
3584d7c2e8aSDmitry Chagin 		 */
3594d7c2e8aSDmitry Chagin 		vectp = (char **)(destp - (imgp->args->argc + imgp->args->envc + 2) *
3604d7c2e8aSDmitry Chagin 		    sizeof(char *));
3614d7c2e8aSDmitry Chagin 	}
3624d7c2e8aSDmitry Chagin 
3634d7c2e8aSDmitry Chagin 	/*
3644d7c2e8aSDmitry Chagin 	 * vectp also becomes our initial stack base
3654d7c2e8aSDmitry Chagin 	 */
3664d7c2e8aSDmitry Chagin 	stack_base = (register_t *)vectp;
3674d7c2e8aSDmitry Chagin 
3684d7c2e8aSDmitry Chagin 	stringp = imgp->args->begin_argv;
3694d7c2e8aSDmitry Chagin 	argc = imgp->args->argc;
3704d7c2e8aSDmitry Chagin 	envc = imgp->args->envc;
3714d7c2e8aSDmitry Chagin 
3724d7c2e8aSDmitry Chagin 	/*
3734d7c2e8aSDmitry Chagin 	 * Copy out strings - arguments and environment.
3744d7c2e8aSDmitry Chagin 	 */
3754d7c2e8aSDmitry Chagin 	copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
3764d7c2e8aSDmitry Chagin 
3774d7c2e8aSDmitry Chagin 	/*
3784d7c2e8aSDmitry Chagin 	 * Fill in "ps_strings" struct for ps, w, etc.
3794d7c2e8aSDmitry Chagin 	 */
3804d7c2e8aSDmitry Chagin 	suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp);
3814d7c2e8aSDmitry Chagin 	suword(&arginfo->ps_nargvstr, argc);
3824d7c2e8aSDmitry Chagin 
3834d7c2e8aSDmitry Chagin 	/*
3844d7c2e8aSDmitry Chagin 	 * Fill in argument portion of vector table.
3854d7c2e8aSDmitry Chagin 	 */
3864d7c2e8aSDmitry Chagin 	for (; argc > 0; --argc) {
3874d7c2e8aSDmitry Chagin 		suword(vectp++, (long)(intptr_t)destp);
3884d7c2e8aSDmitry Chagin 		while (*stringp++ != 0)
3894d7c2e8aSDmitry Chagin 			destp++;
3904d7c2e8aSDmitry Chagin 		destp++;
3914d7c2e8aSDmitry Chagin 	}
3924d7c2e8aSDmitry Chagin 
3934d7c2e8aSDmitry Chagin 	/* a null vector table pointer separates the argp's from the envp's */
3944d7c2e8aSDmitry Chagin 	suword(vectp++, 0);
3954d7c2e8aSDmitry Chagin 
3964d7c2e8aSDmitry Chagin 	suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
3974d7c2e8aSDmitry Chagin 	suword(&arginfo->ps_nenvstr, envc);
3984d7c2e8aSDmitry Chagin 
3994d7c2e8aSDmitry Chagin 	/*
4004d7c2e8aSDmitry Chagin 	 * Fill in environment portion of vector table.
4014d7c2e8aSDmitry Chagin 	 */
4024d7c2e8aSDmitry Chagin 	for (; envc > 0; --envc) {
4034d7c2e8aSDmitry Chagin 		suword(vectp++, (long)(intptr_t)destp);
4044d7c2e8aSDmitry Chagin 		while (*stringp++ != 0)
4054d7c2e8aSDmitry Chagin 			destp++;
4064d7c2e8aSDmitry Chagin 		destp++;
4074d7c2e8aSDmitry Chagin 	}
4084d7c2e8aSDmitry Chagin 
4094d7c2e8aSDmitry Chagin 	/* end of vector table is a null pointer */
4104d7c2e8aSDmitry Chagin 	suword(vectp, 0);
4114d7c2e8aSDmitry Chagin 
4124d7c2e8aSDmitry Chagin 	return (stack_base);
4134d7c2e8aSDmitry Chagin }
4144d7c2e8aSDmitry Chagin 
41579363394SAndrew Gallatin static void
4169104847fSDavid Xu linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
41779363394SAndrew Gallatin {
4181d062e2bSDag-Erling Smørgrav 	struct thread *td = curthread;
4191d062e2bSDag-Erling Smørgrav 	struct proc *p = td->td_proc;
42090af4afaSJohn Baldwin 	struct sigacts *psp;
4211d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
4225002a60fSMarcel Moolenaar 	struct l_rt_sigframe *fp, frame;
4239104847fSDavid Xu 	int sig, code;
42479363394SAndrew Gallatin 	int oonstack;
42579363394SAndrew Gallatin 
4269104847fSDavid Xu 	sig = ksi->ksi_signo;
4279104847fSDavid Xu 	code = ksi->ksi_code;
428df53e91cSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
42990af4afaSJohn Baldwin 	psp = p->p_sigacts;
43090af4afaSJohn Baldwin 	mtx_assert(&psp->ps_mtx, MA_OWNED);
431b40ce416SJulian Elischer 	regs = td->td_frame;
432d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
43379363394SAndrew Gallatin 
43479363394SAndrew Gallatin #ifdef DEBUG
4355002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
436728ef954SJohn Baldwin 		printf(ARGS(rt_sendsig, "%p, %d, %p, %u"),
43724593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
43879363394SAndrew Gallatin #endif
43979363394SAndrew Gallatin 	/*
44079363394SAndrew Gallatin 	 * Allocate space for the signal handler context.
44179363394SAndrew Gallatin 	 */
442a30ec4b9SDavid Xu 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
44390af4afaSJohn Baldwin 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
444a30ec4b9SDavid Xu 		fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp +
445a30ec4b9SDavid Xu 		    td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe));
446d034d459SMarcel Moolenaar 	} else
4475002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)regs->tf_esp - 1;
44890af4afaSJohn Baldwin 	mtx_unlock(&psp->ps_mtx);
44979363394SAndrew Gallatin 
45079363394SAndrew Gallatin 	/*
45179363394SAndrew Gallatin 	 * Build the argument list for the signal handler.
45279363394SAndrew Gallatin 	 */
45379363394SAndrew Gallatin 	if (p->p_sysent->sv_sigtbl)
45479363394SAndrew Gallatin 		if (sig <= p->p_sysent->sv_sigsize)
45579363394SAndrew Gallatin 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
45679363394SAndrew Gallatin 
45799d45c5fSMarcel Moolenaar 	bzero(&frame, sizeof(frame));
45899d45c5fSMarcel Moolenaar 
45979363394SAndrew Gallatin 	frame.sf_handler = catcher;
46079363394SAndrew Gallatin 	frame.sf_sig = sig;
46179363394SAndrew Gallatin 	frame.sf_siginfo = &fp->sf_si;
46279363394SAndrew Gallatin 	frame.sf_ucontext = &fp->sf_sc;
463cc6ca9b3SMarcel Moolenaar 
4649d05b77dSJuli Mallett 	/* Fill in POSIX parts */
465aa8b2011SKonstantin Belousov 	ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig);
466cc6ca9b3SMarcel Moolenaar 
46779363394SAndrew Gallatin 	/*
46879363394SAndrew Gallatin 	 * Build the signal context to be used by sigreturn.
46979363394SAndrew Gallatin 	 */
470cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
471cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_link = NULL;		/* XXX ??? */
472cc6ca9b3SMarcel Moolenaar 
473a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_sp = td->td_sigstk.ss_sp;
474a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size;
475a30ec4b9SDavid Xu 	frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
476d034d459SMarcel Moolenaar 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
477611d9407SJohn Baldwin 	PROC_UNLOCK(p);
478cc6ca9b3SMarcel Moolenaar 
479cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
480cc6ca9b3SMarcel Moolenaar 
481cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
48279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_gs     = rgs();
48379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
48479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
48579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
48679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_edi;
48779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_esi;
48879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_ebp;
48979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_ebx;
490*bdc37934SDmitry Chagin 	frame.sf_sc.uc_mcontext.sc_esp    = regs->tf_esp;
49179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_edx;
49279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_ecx;
49379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_eax;
49479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_eip;
49579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
49679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags;
49779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp;
49879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
49979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
50096a2b635SKonstantin Belousov 	frame.sf_sc.uc_mcontext.sc_cr2    = (register_t)ksi->ksi_addr;
50127a828fcSPierre Beyssac 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
50279363394SAndrew Gallatin 
50379363394SAndrew Gallatin #ifdef DEBUG
5045002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
50524593369SJonathan Lemon 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
5069b778a16SDavid Xu 		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
5079b778a16SDavid Xu 		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
50879363394SAndrew Gallatin #endif
50979363394SAndrew Gallatin 
51079363394SAndrew Gallatin 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
51179363394SAndrew Gallatin 		/*
51279363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
51379363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
51479363394SAndrew Gallatin 		 */
51589734883SAlan Cox #ifdef DEBUG
51689734883SAlan Cox 		if (ldebug(rt_sendsig))
51789734883SAlan Cox 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
51889734883SAlan Cox 			    fp, oonstack);
51989734883SAlan Cox #endif
52019eb87d2SJohn Baldwin 		PROC_LOCK(p);
521b40ce416SJulian Elischer 		sigexit(td, SIGILL);
52279363394SAndrew Gallatin 	}
52379363394SAndrew Gallatin 
52479363394SAndrew Gallatin 	/*
52579363394SAndrew Gallatin 	 * Build context to run handler in.
52679363394SAndrew Gallatin 	 */
52779363394SAndrew Gallatin 	regs->tf_esp = (int)fp;
528*bdc37934SDmitry Chagin 	regs->tf_eip = linux_rt_sigcode;
52922eca0bfSKonstantin Belousov 	regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D);
53079363394SAndrew Gallatin 	regs->tf_cs = _ucodesel;
53179363394SAndrew Gallatin 	regs->tf_ds = _udatasel;
53279363394SAndrew Gallatin 	regs->tf_es = _udatasel;
53379363394SAndrew Gallatin 	regs->tf_fs = _udatasel;
53479363394SAndrew Gallatin 	regs->tf_ss = _udatasel;
535df53e91cSJohn Baldwin 	PROC_LOCK(p);
53690af4afaSJohn Baldwin 	mtx_lock(&psp->ps_mtx);
53779363394SAndrew Gallatin }
53879363394SAndrew Gallatin 
539d66a5066SPeter Wemm 
540d66a5066SPeter Wemm /*
541d66a5066SPeter Wemm  * Send an interrupt to process.
542d66a5066SPeter Wemm  *
543d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
544d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
545d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
546d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
547d66a5066SPeter Wemm  * frame pointer, it returns to the user
548d66a5066SPeter Wemm  * specified pc, psl.
549d66a5066SPeter Wemm  */
550303b270bSEivind Eklund static void
5519104847fSDavid Xu linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
552d66a5066SPeter Wemm {
5531d062e2bSDag-Erling Smørgrav 	struct thread *td = curthread;
5541d062e2bSDag-Erling Smørgrav 	struct proc *p = td->td_proc;
55590af4afaSJohn Baldwin 	struct sigacts *psp;
5561d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
5575002a60fSMarcel Moolenaar 	struct l_sigframe *fp, frame;
5585002a60fSMarcel Moolenaar 	l_sigset_t lmask;
5599104847fSDavid Xu 	int sig, code;
5602c4ab9ddSAndrew Gallatin 	int oonstack, i;
561d66a5066SPeter Wemm 
5622509e6c2SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
56390af4afaSJohn Baldwin 	psp = p->p_sigacts;
5649104847fSDavid Xu 	sig = ksi->ksi_signo;
5659104847fSDavid Xu 	code = ksi->ksi_code;
56690af4afaSJohn Baldwin 	mtx_assert(&psp->ps_mtx, MA_OWNED);
56790af4afaSJohn Baldwin 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
568cc6ca9b3SMarcel Moolenaar 		/* Signal handler installed with SA_SIGINFO. */
5699104847fSDavid Xu 		linux_rt_sendsig(catcher, ksi, mask);
570cc6ca9b3SMarcel Moolenaar 		return;
571cc6ca9b3SMarcel Moolenaar 	}
572b40ce416SJulian Elischer 	regs = td->td_frame;
573d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
574d66a5066SPeter Wemm 
575d66a5066SPeter Wemm #ifdef DEBUG
5765002a60fSMarcel Moolenaar 	if (ldebug(sendsig))
577728ef954SJohn Baldwin 		printf(ARGS(sendsig, "%p, %d, %p, %u"),
57824593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
579d66a5066SPeter Wemm #endif
58079363394SAndrew Gallatin 
581d66a5066SPeter Wemm 	/*
582d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
583d66a5066SPeter Wemm 	 */
584a30ec4b9SDavid Xu 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
58590af4afaSJohn Baldwin 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
586a30ec4b9SDavid Xu 		fp = (struct l_sigframe *)(td->td_sigstk.ss_sp +
587a30ec4b9SDavid Xu 		    td->td_sigstk.ss_size - sizeof(struct l_sigframe));
588d034d459SMarcel Moolenaar 	} else
5895002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)regs->tf_esp - 1;
59090af4afaSJohn Baldwin 	mtx_unlock(&psp->ps_mtx);
591611d9407SJohn Baldwin 	PROC_UNLOCK(p);
592d66a5066SPeter Wemm 
593d66a5066SPeter Wemm 	/*
594d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
595d66a5066SPeter Wemm 	 */
596956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
597956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
598956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
599d66a5066SPeter Wemm 
60099d45c5fSMarcel Moolenaar 	bzero(&frame, sizeof(frame));
60199d45c5fSMarcel Moolenaar 
602d66a5066SPeter Wemm 	frame.sf_handler = catcher;
603d66a5066SPeter Wemm 	frame.sf_sig = sig;
604d66a5066SPeter Wemm 
605cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &lmask);
606cc6ca9b3SMarcel Moolenaar 
607d66a5066SPeter Wemm 	/*
608d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
609d66a5066SPeter Wemm 	 */
610cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.sc_mask   = lmask.__bits[0];
6115206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
6125206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
613213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
614213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
615213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
616213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
617213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
618213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
619*bdc37934SDmitry Chagin 	frame.sf_sc.sc_esp    = regs->tf_esp;
620213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
621213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
622213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
623213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
624213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
625213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
626213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
627213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
628213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
62996a2b635SKonstantin Belousov 	frame.sf_sc.sc_cr2    = (register_t)ksi->ksi_addr;
6309104847fSDavid Xu 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(ksi->ksi_trapno);
631cc6ca9b3SMarcel Moolenaar 
6322c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
633cc6ca9b3SMarcel Moolenaar 		frame.sf_extramask[i] = lmask.__bits[i+1];
634d66a5066SPeter Wemm 
635d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
636d66a5066SPeter Wemm 		/*
637d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
638d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
639d66a5066SPeter Wemm 		 */
64019eb87d2SJohn Baldwin 		PROC_LOCK(p);
641b40ce416SJulian Elischer 		sigexit(td, SIGILL);
642d66a5066SPeter Wemm 	}
643d66a5066SPeter Wemm 
644d66a5066SPeter Wemm 	/*
645d66a5066SPeter Wemm 	 * Build context to run handler in.
646d66a5066SPeter Wemm 	 */
647213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
648*bdc37934SDmitry Chagin 	regs->tf_eip = linux_sigcode;
64922eca0bfSKonstantin Belousov 	regs->tf_eflags &= ~(PSL_T | PSL_VM | PSL_D);
650213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
651213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
652213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
6535206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
654213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
6555002a60fSMarcel Moolenaar 	PROC_LOCK(p);
65690af4afaSJohn Baldwin 	mtx_lock(&psp->ps_mtx);
657d66a5066SPeter Wemm }
658d66a5066SPeter Wemm 
659d66a5066SPeter Wemm /*
660d66a5066SPeter Wemm  * System call to cleanup state after a signal
661d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
662d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
663d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
664d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
665d66a5066SPeter Wemm  * make sure that the user has not modified the
666d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
667d66a5066SPeter Wemm  * a machine fault.
668d66a5066SPeter Wemm  */
669d66a5066SPeter Wemm int
670b07cd97eSMark Murray linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
671d66a5066SPeter Wemm {
6725002a60fSMarcel Moolenaar 	struct l_sigframe frame;
6731d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
6745002a60fSMarcel Moolenaar 	l_sigset_t lmask;
675d6e029adSKonstantin Belousov 	sigset_t bmask;
6762c4ab9ddSAndrew Gallatin 	int eflags, i;
6779104847fSDavid Xu 	ksiginfo_t ksi;
678d66a5066SPeter Wemm 
679b40ce416SJulian Elischer 	regs = td->td_frame;
680d66a5066SPeter Wemm 
681d66a5066SPeter Wemm #ifdef DEBUG
68224593369SJonathan Lemon 	if (ldebug(sigreturn))
68324593369SJonathan Lemon 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
684d66a5066SPeter Wemm #endif
685d66a5066SPeter Wemm 	/*
686cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the sigframe.
687d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
688d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
689d66a5066SPeter Wemm 	 */
6904b7ef73dSDag-Erling Smørgrav 	if (copyin(args->sfp, &frame, sizeof(frame)) != 0)
691d66a5066SPeter Wemm 		return (EFAULT);
692d66a5066SPeter Wemm 
693d66a5066SPeter Wemm 	/*
694d66a5066SPeter Wemm 	 * Check for security violations.
695d66a5066SPeter Wemm 	 */
696d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
697cc6ca9b3SMarcel Moolenaar 	eflags = frame.sf_sc.sc_eflags;
6983d271aaaSEd Maste 	if (!EFLAGS_SECURE(eflags, regs->tf_eflags))
699d66a5066SPeter Wemm 		return (EINVAL);
700d66a5066SPeter Wemm 
701d66a5066SPeter Wemm 	/*
702d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
703d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
704d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
705d66a5066SPeter Wemm 	 */
70640d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
707cc6ca9b3SMarcel Moolenaar 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
7089104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
7099104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
7109104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
7119104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
7129104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_eip;
7139104847fSDavid Xu 		trapsignal(td, &ksi);
714d66a5066SPeter Wemm 		return (EINVAL);
715d66a5066SPeter Wemm 	}
716d66a5066SPeter Wemm 
717cc6ca9b3SMarcel Moolenaar 	lmask.__bits[0] = frame.sf_sc.sc_mask;
7182c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
719cc6ca9b3SMarcel Moolenaar 		lmask.__bits[i+1] = frame.sf_extramask[i];
720d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&lmask, &bmask);
721d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
722956d3333SMarcel Moolenaar 
723d66a5066SPeter Wemm 	/*
724d66a5066SPeter Wemm 	 * Restore signal context.
725d66a5066SPeter Wemm 	 */
7265206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
727cc6ca9b3SMarcel Moolenaar 	regs->tf_fs     = frame.sf_sc.sc_fs;
728cc6ca9b3SMarcel Moolenaar 	regs->tf_es     = frame.sf_sc.sc_es;
729cc6ca9b3SMarcel Moolenaar 	regs->tf_ds     = frame.sf_sc.sc_ds;
730cc6ca9b3SMarcel Moolenaar 	regs->tf_edi    = frame.sf_sc.sc_edi;
731cc6ca9b3SMarcel Moolenaar 	regs->tf_esi    = frame.sf_sc.sc_esi;
732cc6ca9b3SMarcel Moolenaar 	regs->tf_ebp    = frame.sf_sc.sc_ebp;
733cc6ca9b3SMarcel Moolenaar 	regs->tf_ebx    = frame.sf_sc.sc_ebx;
734cc6ca9b3SMarcel Moolenaar 	regs->tf_edx    = frame.sf_sc.sc_edx;
735cc6ca9b3SMarcel Moolenaar 	regs->tf_ecx    = frame.sf_sc.sc_ecx;
736cc6ca9b3SMarcel Moolenaar 	regs->tf_eax    = frame.sf_sc.sc_eax;
737cc6ca9b3SMarcel Moolenaar 	regs->tf_eip    = frame.sf_sc.sc_eip;
738cc6ca9b3SMarcel Moolenaar 	regs->tf_cs     = frame.sf_sc.sc_cs;
739213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
740cc6ca9b3SMarcel Moolenaar 	regs->tf_esp    = frame.sf_sc.sc_esp_at_signal;
741cc6ca9b3SMarcel Moolenaar 	regs->tf_ss     = frame.sf_sc.sc_ss;
742d66a5066SPeter Wemm 
743d66a5066SPeter Wemm 	return (EJUSTRETURN);
744d66a5066SPeter Wemm }
745d66a5066SPeter Wemm 
74679363394SAndrew Gallatin /*
74779363394SAndrew Gallatin  * System call to cleanup state after a signal
74879363394SAndrew Gallatin  * has been taken.  Reset signal mask and
74979363394SAndrew Gallatin  * stack state from context left by rt_sendsig (above).
75079363394SAndrew Gallatin  * Return to previous pc and psl as specified by
75179363394SAndrew Gallatin  * context left by sendsig. Check carefully to
75279363394SAndrew Gallatin  * make sure that the user has not modified the
75379363394SAndrew Gallatin  * psl to gain improper privileges or to cause
75479363394SAndrew Gallatin  * a machine fault.
75579363394SAndrew Gallatin  */
75679363394SAndrew Gallatin int
757b07cd97eSMark Murray linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
75879363394SAndrew Gallatin {
7595002a60fSMarcel Moolenaar 	struct l_ucontext uc;
7605002a60fSMarcel Moolenaar 	struct l_sigcontext *context;
761d6e029adSKonstantin Belousov 	sigset_t bmask;
7625002a60fSMarcel Moolenaar 	l_stack_t *lss;
763206a5d3aSIan Dowse 	stack_t ss;
7641d062e2bSDag-Erling Smørgrav 	struct trapframe *regs;
76579363394SAndrew Gallatin 	int eflags;
7669104847fSDavid Xu 	ksiginfo_t ksi;
76779363394SAndrew Gallatin 
768b40ce416SJulian Elischer 	regs = td->td_frame;
76979363394SAndrew Gallatin 
77079363394SAndrew Gallatin #ifdef DEBUG
77124593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
77224593369SJonathan Lemon 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
77379363394SAndrew Gallatin #endif
77479363394SAndrew Gallatin 	/*
775cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the ucontext.
77679363394SAndrew Gallatin 	 * It is unsafe to keep track of it ourselves, in the event that a
77779363394SAndrew Gallatin 	 * program jumps out of a signal handler.
77879363394SAndrew Gallatin 	 */
7794b7ef73dSDag-Erling Smørgrav 	if (copyin(args->ucp, &uc, sizeof(uc)) != 0)
78079363394SAndrew Gallatin 		return (EFAULT);
78179363394SAndrew Gallatin 
78279363394SAndrew Gallatin 	context = &uc.uc_mcontext;
78379363394SAndrew Gallatin 
78479363394SAndrew Gallatin 	/*
78579363394SAndrew Gallatin 	 * Check for security violations.
78679363394SAndrew Gallatin 	 */
78779363394SAndrew Gallatin #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
78879363394SAndrew Gallatin 	eflags = context->sc_eflags;
7893d271aaaSEd Maste 	if (!EFLAGS_SECURE(eflags, regs->tf_eflags))
79079363394SAndrew Gallatin 		return (EINVAL);
79179363394SAndrew Gallatin 
79279363394SAndrew Gallatin 	/*
79379363394SAndrew Gallatin 	 * Don't allow users to load a valid privileged %cs.  Let the
79479363394SAndrew Gallatin 	 * hardware check for invalid selectors, excess privilege in
79579363394SAndrew Gallatin 	 * other selectors, invalid %eip's and invalid %esp's.
79679363394SAndrew Gallatin 	 */
79779363394SAndrew Gallatin #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
79879363394SAndrew Gallatin 	if (!CS_SECURE(context->sc_cs)) {
7999104847fSDavid Xu 		ksiginfo_init_trap(&ksi);
8009104847fSDavid Xu 		ksi.ksi_signo = SIGBUS;
8019104847fSDavid Xu 		ksi.ksi_code = BUS_OBJERR;
8029104847fSDavid Xu 		ksi.ksi_trapno = T_PROTFLT;
8039104847fSDavid Xu 		ksi.ksi_addr = (void *)regs->tf_eip;
8049104847fSDavid Xu 		trapsignal(td, &ksi);
80579363394SAndrew Gallatin 		return (EINVAL);
80679363394SAndrew Gallatin 	}
80779363394SAndrew Gallatin 
808d6e029adSKonstantin Belousov 	linux_to_bsd_sigset(&uc.uc_sigmask, &bmask);
809d6e029adSKonstantin Belousov 	kern_sigprocmask(td, SIG_SETMASK, &bmask, NULL, 0);
81079363394SAndrew Gallatin 
81179363394SAndrew Gallatin 	/*
812cc6ca9b3SMarcel Moolenaar 	 * Restore signal context
81379363394SAndrew Gallatin 	 */
81479363394SAndrew Gallatin 	/* %gs was restored by the trampoline. */
81579363394SAndrew Gallatin 	regs->tf_fs     = context->sc_fs;
81679363394SAndrew Gallatin 	regs->tf_es     = context->sc_es;
81779363394SAndrew Gallatin 	regs->tf_ds     = context->sc_ds;
81879363394SAndrew Gallatin 	regs->tf_edi    = context->sc_edi;
81979363394SAndrew Gallatin 	regs->tf_esi    = context->sc_esi;
82079363394SAndrew Gallatin 	regs->tf_ebp    = context->sc_ebp;
82179363394SAndrew Gallatin 	regs->tf_ebx    = context->sc_ebx;
82279363394SAndrew Gallatin 	regs->tf_edx    = context->sc_edx;
82379363394SAndrew Gallatin 	regs->tf_ecx    = context->sc_ecx;
82479363394SAndrew Gallatin 	regs->tf_eax    = context->sc_eax;
82579363394SAndrew Gallatin 	regs->tf_eip    = context->sc_eip;
82679363394SAndrew Gallatin 	regs->tf_cs     = context->sc_cs;
82779363394SAndrew Gallatin 	regs->tf_eflags = eflags;
82879363394SAndrew Gallatin 	regs->tf_esp    = context->sc_esp_at_signal;
82979363394SAndrew Gallatin 	regs->tf_ss     = context->sc_ss;
83079363394SAndrew Gallatin 
83179363394SAndrew Gallatin 	/*
83279363394SAndrew Gallatin 	 * call sigaltstack & ignore results..
83379363394SAndrew Gallatin 	 */
83479363394SAndrew Gallatin 	lss = &uc.uc_stack;
835206a5d3aSIan Dowse 	ss.ss_sp = lss->ss_sp;
836206a5d3aSIan Dowse 	ss.ss_size = lss->ss_size;
837206a5d3aSIan Dowse 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
83879363394SAndrew Gallatin 
83979363394SAndrew Gallatin #ifdef DEBUG
84024593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
84124593369SJonathan Lemon 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
842206a5d3aSIan Dowse 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
84379363394SAndrew Gallatin #endif
844206a5d3aSIan Dowse 	(void)kern_sigaltstack(td, &ss, NULL);
84579363394SAndrew Gallatin 
84679363394SAndrew Gallatin 	return (EJUSTRETURN);
84779363394SAndrew Gallatin }
84879363394SAndrew Gallatin 
849afe1a688SKonstantin Belousov static int
850afe1a688SKonstantin Belousov linux_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
851d66a5066SPeter Wemm {
852afe1a688SKonstantin Belousov 	struct proc *p;
853afe1a688SKonstantin Belousov 	struct trapframe *frame;
854afe1a688SKonstantin Belousov 
855afe1a688SKonstantin Belousov 	p = td->td_proc;
856afe1a688SKonstantin Belousov 	frame = td->td_frame;
857afe1a688SKonstantin Belousov 
858afe1a688SKonstantin Belousov 	sa->code = frame->tf_eax;
859afe1a688SKonstantin Belousov 	sa->args[0] = frame->tf_ebx;
860afe1a688SKonstantin Belousov 	sa->args[1] = frame->tf_ecx;
861afe1a688SKonstantin Belousov 	sa->args[2] = frame->tf_edx;
862afe1a688SKonstantin Belousov 	sa->args[3] = frame->tf_esi;
863afe1a688SKonstantin Belousov 	sa->args[4] = frame->tf_edi;
864afe1a688SKonstantin Belousov 	sa->args[5] = frame->tf_ebp;	/* Unconfirmed */
865afe1a688SKonstantin Belousov 
866afe1a688SKonstantin Belousov 	if (sa->code >= p->p_sysent->sv_size)
867afe1a688SKonstantin Belousov 		sa->callp = &p->p_sysent->sv_table[0];
868afe1a688SKonstantin Belousov  	else
869afe1a688SKonstantin Belousov  		sa->callp = &p->p_sysent->sv_table[sa->code];
870afe1a688SKonstantin Belousov 	sa->narg = sa->callp->sy_narg;
871afe1a688SKonstantin Belousov 
872afe1a688SKonstantin Belousov 	td->td_retval[0] = 0;
873afe1a688SKonstantin Belousov 	td->td_retval[1] = frame->tf_edx;
874afe1a688SKonstantin Belousov 
875afe1a688SKonstantin Belousov 	return (0);
876d66a5066SPeter Wemm }
877d66a5066SPeter Wemm 
878d323ddf3SMatthew Dillon /*
879d323ddf3SMatthew Dillon  * If a linux binary is exec'ing something, try this image activator
880d323ddf3SMatthew Dillon  * first.  We override standard shell script execution in order to
881d323ddf3SMatthew Dillon  * be able to modify the interpreter path.  We only do this if a linux
882d323ddf3SMatthew Dillon  * binary is doing the exec, so we do not create an EXEC module for it.
883d323ddf3SMatthew Dillon  */
88489c9a483SAlfred Perlstein static int	exec_linux_imgact_try(struct image_params *iparams);
885d323ddf3SMatthew Dillon 
886d323ddf3SMatthew Dillon static int
887b07cd97eSMark Murray exec_linux_imgact_try(struct image_params *imgp)
888d323ddf3SMatthew Dillon {
889d323ddf3SMatthew Dillon     const char *head = (const char *)imgp->image_header;
8900311233eSJohn Baldwin     char *rpath;
891a14a9498SAlan Cox     int error = -1;
892d323ddf3SMatthew Dillon 
893d323ddf3SMatthew Dillon     /*
894d323ddf3SMatthew Dillon      * The interpreter for shell scripts run from a linux binary needs
895d323ddf3SMatthew Dillon      * to be located in /compat/linux if possible in order to recursively
896d323ddf3SMatthew Dillon      * maintain linux path emulation.
897d323ddf3SMatthew Dillon      */
898d323ddf3SMatthew Dillon     if (((const short *)head)[0] == SHELLMAGIC) {
899d323ddf3SMatthew Dillon 	    /*
900d323ddf3SMatthew Dillon 	     * Run our normal shell image activator.  If it succeeds attempt
901d323ddf3SMatthew Dillon 	     * to use the alternate path for the interpreter.  If an alternate
902d323ddf3SMatthew Dillon 	     * path is found, use our stringspace to store it.
903d323ddf3SMatthew Dillon 	     */
904d323ddf3SMatthew Dillon 	    if ((error = exec_shell_imgact(imgp)) == 0) {
9050311233eSJohn Baldwin 		    linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
90648b05c3fSKonstantin Belousov 			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD);
907a14a9498SAlan Cox 		    if (rpath != NULL)
908a14a9498SAlan Cox 			    imgp->args->fname_buf =
909a14a9498SAlan Cox 				imgp->interpreter_name = rpath;
910d323ddf3SMatthew Dillon 	    }
911d323ddf3SMatthew Dillon     }
912d323ddf3SMatthew Dillon     return (error);
913d323ddf3SMatthew Dillon }
914d323ddf3SMatthew Dillon 
915598d45beSMatthew N. Dodd /*
916598d45beSMatthew N. Dodd  * exec_setregs may initialize some registers differently than Linux
917598d45beSMatthew N. Dodd  * does, thus potentially confusing Linux binaries. If necessary, we
918598d45beSMatthew N. Dodd  * override the exec_setregs default(s) here.
919598d45beSMatthew N. Dodd  */
920598d45beSMatthew N. Dodd static void
921a107d8aaSNathan Whitehorn exec_linux_setregs(struct thread *td, struct image_params *imgp, u_long stack)
922598d45beSMatthew N. Dodd {
923598d45beSMatthew N. Dodd 	struct pcb *pcb = td->td_pcb;
924598d45beSMatthew N. Dodd 
925a107d8aaSNathan Whitehorn 	exec_setregs(td, imgp, stack);
926598d45beSMatthew N. Dodd 
927598d45beSMatthew N. Dodd 	/* Linux sets %gs to 0, we default to _udatasel */
9282ee8325fSJohn Baldwin 	pcb->pcb_gs = 0;
9292ee8325fSJohn Baldwin 	load_gs(0);
9302a51b9b0SDavid Schultz 
9312ee8325fSJohn Baldwin 	pcb->pcb_initial_npxcw = __LINUX_NPXCW__;
932598d45beSMatthew N. Dodd }
933598d45beSMatthew N. Dodd 
9344d7c2e8aSDmitry Chagin static void
9354d7c2e8aSDmitry Chagin linux_get_machine(const char **dst)
9364d7c2e8aSDmitry Chagin {
9374d7c2e8aSDmitry Chagin 
9384d7c2e8aSDmitry Chagin 	switch (cpu_class) {
9394d7c2e8aSDmitry Chagin 	case CPUCLASS_686:
9404d7c2e8aSDmitry Chagin 		*dst = "i686";
9414d7c2e8aSDmitry Chagin 		break;
9424d7c2e8aSDmitry Chagin 	case CPUCLASS_586:
9434d7c2e8aSDmitry Chagin 		*dst = "i586";
9444d7c2e8aSDmitry Chagin 		break;
9454d7c2e8aSDmitry Chagin 	case CPUCLASS_486:
9464d7c2e8aSDmitry Chagin 		*dst = "i486";
9474d7c2e8aSDmitry Chagin 		break;
9484d7c2e8aSDmitry Chagin 	default:
9494d7c2e8aSDmitry Chagin 		*dst = "i386";
9504d7c2e8aSDmitry Chagin 	}
9514d7c2e8aSDmitry Chagin }
9524d7c2e8aSDmitry Chagin 
953d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
954a8d403e1SKonstantin Belousov 	.sv_size	= LINUX_SYS_MAXSYSCALL,
955a8d403e1SKonstantin Belousov 	.sv_table	= linux_sysent,
956a8d403e1SKonstantin Belousov 	.sv_mask	= 0,
957a8d403e1SKonstantin Belousov 	.sv_sigsize	= LINUX_SIGTBLSZ,
958a8d403e1SKonstantin Belousov 	.sv_sigtbl	= bsd_to_linux_signal,
959a8d403e1SKonstantin Belousov 	.sv_errsize	= ELAST + 1,
960a8d403e1SKonstantin Belousov 	.sv_errtbl	= bsd_to_linux_errno,
961a8d403e1SKonstantin Belousov 	.sv_transtrap	= translate_traps,
962a8d403e1SKonstantin Belousov 	.sv_fixup	= linux_fixup,
963a8d403e1SKonstantin Belousov 	.sv_sendsig	= linux_sendsig,
964*bdc37934SDmitry Chagin 	.sv_sigcode	= &_binary_linux_locore_o_start,
965a8d403e1SKonstantin Belousov 	.sv_szsigcode	= &linux_szsigcode,
966afe1a688SKonstantin Belousov 	.sv_prepsyscall	= NULL,
967a8d403e1SKonstantin Belousov 	.sv_name	= "Linux a.out",
968a8d403e1SKonstantin Belousov 	.sv_coredump	= NULL,
969a8d403e1SKonstantin Belousov 	.sv_imgact_try	= exec_linux_imgact_try,
970a8d403e1SKonstantin Belousov 	.sv_minsigstksz	= LINUX_MINSIGSTKSZ,
971a8d403e1SKonstantin Belousov 	.sv_pagesize	= PAGE_SIZE,
972a8d403e1SKonstantin Belousov 	.sv_minuser	= VM_MIN_ADDRESS,
973a8d403e1SKonstantin Belousov 	.sv_maxuser	= VM_MAXUSER_ADDRESS,
9748f1e49a6SDmitry Chagin 	.sv_usrstack	= LINUX_USRSTACK,
975a8d403e1SKonstantin Belousov 	.sv_psstrings	= PS_STRINGS,
976a8d403e1SKonstantin Belousov 	.sv_stackprot	= VM_PROT_ALL,
977a8d403e1SKonstantin Belousov 	.sv_copyout_strings = exec_copyout_strings,
978a8d403e1SKonstantin Belousov 	.sv_setregs	= exec_linux_setregs,
979a8d403e1SKonstantin Belousov 	.sv_fixlimit	= NULL,
980b4cf0e62SKonstantin Belousov 	.sv_maxssiz	= NULL,
981afe1a688SKonstantin Belousov 	.sv_flags	= SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32,
982afe1a688SKonstantin Belousov 	.sv_set_syscall_retval = cpu_set_syscall_retval,
983afe1a688SKonstantin Belousov 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
984afe1a688SKonstantin Belousov 	.sv_syscallnames = NULL,
9858f1e49a6SDmitry Chagin 	.sv_shared_page_base = LINUX_SHAREDPAGE,
9868f1e49a6SDmitry Chagin 	.sv_shared_page_len = PAGE_SIZE,
987e5d81ef1SDmitry Chagin 	.sv_schedtail	= linux_schedtail,
98881338031SDmitry Chagin 	.sv_thread_detach = linux_thread_detach,
989d66a5066SPeter Wemm };
9908f1e49a6SDmitry Chagin INIT_SYSENTVEC(aout_sysvec, &linux_sysvec);
991e1743d02SSøren Schmidt 
992e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
993a8d403e1SKonstantin Belousov 	.sv_size	= LINUX_SYS_MAXSYSCALL,
994a8d403e1SKonstantin Belousov 	.sv_table	= linux_sysent,
995a8d403e1SKonstantin Belousov 	.sv_mask	= 0,
996a8d403e1SKonstantin Belousov 	.sv_sigsize	= LINUX_SIGTBLSZ,
997a8d403e1SKonstantin Belousov 	.sv_sigtbl	= bsd_to_linux_signal,
998a8d403e1SKonstantin Belousov 	.sv_errsize	= ELAST + 1,
999a8d403e1SKonstantin Belousov 	.sv_errtbl	= bsd_to_linux_errno,
1000a8d403e1SKonstantin Belousov 	.sv_transtrap	= translate_traps,
1001a8d403e1SKonstantin Belousov 	.sv_fixup	= elf_linux_fixup,
1002a8d403e1SKonstantin Belousov 	.sv_sendsig	= linux_sendsig,
1003*bdc37934SDmitry Chagin 	.sv_sigcode	= &_binary_linux_locore_o_start,
1004a8d403e1SKonstantin Belousov 	.sv_szsigcode	= &linux_szsigcode,
1005afe1a688SKonstantin Belousov 	.sv_prepsyscall	= NULL,
1006a8d403e1SKonstantin Belousov 	.sv_name	= "Linux ELF",
1007a8d403e1SKonstantin Belousov 	.sv_coredump	= elf32_coredump,
1008a8d403e1SKonstantin Belousov 	.sv_imgact_try	= exec_linux_imgact_try,
1009a8d403e1SKonstantin Belousov 	.sv_minsigstksz	= LINUX_MINSIGSTKSZ,
1010a8d403e1SKonstantin Belousov 	.sv_pagesize	= PAGE_SIZE,
1011a8d403e1SKonstantin Belousov 	.sv_minuser	= VM_MIN_ADDRESS,
1012a8d403e1SKonstantin Belousov 	.sv_maxuser	= VM_MAXUSER_ADDRESS,
10138f1e49a6SDmitry Chagin 	.sv_usrstack	= LINUX_USRSTACK,
10148f1e49a6SDmitry Chagin 	.sv_psstrings	= LINUX_PS_STRINGS,
1015a8d403e1SKonstantin Belousov 	.sv_stackprot	= VM_PROT_ALL,
10164d7c2e8aSDmitry Chagin 	.sv_copyout_strings = linux_copyout_strings,
1017a8d403e1SKonstantin Belousov 	.sv_setregs	= exec_linux_setregs,
1018a8d403e1SKonstantin Belousov 	.sv_fixlimit	= NULL,
1019b4cf0e62SKonstantin Belousov 	.sv_maxssiz	= NULL,
10208f1e49a6SDmitry Chagin 	.sv_flags	= SV_ABI_LINUX | SV_IA32 | SV_ILP32 | SV_SHP,
1021afe1a688SKonstantin Belousov 	.sv_set_syscall_retval = cpu_set_syscall_retval,
1022afe1a688SKonstantin Belousov 	.sv_fetch_syscall_args = linux_fetch_syscall_args,
1023afe1a688SKonstantin Belousov 	.sv_syscallnames = NULL,
10248f1e49a6SDmitry Chagin 	.sv_shared_page_base = LINUX_SHAREDPAGE,
10258f1e49a6SDmitry Chagin 	.sv_shared_page_len = PAGE_SIZE,
1026e5d81ef1SDmitry Chagin 	.sv_schedtail	= linux_schedtail,
102781338031SDmitry Chagin 	.sv_thread_detach = linux_thread_detach,
1028e1743d02SSøren Schmidt };
1029*bdc37934SDmitry Chagin 
1030*bdc37934SDmitry Chagin static void
1031*bdc37934SDmitry Chagin linux_vdso_install(void *param)
1032*bdc37934SDmitry Chagin {
1033*bdc37934SDmitry Chagin 
1034*bdc37934SDmitry Chagin 	linux_szsigcode = (&_binary_linux_locore_o_end -
1035*bdc37934SDmitry Chagin 	    &_binary_linux_locore_o_start);
1036*bdc37934SDmitry Chagin 
1037*bdc37934SDmitry Chagin 	if (linux_szsigcode > elf_linux_sysvec.sv_shared_page_len)
1038*bdc37934SDmitry Chagin 		panic("Linux invalid vdso size\n");
1039*bdc37934SDmitry Chagin 
1040*bdc37934SDmitry Chagin 	__elfN(linux_vdso_fixup)(&elf_linux_sysvec);
1041*bdc37934SDmitry Chagin 
1042*bdc37934SDmitry Chagin 	linux_shared_page_obj = __elfN(linux_shared_page_init)
1043*bdc37934SDmitry Chagin 	    (&linux_shared_page_mapping);
1044*bdc37934SDmitry Chagin 
1045*bdc37934SDmitry Chagin 	__elfN(linux_vdso_reloc)(&elf_linux_sysvec, LINUX_SHAREDPAGE);
1046*bdc37934SDmitry Chagin 
1047*bdc37934SDmitry Chagin 	bcopy(elf_linux_sysvec.sv_sigcode, linux_shared_page_mapping,
1048*bdc37934SDmitry Chagin 	    linux_szsigcode);
1049*bdc37934SDmitry Chagin 	elf_linux_sysvec.sv_shared_page_obj = linux_shared_page_obj;
1050*bdc37934SDmitry Chagin }
1051*bdc37934SDmitry Chagin SYSINIT(elf_linux_vdso_init, SI_SUB_EXEC, SI_ORDER_ANY,
1052*bdc37934SDmitry Chagin     (sysinit_cfunc_t)linux_vdso_install, NULL);
1053*bdc37934SDmitry Chagin 
1054*bdc37934SDmitry Chagin static void
1055*bdc37934SDmitry Chagin linux_vdso_deinstall(void *param)
1056*bdc37934SDmitry Chagin {
1057*bdc37934SDmitry Chagin 
1058*bdc37934SDmitry Chagin 	__elfN(linux_shared_page_fini)(linux_shared_page_obj);
1059*bdc37934SDmitry Chagin };
1060*bdc37934SDmitry Chagin SYSUNINIT(elf_linux_vdso_uninit, SI_SUB_EXEC, SI_ORDER_FIRST,
1061*bdc37934SDmitry Chagin     (sysinit_cfunc_t)linux_vdso_deinstall, NULL);
1062e1743d02SSøren Schmidt 
106389ffc202SBjoern A. Zeeb static char GNU_ABI_VENDOR[] = "GNU";
106489ffc202SBjoern A. Zeeb static int GNULINUX_ABI_DESC = 0;
106589ffc202SBjoern A. Zeeb 
106689ffc202SBjoern A. Zeeb static boolean_t
106789ffc202SBjoern A. Zeeb linux_trans_osrel(const Elf_Note *note, int32_t *osrel)
106889ffc202SBjoern A. Zeeb {
106989ffc202SBjoern A. Zeeb 	const Elf32_Word *desc;
107089ffc202SBjoern A. Zeeb 	uintptr_t p;
107189ffc202SBjoern A. Zeeb 
107289ffc202SBjoern A. Zeeb 	p = (uintptr_t)(note + 1);
107389ffc202SBjoern A. Zeeb 	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
107489ffc202SBjoern A. Zeeb 
107589ffc202SBjoern A. Zeeb 	desc = (const Elf32_Word *)p;
107689ffc202SBjoern A. Zeeb 	if (desc[0] != GNULINUX_ABI_DESC)
107789ffc202SBjoern A. Zeeb 		return (FALSE);
107889ffc202SBjoern A. Zeeb 
107989ffc202SBjoern A. Zeeb 	/*
108089ffc202SBjoern A. Zeeb 	 * For linux we encode osrel as follows (see linux_mib.c):
108189ffc202SBjoern A. Zeeb 	 * VVVMMMIII (version, major, minor), see linux_mib.c.
108289ffc202SBjoern A. Zeeb 	 */
108389ffc202SBjoern A. Zeeb 	*osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3];
108489ffc202SBjoern A. Zeeb 
108589ffc202SBjoern A. Zeeb 	return (TRUE);
108689ffc202SBjoern A. Zeeb }
108732c01de2SDmitry Chagin 
108832c01de2SDmitry Chagin static Elf_Brandnote linux_brandnote = {
108989ffc202SBjoern A. Zeeb 	.hdr.n_namesz	= sizeof(GNU_ABI_VENDOR),
109089ffc202SBjoern A. Zeeb 	.hdr.n_descsz	= 16,	/* XXX at least 16 */
109132c01de2SDmitry Chagin 	.hdr.n_type	= 1,
109289ffc202SBjoern A. Zeeb 	.vendor		= GNU_ABI_VENDOR,
109389ffc202SBjoern A. Zeeb 	.flags		= BN_TRANSLATE_OSREL,
109489ffc202SBjoern A. Zeeb 	.trans_osrel	= linux_trans_osrel
109532c01de2SDmitry Chagin };
109632c01de2SDmitry Chagin 
1097514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
1098a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1099a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1100a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1101a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1102a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.1",
1103a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1104a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
110532c01de2SDmitry Chagin 	.brand_note	= &linux_brandnote,
11062dedc128SDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
11075cf588ebSPeter Wemm };
11085cf588ebSPeter Wemm 
1109514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
1110a8d403e1SKonstantin Belousov 	.brand		= ELFOSABI_LINUX,
1111a8d403e1SKonstantin Belousov 	.machine	= EM_386,
1112a8d403e1SKonstantin Belousov 	.compat_3_brand	= "Linux",
1113a8d403e1SKonstantin Belousov 	.emul_path	= "/compat/linux",
1114a8d403e1SKonstantin Belousov 	.interp_path	= "/lib/ld-linux.so.2",
1115a8d403e1SKonstantin Belousov 	.sysvec		= &elf_linux_sysvec,
1116a8d403e1SKonstantin Belousov 	.interp_newpath	= NULL,
111732c01de2SDmitry Chagin 	.brand_note	= &linux_brandnote,
11182dedc128SDmitry Chagin 	.flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE
11194e138a28SMike Smith };
11204e138a28SMike Smith 
1121514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
1122514058dcSAlexander Langer 	&linux_brand,
1123514058dcSAlexander Langer 	&linux_glibc2brand,
1124514058dcSAlexander Langer 	NULL
1125514058dcSAlexander Langer };
1126514058dcSAlexander Langer 
1127aa855a59SPeter Wemm static int
1128c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
1129d30ea4f5SPeter Wemm {
1130514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
1131514058dcSAlexander Langer 	int error;
1132f41325dbSPeter Wemm 	struct linux_ioctl_handler **lihp;
1133060e4882SDoug Ambrisko 	struct linux_device_handler **ldhp;
1134514058dcSAlexander Langer 
1135514058dcSAlexander Langer 	error = 0;
1136514058dcSAlexander Langer 
1137aa855a59SPeter Wemm 	switch(type) {
1138aa855a59SPeter Wemm 	case MOD_LOAD:
1139aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1140aa855a59SPeter Wemm 		     ++brandinfo)
11413ebc1248SPeter Wemm 			if (elf32_insert_brand_entry(*brandinfo) < 0)
1142aa855a59SPeter Wemm 				error = EINVAL;
1143466b14d7SMarcel Moolenaar 		if (error == 0) {
1144f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1145f41325dbSPeter Wemm 				linux_ioctl_register_handler(*lihp);
1146060e4882SDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
1147060e4882SDoug Ambrisko 				linux_device_register_handler(*ldhp);
11489b44bfc5SAlexander Leidinger 			LIST_INIT(&futex_list);
114979262bf1SDmitry Chagin 			mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF);
11509b44bfc5SAlexander Leidinger 			linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, linux_proc_exit,
11519b44bfc5SAlexander Leidinger 			      NULL, 1000);
11529b44bfc5SAlexander Leidinger 			linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec,
11539b44bfc5SAlexander Leidinger 			      NULL, 1000);
115481338031SDmitry Chagin 			linux_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor,
115581338031SDmitry Chagin 			    linux_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
11564d7c2e8aSDmitry Chagin 			linux_get_machine(&linux_platform);
11574d7c2e8aSDmitry Chagin 			linux_szplatform = roundup(strlen(linux_platform) + 1,
11584d7c2e8aSDmitry Chagin 			    sizeof(char *));
11597ae27ff4SJamie Gritton 			linux_osd_jail_register();
11601ca16454SDmitry Chagin 			stclohz = (stathz ? stathz : hz);
116143bef515SMarcel Moolenaar 			if (bootverbose)
1162466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler installed\n");
1163466b14d7SMarcel Moolenaar 		} else
1164466b14d7SMarcel Moolenaar 			printf("cannot insert Linux ELF brand handler\n");
1165aa855a59SPeter Wemm 		break;
1166aa855a59SPeter Wemm 	case MOD_UNLOAD:
1167aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1168aa855a59SPeter Wemm 		     ++brandinfo)
11693ebc1248SPeter Wemm 			if (elf32_brand_inuse(*brandinfo))
1170d2758342SMark Newton 				error = EBUSY;
1171d2758342SMark Newton 		if (error == 0) {
1172d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
1173d2758342SMark Newton 			     *brandinfo != NULL; ++brandinfo)
11743ebc1248SPeter Wemm 				if (elf32_remove_brand_entry(*brandinfo) < 0)
1175aa855a59SPeter Wemm 					error = EINVAL;
1176d2758342SMark Newton 		}
1177466b14d7SMarcel Moolenaar 		if (error == 0) {
1178f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1179f41325dbSPeter Wemm 				linux_ioctl_unregister_handler(*lihp);
1180060e4882SDoug Ambrisko 			SET_FOREACH(ldhp, linux_device_handler_set)
1181060e4882SDoug Ambrisko 				linux_device_unregister_handler(*ldhp);
118279262bf1SDmitry Chagin 			mtx_destroy(&futex_mtx);
11839b44bfc5SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
11849b44bfc5SAlexander Leidinger 			EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
118581338031SDmitry Chagin 			EVENTHANDLER_DEREGISTER(thread_dtor, linux_thread_dtor_tag);
11867ae27ff4SJamie Gritton 			linux_osd_jail_deregister();
1187466b14d7SMarcel Moolenaar 			if (bootverbose)
1188466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler removed\n");
1189466b14d7SMarcel Moolenaar 		} else
1190aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
1191aa855a59SPeter Wemm 		break;
1192aa855a59SPeter Wemm 	default:
1193af682d48SDmitry Chagin 		return (EOPNOTSUPP);
1194d30ea4f5SPeter Wemm 	}
1195af682d48SDmitry Chagin 	return (error);
1196aa855a59SPeter Wemm }
1197466b14d7SMarcel Moolenaar 
1198aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
1199aa855a59SPeter Wemm 	"linuxelf",
1200aa855a59SPeter Wemm 	linux_elf_modevent,
12019823d527SKevin Lo 	0
1202aa855a59SPeter Wemm };
1203466b14d7SMarcel Moolenaar 
120478ae4338SKonstantin Belousov DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
1205