xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision 7646aefc212d03614233a9ee3ceb1ecc87c076cf)
1d66a5066SPeter Wemm /*-
2e1743d02SSøren Schmidt  * Copyright (c) 1994-1996 S�ren Schmidt
3d66a5066SPeter Wemm  * All rights reserved.
4d66a5066SPeter Wemm  *
5d66a5066SPeter Wemm  * Redistribution and use in source and binary forms, with or without
6d66a5066SPeter Wemm  * modification, are permitted provided that the following conditions
7d66a5066SPeter Wemm  * are met:
8d66a5066SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
9d66a5066SPeter Wemm  *    notice, this list of conditions and the following disclaimer
10d66a5066SPeter Wemm  *    in this position and unchanged.
11d66a5066SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
12d66a5066SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
13d66a5066SPeter Wemm  *    documentation and/or other materials provided with the distribution.
14d66a5066SPeter Wemm  * 3. The name of the author may not be used to endorse or promote products
1521dc7d4fSJens Schweikhardt  *    derived from this software without specific prior written permission
16d66a5066SPeter Wemm  *
17d66a5066SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18d66a5066SPeter Wemm  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19d66a5066SPeter Wemm  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20d66a5066SPeter Wemm  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21d66a5066SPeter Wemm  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22d66a5066SPeter Wemm  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23d66a5066SPeter Wemm  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24d66a5066SPeter Wemm  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25d66a5066SPeter Wemm  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26d66a5066SPeter Wemm  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27d66a5066SPeter Wemm  *
28c3aac50fSPeter Wemm  * $FreeBSD$
29d66a5066SPeter Wemm  */
30d66a5066SPeter Wemm 
31d66a5066SPeter Wemm /* XXX we use functions that might not exist. */
325591b823SEivind Eklund #include "opt_compat.h"
33a9148ab1SPeter Wemm #include "opt_kstack_pages.h"
345591b823SEivind Eklund 
355591b823SEivind Eklund #ifndef COMPAT_43
365591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
375591b823SEivind Eklund #endif
38d66a5066SPeter Wemm 
39d66a5066SPeter Wemm #include <sys/param.h>
4075f83872SPeter Wemm #include <sys/systm.h>
41d66a5066SPeter Wemm #include <sys/imgact.h>
4222d4b0fbSJohn Polstra #include <sys/imgact_aout.h>
43e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
447106ca0dSJohn Baldwin #include <sys/lock.h>
45e1743d02SSøren Schmidt #include <sys/malloc.h>
4623955314SAlfred Perlstein #include <sys/mutex.h>
47fb919e4dSMark Murray #include <sys/proc.h>
48fb919e4dSMark Murray #include <sys/signalvar.h>
49206a5d3aSIan Dowse #include <sys/syscallsubr.h>
50fb919e4dSMark Murray #include <sys/sysent.h>
51fb919e4dSMark Murray #include <sys/sysproto.h>
52a9148ab1SPeter Wemm #include <sys/user.h>
53a9148ab1SPeter Wemm #include <sys/vnode.h>
54fb919e4dSMark Murray 
55d66a5066SPeter Wemm #include <vm/vm.h>
56d66a5066SPeter Wemm #include <vm/vm_param.h>
57d66a5066SPeter Wemm #include <vm/vm_page.h>
58d66a5066SPeter Wemm #include <vm/vm_extern.h>
59d66a5066SPeter Wemm #include <sys/exec.h>
605cf588ebSPeter Wemm #include <sys/kernel.h>
61aa855a59SPeter Wemm #include <sys/module.h>
62d66a5066SPeter Wemm #include <machine/cpu.h>
63a9148ab1SPeter Wemm #include <machine/md_var.h>
64fb919e4dSMark Murray #include <sys/mutex.h>
65d66a5066SPeter Wemm 
66a9148ab1SPeter Wemm #include <vm/vm.h>
67a9148ab1SPeter Wemm #include <vm/vm_param.h>
68a9148ab1SPeter Wemm #include <vm/pmap.h>
69a9148ab1SPeter Wemm #include <vm/vm_map.h>
70a9148ab1SPeter Wemm #include <vm/vm_object.h>
71a9148ab1SPeter Wemm 
72d66a5066SPeter Wemm #include <i386/linux/linux.h>
73ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h>
74b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h>
75322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h>
76e1743d02SSøren Schmidt 
771d91482dSPeter Wemm MODULE_VERSION(linux, 1);
78158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
79158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
80158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
811d91482dSPeter Wemm 
8243bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
8343bef515SMarcel Moolenaar 
84d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN
85d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2123 /* #! */
86d323ddf3SMatthew Dillon #else
87d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2321
88d323ddf3SMatthew Dillon #endif
89d323ddf3SMatthew Dillon 
90e061a6caSMarcel Moolenaar /*
91e061a6caSMarcel Moolenaar  * Allow the sendsig functions to use the ldebug() facility
92e061a6caSMarcel Moolenaar  * even though they are not syscalls themselves. Map them
93e061a6caSMarcel Moolenaar  * to syscall 0. This is slightly less bogus than using
94e061a6caSMarcel Moolenaar  * ldebug(sigreturn).
95e061a6caSMarcel Moolenaar  */
96e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_rt_sendsig	0
97e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_sendsig		0
98e061a6caSMarcel Moolenaar 
9943bef515SMarcel Moolenaar extern char linux_sigcode[];
10043bef515SMarcel Moolenaar extern int linux_szsigcode;
10143bef515SMarcel Moolenaar 
10243bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
10343bef515SMarcel Moolenaar 
104f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
10543bef515SMarcel Moolenaar 
10689c9a483SAlfred Perlstein static int	linux_fixup(register_t **stack_base,
10789c9a483SAlfred Perlstein 		    struct image_params *iparams);
10889c9a483SAlfred Perlstein static int	elf_linux_fixup(register_t **stack_base,
10989c9a483SAlfred Perlstein 		    struct image_params *iparams);
110bda2a3afSBruce Evans static void	linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
111bda2a3afSBruce Evans 		    caddr_t *params);
11289c9a483SAlfred Perlstein static void     linux_sendsig(sig_t catcher, int sig, sigset_t *mask,
11389c9a483SAlfred Perlstein 		    u_long code);
114d66a5066SPeter Wemm 
115d66a5066SPeter Wemm /*
116d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
117d66a5066SPeter Wemm  */
11885f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
119d66a5066SPeter Wemm   	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
120d66a5066SPeter Wemm  	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
121d66a5066SPeter Wemm  	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
122d66a5066SPeter Wemm  	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
123d66a5066SPeter Wemm  	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
124d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
125d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
126d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
12785f118c8SDmitrij Tejblum   	-6, -6, -43, -42, -75, -6, -84
128d66a5066SPeter Wemm };
129d66a5066SPeter Wemm 
130956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
131956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
132956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
133956d3333SMarcel Moolenaar 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 0,
134956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
135956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
136956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
137956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
138956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
139d66a5066SPeter Wemm };
140d66a5066SPeter Wemm 
141956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
142956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
143956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
144956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
145956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
146956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
147956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
148956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
149956d3333SMarcel Moolenaar 	SIGIO, SIGURG, 0
150d66a5066SPeter Wemm };
151d66a5066SPeter Wemm 
15227a828fcSPierre Beyssac #define LINUX_T_UNKNOWN  255
15327a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = {
15427a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 0 */
15527a828fcSPierre Beyssac 	6,			/* 1  T_PRIVINFLT */
15627a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 2 */
15727a828fcSPierre Beyssac 	3,			/* 3  T_BPTFLT */
15827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 4 */
15927a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 5 */
16027a828fcSPierre Beyssac 	16,			/* 6  T_ARITHTRAP */
16127a828fcSPierre Beyssac 	254,			/* 7  T_ASTFLT */
16227a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 8 */
16327a828fcSPierre Beyssac 	13,			/* 9  T_PROTFLT */
16427a828fcSPierre Beyssac 	1,			/* 10 T_TRCTRAP */
16527a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 11 */
16627a828fcSPierre Beyssac 	14,			/* 12 T_PAGEFLT */
16727a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 13 */
16827a828fcSPierre Beyssac 	17,			/* 14 T_ALIGNFLT */
16927a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 15 */
17027a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 16 */
17127a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 17 */
17227a828fcSPierre Beyssac 	0,			/* 18 T_DIVIDE */
17327a828fcSPierre Beyssac 	2,			/* 19 T_NMI */
17427a828fcSPierre Beyssac 	4,			/* 20 T_OFLOW */
17527a828fcSPierre Beyssac 	5,			/* 21 T_BOUND */
17627a828fcSPierre Beyssac 	7,			/* 22 T_DNA */
17727a828fcSPierre Beyssac 	8,			/* 23 T_DOUBLEFLT */
17827a828fcSPierre Beyssac 	9,			/* 24 T_FPOPFLT */
17927a828fcSPierre Beyssac 	10,			/* 25 T_TSSFLT */
18027a828fcSPierre Beyssac 	11,			/* 26 T_SEGNPFLT */
18127a828fcSPierre Beyssac 	12,			/* 27 T_STKFLT */
18227a828fcSPierre Beyssac 	18,			/* 28 T_MCHK */
18327a828fcSPierre Beyssac 	19,			/* 29 T_XMMFLT */
18427a828fcSPierre Beyssac 	15			/* 30 T_RESERVED */
18527a828fcSPierre Beyssac };
18627a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \
18727a828fcSPierre Beyssac     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
18827a828fcSPierre Beyssac      _bsd_to_linux_trapcode[(code)]: \
18927a828fcSPierre Beyssac      LINUX_T_UNKNOWN)
19027a828fcSPierre Beyssac 
191288078beSEivind Eklund /*
192288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
193288078beSEivind Eklund  * means, deal with it here.
194356861dbSMatthew Dillon  *
195356861dbSMatthew Dillon  * MPSAFE
196288078beSEivind Eklund  */
197288078beSEivind Eklund static int
198288078beSEivind Eklund translate_traps(int signal, int trap_code)
199288078beSEivind Eklund {
200d563a53aSEivind Eklund 	if (signal != SIGBUS)
201d563a53aSEivind Eklund 		return signal;
202288078beSEivind Eklund 	switch (trap_code) {
203288078beSEivind Eklund 	case T_PROTFLT:
204288078beSEivind Eklund 	case T_TSSFLT:
205288078beSEivind Eklund 	case T_DOUBLEFLT:
206288078beSEivind Eklund 	case T_PAGEFLT:
207288078beSEivind Eklund 		return SIGSEGV;
208288078beSEivind Eklund 	default:
209288078beSEivind Eklund 		return signal;
210288078beSEivind Eklund 	}
211288078beSEivind Eklund }
212288078beSEivind Eklund 
213303b270bSEivind Eklund static int
214654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp)
215d66a5066SPeter Wemm {
216654f6be1SBruce Evans 	register_t *argv, *envp;
217d66a5066SPeter Wemm 
218d66a5066SPeter Wemm 	argv = *stack_base;
219d66a5066SPeter Wemm 	envp = *stack_base + (imgp->argc + 1);
220d66a5066SPeter Wemm 	(*stack_base)--;
22186a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
222d66a5066SPeter Wemm 	(*stack_base)--;
22386a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
224d66a5066SPeter Wemm 	(*stack_base)--;
22586a14a7aSBruce Evans 	**stack_base = imgp->argc;
226e1743d02SSøren Schmidt 	return 0;
227d66a5066SPeter Wemm }
228d66a5066SPeter Wemm 
229303b270bSEivind Eklund static int
230654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
231e1743d02SSøren Schmidt {
232e1743d02SSøren Schmidt 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
233654f6be1SBruce Evans 	register_t *pos;
234d66a5066SPeter Wemm 
235e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
236e1743d02SSøren Schmidt 
237e1743d02SSøren Schmidt 	if (args->trace) {
238e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
239e1743d02SSøren Schmidt 	}
240e1743d02SSøren Schmidt 	if (args->execfd != -1) {
241e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
242e1743d02SSøren Schmidt 	}
243e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
244e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
245e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
246e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
247e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
248e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
249e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
250611d9407SJohn Baldwin 	PROC_LOCK(imgp->proc);
251b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
252b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
253b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
254b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
255611d9407SJohn Baldwin 	PROC_UNLOCK(imgp->proc);
256e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
257e1743d02SSøren Schmidt 
258e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
259e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
260e1743d02SSøren Schmidt 
261e1743d02SSøren Schmidt 	(*stack_base)--;
262ecbb00a2SDoug Rabson 	**stack_base = (long)imgp->argc;
263e1743d02SSøren Schmidt 	return 0;
264e1743d02SSøren Schmidt }
265d66a5066SPeter Wemm 
266d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
26702318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode;
26879363394SAndrew Gallatin 
26979363394SAndrew Gallatin static void
27079363394SAndrew Gallatin linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
27179363394SAndrew Gallatin {
272b40ce416SJulian Elischer 	register struct thread *td = curthread;
273b40ce416SJulian Elischer 	register struct proc *p = td->td_proc;
27479363394SAndrew Gallatin 	register struct trapframe *regs;
2755002a60fSMarcel Moolenaar 	struct l_rt_sigframe *fp, frame;
27679363394SAndrew Gallatin 	int oonstack;
27779363394SAndrew Gallatin 
278df53e91cSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
279b40ce416SJulian Elischer 	regs = td->td_frame;
280d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
28179363394SAndrew Gallatin 
28279363394SAndrew Gallatin #ifdef DEBUG
2835002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
28424593369SJonathan Lemon 		printf(ARGS(rt_sendsig, "%p, %d, %p, %lu"),
28524593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
28679363394SAndrew Gallatin #endif
28779363394SAndrew Gallatin 	/*
28879363394SAndrew Gallatin 	 * Allocate space for the signal handler context.
28979363394SAndrew Gallatin 	 */
29079363394SAndrew Gallatin 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
291cc6ca9b3SMarcel Moolenaar 	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
2925002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)(p->p_sigstk.ss_sp +
2935002a60fSMarcel Moolenaar 		    p->p_sigstk.ss_size - sizeof(struct l_rt_sigframe));
294d034d459SMarcel Moolenaar 	} else
2955002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)regs->tf_esp - 1;
296611d9407SJohn Baldwin 	PROC_UNLOCK(p);
29779363394SAndrew Gallatin 
29879363394SAndrew Gallatin 	/*
29979363394SAndrew Gallatin 	 * Build the argument list for the signal handler.
30079363394SAndrew Gallatin 	 */
30179363394SAndrew Gallatin 	if (p->p_sysent->sv_sigtbl)
30279363394SAndrew Gallatin 		if (sig <= p->p_sysent->sv_sigsize)
30379363394SAndrew Gallatin 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
30479363394SAndrew Gallatin 
30579363394SAndrew Gallatin 	frame.sf_handler = catcher;
30679363394SAndrew Gallatin 	frame.sf_sig = sig;
30779363394SAndrew Gallatin 	frame.sf_siginfo = &fp->sf_si;
30879363394SAndrew Gallatin 	frame.sf_ucontext = &fp->sf_sc;
309cc6ca9b3SMarcel Moolenaar 
31079363394SAndrew Gallatin 	/* Fill siginfo structure. */
31179363394SAndrew Gallatin 	frame.sf_si.lsi_signo = sig;
31279363394SAndrew Gallatin 	frame.sf_si.lsi_code = code;
31379363394SAndrew Gallatin 	frame.sf_si.lsi_addr = (void *)regs->tf_err;
314cc6ca9b3SMarcel Moolenaar 
31579363394SAndrew Gallatin 	/*
31679363394SAndrew Gallatin 	 * Build the signal context to be used by sigreturn.
31779363394SAndrew Gallatin 	 */
318cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
319cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_link = NULL;		/* XXX ??? */
320cc6ca9b3SMarcel Moolenaar 
321611d9407SJohn Baldwin 	PROC_LOCK(p);
322cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_sp = p->p_sigstk.ss_sp;
323cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_size = p->p_sigstk.ss_size;
324d034d459SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
325d034d459SMarcel Moolenaar 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
326611d9407SJohn Baldwin 	PROC_UNLOCK(p);
327cc6ca9b3SMarcel Moolenaar 
328cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
329cc6ca9b3SMarcel Moolenaar 
330cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
33179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_gs     = rgs();
33279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
33379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
33479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
33579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_edi;
33679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_esi;
33779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_ebp;
33879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_ebx;
33979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_edx;
34079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_ecx;
34179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_eax;
34279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_eip;
34379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
34479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags;
34579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp;
34679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
34779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
34827a828fcSPierre Beyssac 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
34979363394SAndrew Gallatin 
35079363394SAndrew Gallatin #ifdef DEBUG
3515002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
35224593369SJonathan Lemon 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
35324593369SJonathan Lemon 		    frame.sf_sc.uc_stack.ss_flags, p->p_sigstk.ss_sp,
35424593369SJonathan Lemon 		    p->p_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
35579363394SAndrew Gallatin #endif
35679363394SAndrew Gallatin 
35779363394SAndrew Gallatin 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
35879363394SAndrew Gallatin 		/*
35979363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
36079363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
36179363394SAndrew Gallatin 		 */
36289734883SAlan Cox #ifdef DEBUG
36389734883SAlan Cox 		if (ldebug(rt_sendsig))
36489734883SAlan Cox 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
36589734883SAlan Cox 			    fp, oonstack);
36689734883SAlan Cox #endif
36719eb87d2SJohn Baldwin 		PROC_LOCK(p);
368b40ce416SJulian Elischer 		sigexit(td, SIGILL);
36979363394SAndrew Gallatin 	}
37079363394SAndrew Gallatin 
37179363394SAndrew Gallatin 	/*
37279363394SAndrew Gallatin 	 * Build context to run handler in.
37379363394SAndrew Gallatin 	 */
37479363394SAndrew Gallatin 	regs->tf_esp = (int)fp;
37579363394SAndrew Gallatin 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) +
37602318dacSJake Burkholder 	    linux_sznonrtsigcode;
377846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
37879363394SAndrew Gallatin 	regs->tf_cs = _ucodesel;
37979363394SAndrew Gallatin 	regs->tf_ds = _udatasel;
38079363394SAndrew Gallatin 	regs->tf_es = _udatasel;
38179363394SAndrew Gallatin 	regs->tf_fs = _udatasel;
38279363394SAndrew Gallatin 	regs->tf_ss = _udatasel;
383df53e91cSJohn Baldwin 	PROC_LOCK(p);
38479363394SAndrew Gallatin }
38579363394SAndrew Gallatin 
386d66a5066SPeter Wemm 
387d66a5066SPeter Wemm /*
388d66a5066SPeter Wemm  * Send an interrupt to process.
389d66a5066SPeter Wemm  *
390d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
391d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
392d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
393d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
394d66a5066SPeter Wemm  * frame pointer, it returns to the user
395d66a5066SPeter Wemm  * specified pc, psl.
396d66a5066SPeter Wemm  */
397d66a5066SPeter Wemm 
398303b270bSEivind Eklund static void
399956d3333SMarcel Moolenaar linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
400d66a5066SPeter Wemm {
401b40ce416SJulian Elischer 	register struct thread *td = curthread;
402b40ce416SJulian Elischer 	register struct proc *p = td->td_proc;
403213fdd80SPeter Wemm 	register struct trapframe *regs;
4045002a60fSMarcel Moolenaar 	struct l_sigframe *fp, frame;
4055002a60fSMarcel Moolenaar 	l_sigset_t lmask;
4062c4ab9ddSAndrew Gallatin 	int oonstack, i;
407d66a5066SPeter Wemm 
4082509e6c2SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
409cc6ca9b3SMarcel Moolenaar 	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
410cc6ca9b3SMarcel Moolenaar 		/* Signal handler installed with SA_SIGINFO. */
411cc6ca9b3SMarcel Moolenaar 		linux_rt_sendsig(catcher, sig, mask, code);
412cc6ca9b3SMarcel Moolenaar 		return;
413cc6ca9b3SMarcel Moolenaar 	}
414cc6ca9b3SMarcel Moolenaar 
415b40ce416SJulian Elischer 	regs = td->td_frame;
416d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
417d66a5066SPeter Wemm 
418d66a5066SPeter Wemm #ifdef DEBUG
4195002a60fSMarcel Moolenaar 	if (ldebug(sendsig))
42024593369SJonathan Lemon 		printf(ARGS(sendsig, "%p, %d, %p, %lu"),
42124593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
422d66a5066SPeter Wemm #endif
42379363394SAndrew Gallatin 
424d66a5066SPeter Wemm 	/*
425d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
426d66a5066SPeter Wemm 	 */
427645682fdSLuoqi Chen 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
428cc6ca9b3SMarcel Moolenaar 	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
4295002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)(p->p_sigstk.ss_sp +
4305002a60fSMarcel Moolenaar 		    p->p_sigstk.ss_size - sizeof(struct l_sigframe));
431d034d459SMarcel Moolenaar 	} else
4325002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)regs->tf_esp - 1;
433611d9407SJohn Baldwin 	PROC_UNLOCK(p);
434d66a5066SPeter Wemm 
435d66a5066SPeter Wemm 	/*
436d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
437d66a5066SPeter Wemm 	 */
438956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
439956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
440956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
441d66a5066SPeter Wemm 
442d66a5066SPeter Wemm 	frame.sf_handler = catcher;
443d66a5066SPeter Wemm 	frame.sf_sig = sig;
444d66a5066SPeter Wemm 
445cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &lmask);
446cc6ca9b3SMarcel Moolenaar 
447d66a5066SPeter Wemm 	/*
448d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
449d66a5066SPeter Wemm 	 */
450cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.sc_mask   = lmask.__bits[0];
4515206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
4525206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
453213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
454213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
455213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
456213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
457213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
458213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
459213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
460213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
461213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
462213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
463213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
464213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
465213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
466213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
467213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
46827a828fcSPierre Beyssac 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code);
469cc6ca9b3SMarcel Moolenaar 
4705002a60fSMarcel Moolenaar 	bzero(&frame.sf_fpstate, sizeof(struct l_fpstate));
471cc6ca9b3SMarcel Moolenaar 
4722c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
473cc6ca9b3SMarcel Moolenaar 		frame.sf_extramask[i] = lmask.__bits[i+1];
474d66a5066SPeter Wemm 
475d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
476d66a5066SPeter Wemm 		/*
477d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
478d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
479d66a5066SPeter Wemm 		 */
48019eb87d2SJohn Baldwin 		PROC_LOCK(p);
481b40ce416SJulian Elischer 		sigexit(td, SIGILL);
482d66a5066SPeter Wemm 	}
483d66a5066SPeter Wemm 
484d66a5066SPeter Wemm 	/*
485d66a5066SPeter Wemm 	 * Build context to run handler in.
486d66a5066SPeter Wemm 	 */
487213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
4884c56fcdeSBruce Evans 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
489846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
490213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
491213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
492213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
4935206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
494213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
4955002a60fSMarcel Moolenaar 	PROC_LOCK(p);
496d66a5066SPeter Wemm }
497d66a5066SPeter Wemm 
498d66a5066SPeter Wemm /*
499d66a5066SPeter Wemm  * System call to cleanup state after a signal
500d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
501d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
502d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
503d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
504d66a5066SPeter Wemm  * make sure that the user has not modified the
505d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
506d66a5066SPeter Wemm  * a machine fault.
507d66a5066SPeter Wemm  */
508d66a5066SPeter Wemm int
509b40ce416SJulian Elischer linux_sigreturn(td, args)
510b40ce416SJulian Elischer 	struct thread *td;
511d66a5066SPeter Wemm 	struct linux_sigreturn_args *args;
512d66a5066SPeter Wemm {
513b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
5145002a60fSMarcel Moolenaar 	struct l_sigframe frame;
515213fdd80SPeter Wemm 	register struct trapframe *regs;
5165002a60fSMarcel Moolenaar 	l_sigset_t lmask;
5172c4ab9ddSAndrew Gallatin 	int eflags, i;
518d66a5066SPeter Wemm 
519b40ce416SJulian Elischer 	regs = td->td_frame;
520d66a5066SPeter Wemm 
521d66a5066SPeter Wemm #ifdef DEBUG
52224593369SJonathan Lemon 	if (ldebug(sigreturn))
52324593369SJonathan Lemon 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
524d66a5066SPeter Wemm #endif
525d66a5066SPeter Wemm 	/*
526cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the sigframe.
527d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
528d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
529d66a5066SPeter Wemm 	 */
530cc6ca9b3SMarcel Moolenaar 	if (copyin((caddr_t)args->sfp, &frame, sizeof(frame)) != 0)
531d66a5066SPeter Wemm 		return (EFAULT);
532d66a5066SPeter Wemm 
533d66a5066SPeter Wemm 	/*
534d66a5066SPeter Wemm 	 * Check for security violations.
535d66a5066SPeter Wemm 	 */
536d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
537cc6ca9b3SMarcel Moolenaar 	eflags = frame.sf_sc.sc_eflags;
538d66a5066SPeter Wemm 	/*
539d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
540d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
541d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
542d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
543d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
544d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
545d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
546d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
547d66a5066SPeter Wemm 	 */
548213fdd80SPeter Wemm 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
549d66a5066SPeter Wemm     		return(EINVAL);
550d66a5066SPeter Wemm 	}
551d66a5066SPeter Wemm 
552d66a5066SPeter Wemm 	/*
553d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
554d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
555d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
556d66a5066SPeter Wemm 	 */
55740d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
558cc6ca9b3SMarcel Moolenaar 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
559d66a5066SPeter Wemm 		trapsignal(p, SIGBUS, T_PROTFLT);
560d66a5066SPeter Wemm 		return(EINVAL);
561d66a5066SPeter Wemm 	}
562d66a5066SPeter Wemm 
563cc6ca9b3SMarcel Moolenaar 	lmask.__bits[0] = frame.sf_sc.sc_mask;
5642c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
565cc6ca9b3SMarcel Moolenaar 		lmask.__bits[i+1] = frame.sf_extramask[i];
566611d9407SJohn Baldwin 	PROC_LOCK(p);
567cc6ca9b3SMarcel Moolenaar 	linux_to_bsd_sigset(&lmask, &p->p_sigmask);
568645682fdSLuoqi Chen 	SIG_CANTMASK(p->p_sigmask);
56979065dbaSBruce Evans 	signotify(p);
570611d9407SJohn Baldwin 	PROC_UNLOCK(p);
571956d3333SMarcel Moolenaar 
572d66a5066SPeter Wemm 	/*
573d66a5066SPeter Wemm 	 * Restore signal context.
574d66a5066SPeter Wemm 	 */
5755206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
576cc6ca9b3SMarcel Moolenaar 	regs->tf_fs     = frame.sf_sc.sc_fs;
577cc6ca9b3SMarcel Moolenaar 	regs->tf_es     = frame.sf_sc.sc_es;
578cc6ca9b3SMarcel Moolenaar 	regs->tf_ds     = frame.sf_sc.sc_ds;
579cc6ca9b3SMarcel Moolenaar 	regs->tf_edi    = frame.sf_sc.sc_edi;
580cc6ca9b3SMarcel Moolenaar 	regs->tf_esi    = frame.sf_sc.sc_esi;
581cc6ca9b3SMarcel Moolenaar 	regs->tf_ebp    = frame.sf_sc.sc_ebp;
582cc6ca9b3SMarcel Moolenaar 	regs->tf_ebx    = frame.sf_sc.sc_ebx;
583cc6ca9b3SMarcel Moolenaar 	regs->tf_edx    = frame.sf_sc.sc_edx;
584cc6ca9b3SMarcel Moolenaar 	regs->tf_ecx    = frame.sf_sc.sc_ecx;
585cc6ca9b3SMarcel Moolenaar 	regs->tf_eax    = frame.sf_sc.sc_eax;
586cc6ca9b3SMarcel Moolenaar 	regs->tf_eip    = frame.sf_sc.sc_eip;
587cc6ca9b3SMarcel Moolenaar 	regs->tf_cs     = frame.sf_sc.sc_cs;
588213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
589cc6ca9b3SMarcel Moolenaar 	regs->tf_esp    = frame.sf_sc.sc_esp_at_signal;
590cc6ca9b3SMarcel Moolenaar 	regs->tf_ss     = frame.sf_sc.sc_ss;
591d66a5066SPeter Wemm 
592d66a5066SPeter Wemm 	return (EJUSTRETURN);
593d66a5066SPeter Wemm }
594d66a5066SPeter Wemm 
59579363394SAndrew Gallatin /*
59679363394SAndrew Gallatin  * System call to cleanup state after a signal
59779363394SAndrew Gallatin  * has been taken.  Reset signal mask and
59879363394SAndrew Gallatin  * stack state from context left by rt_sendsig (above).
59979363394SAndrew Gallatin  * Return to previous pc and psl as specified by
60079363394SAndrew Gallatin  * context left by sendsig. Check carefully to
60179363394SAndrew Gallatin  * make sure that the user has not modified the
60279363394SAndrew Gallatin  * psl to gain improper privileges or to cause
60379363394SAndrew Gallatin  * a machine fault.
60479363394SAndrew Gallatin  */
60579363394SAndrew Gallatin int
606b40ce416SJulian Elischer linux_rt_sigreturn(td, args)
607b40ce416SJulian Elischer 	struct thread *td;
60879363394SAndrew Gallatin 	struct linux_rt_sigreturn_args *args;
60979363394SAndrew Gallatin {
610b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
6115002a60fSMarcel Moolenaar 	struct l_ucontext uc;
6125002a60fSMarcel Moolenaar 	struct l_sigcontext *context;
6135002a60fSMarcel Moolenaar 	l_stack_t *lss;
614206a5d3aSIan Dowse 	stack_t ss;
61579363394SAndrew Gallatin 	register struct trapframe *regs;
61679363394SAndrew Gallatin 	int eflags;
61779363394SAndrew Gallatin 
618b40ce416SJulian Elischer 	regs = td->td_frame;
61979363394SAndrew Gallatin 
62079363394SAndrew Gallatin #ifdef DEBUG
62124593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
62224593369SJonathan Lemon 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
62379363394SAndrew Gallatin #endif
62479363394SAndrew Gallatin 	/*
625cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the ucontext.
62679363394SAndrew Gallatin 	 * It is unsafe to keep track of it ourselves, in the event that a
62779363394SAndrew Gallatin 	 * program jumps out of a signal handler.
62879363394SAndrew Gallatin 	 */
62979363394SAndrew Gallatin 	if (copyin((caddr_t)args->ucp, &uc, sizeof(uc)) != 0)
63079363394SAndrew Gallatin 		return (EFAULT);
63179363394SAndrew Gallatin 
63279363394SAndrew Gallatin 	context = &uc.uc_mcontext;
63379363394SAndrew Gallatin 
63479363394SAndrew Gallatin 	/*
63579363394SAndrew Gallatin 	 * Check for security violations.
63679363394SAndrew Gallatin 	 */
63779363394SAndrew Gallatin #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
63879363394SAndrew Gallatin 	eflags = context->sc_eflags;
63979363394SAndrew Gallatin 	/*
64079363394SAndrew Gallatin 	 * XXX do allow users to change the privileged flag PSL_RF.  The
64179363394SAndrew Gallatin 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
64279363394SAndrew Gallatin 	 * sometimes set it there too.  tf_eflags is kept in the signal
64379363394SAndrew Gallatin 	 * context during signal handling and there is no other place
64479363394SAndrew Gallatin 	 * to remember it, so the PSL_RF bit may be corrupted by the
64579363394SAndrew Gallatin 	 * signal handler without us knowing.  Corruption of the PSL_RF
64679363394SAndrew Gallatin 	 * bit at worst causes one more or one less debugger trap, so
64779363394SAndrew Gallatin 	 * allowing it is fairly harmless.
64879363394SAndrew Gallatin 	 */
64979363394SAndrew Gallatin 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
65079363394SAndrew Gallatin     		return(EINVAL);
65179363394SAndrew Gallatin 	}
65279363394SAndrew Gallatin 
65379363394SAndrew Gallatin 	/*
65479363394SAndrew Gallatin 	 * Don't allow users to load a valid privileged %cs.  Let the
65579363394SAndrew Gallatin 	 * hardware check for invalid selectors, excess privilege in
65679363394SAndrew Gallatin 	 * other selectors, invalid %eip's and invalid %esp's.
65779363394SAndrew Gallatin 	 */
65879363394SAndrew Gallatin #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
65979363394SAndrew Gallatin 	if (!CS_SECURE(context->sc_cs)) {
66079363394SAndrew Gallatin 		trapsignal(p, SIGBUS, T_PROTFLT);
66179363394SAndrew Gallatin 		return(EINVAL);
66279363394SAndrew Gallatin 	}
66379363394SAndrew Gallatin 
664611d9407SJohn Baldwin 	PROC_LOCK(p);
665b595ab37SAndrew Gallatin 	linux_to_bsd_sigset(&uc.uc_sigmask, &p->p_sigmask);
66679363394SAndrew Gallatin 	SIG_CANTMASK(p->p_sigmask);
66779065dbaSBruce Evans 	signotify(p);
668611d9407SJohn Baldwin 	PROC_UNLOCK(p);
66979363394SAndrew Gallatin 
67079363394SAndrew Gallatin 	/*
671cc6ca9b3SMarcel Moolenaar 	 * Restore signal context
67279363394SAndrew Gallatin 	 */
67379363394SAndrew Gallatin 	/* %gs was restored by the trampoline. */
67479363394SAndrew Gallatin 	regs->tf_fs     = context->sc_fs;
67579363394SAndrew Gallatin 	regs->tf_es     = context->sc_es;
67679363394SAndrew Gallatin 	regs->tf_ds     = context->sc_ds;
67779363394SAndrew Gallatin 	regs->tf_edi    = context->sc_edi;
67879363394SAndrew Gallatin 	regs->tf_esi    = context->sc_esi;
67979363394SAndrew Gallatin 	regs->tf_ebp    = context->sc_ebp;
68079363394SAndrew Gallatin 	regs->tf_ebx    = context->sc_ebx;
68179363394SAndrew Gallatin 	regs->tf_edx    = context->sc_edx;
68279363394SAndrew Gallatin 	regs->tf_ecx    = context->sc_ecx;
68379363394SAndrew Gallatin 	regs->tf_eax    = context->sc_eax;
68479363394SAndrew Gallatin 	regs->tf_eip    = context->sc_eip;
68579363394SAndrew Gallatin 	regs->tf_cs     = context->sc_cs;
68679363394SAndrew Gallatin 	regs->tf_eflags = eflags;
68779363394SAndrew Gallatin 	regs->tf_esp    = context->sc_esp_at_signal;
68879363394SAndrew Gallatin 	regs->tf_ss     = context->sc_ss;
68979363394SAndrew Gallatin 
69079363394SAndrew Gallatin 	/*
69179363394SAndrew Gallatin 	 * call sigaltstack & ignore results..
69279363394SAndrew Gallatin 	 */
69379363394SAndrew Gallatin 	lss = &uc.uc_stack;
694206a5d3aSIan Dowse 	ss.ss_sp = lss->ss_sp;
695206a5d3aSIan Dowse 	ss.ss_size = lss->ss_size;
696206a5d3aSIan Dowse 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
69779363394SAndrew Gallatin 
69879363394SAndrew Gallatin #ifdef DEBUG
69924593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
70024593369SJonathan Lemon 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
701206a5d3aSIan Dowse 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
70279363394SAndrew Gallatin #endif
703206a5d3aSIan Dowse 	(void)kern_sigaltstack(td, &ss, NULL);
70479363394SAndrew Gallatin 
70579363394SAndrew Gallatin 	return (EJUSTRETURN);
70679363394SAndrew Gallatin }
70779363394SAndrew Gallatin 
708356861dbSMatthew Dillon /*
709356861dbSMatthew Dillon  * MPSAFE
710356861dbSMatthew Dillon  */
711303b270bSEivind Eklund static void
712d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
713d66a5066SPeter Wemm {
714d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
715d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
716d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
717d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
718d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
7197646aefcSPeter Wemm 	args[5] = tf->tf_ebp;	/* Unconfirmed */
720d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
721d66a5066SPeter Wemm }
722d66a5066SPeter Wemm 
723a9148ab1SPeter Wemm 
724a9148ab1SPeter Wemm 
725a9148ab1SPeter Wemm /*
726a9148ab1SPeter Wemm  * Dump core, into a file named as described in the comments for
727a9148ab1SPeter Wemm  * expand_name(), unless the process was setuid/setgid.
728a9148ab1SPeter Wemm  */
729a9148ab1SPeter Wemm static int
730a9148ab1SPeter Wemm linux_aout_coredump(struct thread *td, struct vnode *vp, off_t limit)
731a9148ab1SPeter Wemm {
732a9148ab1SPeter Wemm 	struct proc *p = td->td_proc;
733a9148ab1SPeter Wemm 	struct ucred *cred = td->td_ucred;
734a9148ab1SPeter Wemm 	struct vmspace *vm = p->p_vmspace;
735a9148ab1SPeter Wemm 	caddr_t tempuser;
736a9148ab1SPeter Wemm 	int error;
737a9148ab1SPeter Wemm 
738a9148ab1SPeter Wemm 	if (ctob((UAREA_PAGES + KSTACK_PAGES) +
739a9148ab1SPeter Wemm 	    vm->vm_dsize + vm->vm_ssize) >= limit)
740a9148ab1SPeter Wemm 		return (EFAULT);
741a9148ab1SPeter Wemm 	tempuser = malloc(ctob(UAREA_PAGES + KSTACK_PAGES), M_TEMP,
742a9148ab1SPeter Wemm 	    M_WAITOK | M_ZERO);
743a9148ab1SPeter Wemm 	if (tempuser == NULL)
744a9148ab1SPeter Wemm 		return (ENOMEM);
745a9148ab1SPeter Wemm 	bcopy(p->p_uarea, tempuser, sizeof(struct user));
746a9148ab1SPeter Wemm 	bcopy(td->td_frame,
747a9148ab1SPeter Wemm 	    tempuser + ctob(UAREA_PAGES) +
748a9148ab1SPeter Wemm 	    ((caddr_t) td->td_frame - (caddr_t) td->td_kstack),
749a9148ab1SPeter Wemm 	    sizeof(struct trapframe));
750a9148ab1SPeter Wemm 	PROC_LOCK(p);
751a9148ab1SPeter Wemm 	fill_kinfo_proc(p, &p->p_uarea->u_kproc);
752a9148ab1SPeter Wemm 	PROC_UNLOCK(p);
753a9148ab1SPeter Wemm 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t) tempuser,
754a9148ab1SPeter Wemm 	    ctob(UAREA_PAGES + KSTACK_PAGES),
755a9148ab1SPeter Wemm 	    (off_t)0, UIO_SYSSPACE, IO_UNIT, cred, NOCRED,
756a9148ab1SPeter Wemm 	    (int *)NULL, td);
757a9148ab1SPeter Wemm 	free(tempuser, M_TEMP);
758a9148ab1SPeter Wemm 	if (error == 0)
759a9148ab1SPeter Wemm 		error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,
760a9148ab1SPeter Wemm 		    (int)ctob(vm->vm_dsize),
761a9148ab1SPeter Wemm 		    (off_t)ctob(UAREA_PAGES + KSTACK_PAGES), UIO_USERSPACE,
762a9148ab1SPeter Wemm 		    IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
763a9148ab1SPeter Wemm 	if (error == 0)
764a9148ab1SPeter Wemm 		error = vn_rdwr_inchunks(UIO_WRITE, vp,
765a9148ab1SPeter Wemm 		    (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)),
766a9148ab1SPeter Wemm 		    round_page(ctob(vm->vm_ssize)),
767a9148ab1SPeter Wemm 		    (off_t)ctob(UAREA_PAGES + KSTACK_PAGES) +
768a9148ab1SPeter Wemm 		        ctob(vm->vm_dsize), UIO_USERSPACE,
769a9148ab1SPeter Wemm 		    IO_UNIT | IO_DIRECT, cred, NOCRED, (int *) NULL, td);
770a9148ab1SPeter Wemm 	return (error);
771a9148ab1SPeter Wemm }
772d323ddf3SMatthew Dillon /*
773d323ddf3SMatthew Dillon  * If a linux binary is exec'ing something, try this image activator
774d323ddf3SMatthew Dillon  * first.  We override standard shell script execution in order to
775d323ddf3SMatthew Dillon  * be able to modify the interpreter path.  We only do this if a linux
776d323ddf3SMatthew Dillon  * binary is doing the exec, so we do not create an EXEC module for it.
777d323ddf3SMatthew Dillon  */
77889c9a483SAlfred Perlstein static int	exec_linux_imgact_try(struct image_params *iparams);
779d323ddf3SMatthew Dillon 
780d323ddf3SMatthew Dillon static int
781d323ddf3SMatthew Dillon exec_linux_imgact_try(imgp)
782d323ddf3SMatthew Dillon     struct image_params *imgp;
783d323ddf3SMatthew Dillon {
784d323ddf3SMatthew Dillon     const char *head = (const char *)imgp->image_header;
785d323ddf3SMatthew Dillon     int error = -1;
786d323ddf3SMatthew Dillon 
787d323ddf3SMatthew Dillon     /*
788d323ddf3SMatthew Dillon      * The interpreter for shell scripts run from a linux binary needs
789d323ddf3SMatthew Dillon      * to be located in /compat/linux if possible in order to recursively
790d323ddf3SMatthew Dillon      * maintain linux path emulation.
791d323ddf3SMatthew Dillon      */
792d323ddf3SMatthew Dillon     if (((const short *)head)[0] == SHELLMAGIC) {
793d323ddf3SMatthew Dillon 	    /*
794d323ddf3SMatthew Dillon 	     * Run our normal shell image activator.  If it succeeds attempt
795d323ddf3SMatthew Dillon 	     * to use the alternate path for the interpreter.  If an alternate
796d323ddf3SMatthew Dillon 	     * path is found, use our stringspace to store it.
797d323ddf3SMatthew Dillon 	     */
798d323ddf3SMatthew Dillon 	    if ((error = exec_shell_imgact(imgp)) == 0) {
799d323ddf3SMatthew Dillon 		    char *rpath = NULL;
800d323ddf3SMatthew Dillon 
801079b7badSJulian Elischer 		    linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL,
802d323ddf3SMatthew Dillon 			imgp->interpreter_name, &rpath, 0);
803d323ddf3SMatthew Dillon 		    if (rpath != imgp->interpreter_name) {
804d323ddf3SMatthew Dillon 			    int len = strlen(rpath) + 1;
805d323ddf3SMatthew Dillon 
806d323ddf3SMatthew Dillon 			    if (len <= MAXSHELLCMDLEN) {
807d323ddf3SMatthew Dillon 				    memcpy(imgp->interpreter_name, rpath, len);
808d323ddf3SMatthew Dillon 			    }
809d323ddf3SMatthew Dillon 			    free(rpath, M_TEMP);
810d323ddf3SMatthew Dillon 		    }
811d323ddf3SMatthew Dillon 	    }
812d323ddf3SMatthew Dillon     }
813d323ddf3SMatthew Dillon     return(error);
814d323ddf3SMatthew Dillon }
815d323ddf3SMatthew Dillon 
816d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
817e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
818d66a5066SPeter Wemm 	linux_sysent,
819d66a5066SPeter Wemm 	0xff,
820956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
821d66a5066SPeter Wemm 	bsd_to_linux_signal,
82285f118c8SDmitrij Tejblum 	ELAST + 1,
823d66a5066SPeter Wemm 	bsd_to_linux_errno,
824288078beSEivind Eklund 	translate_traps,
825d66a5066SPeter Wemm 	linux_fixup,
826d66a5066SPeter Wemm 	linux_sendsig,
827d66a5066SPeter Wemm 	linux_sigcode,
828d66a5066SPeter Wemm 	&linux_szsigcode,
829d66a5066SPeter Wemm 	linux_prepsyscall,
83022d4b0fbSJohn Polstra 	"Linux a.out",
831a9148ab1SPeter Wemm 	linux_aout_coredump,
832806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
833f36ba452SJake Burkholder 	LINUX_MINSIGSTKSZ,
834f36ba452SJake Burkholder 	PAGE_SIZE,
835f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
836f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
837f36ba452SJake Burkholder 	USRSTACK,
838f36ba452SJake Burkholder 	PS_STRINGS,
839f36ba452SJake Burkholder 	VM_PROT_ALL,
840f36ba452SJake Burkholder 	exec_copyout_strings,
841f36ba452SJake Burkholder 	exec_setregs
842d66a5066SPeter Wemm };
843e1743d02SSøren Schmidt 
844e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
845e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
846e1743d02SSøren Schmidt 	linux_sysent,
847e1743d02SSøren Schmidt 	0xff,
848956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
849e1743d02SSøren Schmidt 	bsd_to_linux_signal,
85085f118c8SDmitrij Tejblum 	ELAST + 1,
851e1743d02SSøren Schmidt 	bsd_to_linux_errno,
852288078beSEivind Eklund 	translate_traps,
853e1743d02SSøren Schmidt 	elf_linux_fixup,
854e1743d02SSøren Schmidt 	linux_sendsig,
855e1743d02SSøren Schmidt 	linux_sigcode,
856e1743d02SSøren Schmidt 	&linux_szsigcode,
857e1743d02SSøren Schmidt 	linux_prepsyscall,
85822d4b0fbSJohn Polstra 	"Linux ELF",
8593ebc1248SPeter Wemm 	elf32_coredump,
860806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
861f36ba452SJake Burkholder 	LINUX_MINSIGSTKSZ,
862f36ba452SJake Burkholder 	PAGE_SIZE,
863f36ba452SJake Burkholder 	VM_MIN_ADDRESS,
864f36ba452SJake Burkholder 	VM_MAXUSER_ADDRESS,
865f36ba452SJake Burkholder 	USRSTACK,
866f36ba452SJake Burkholder 	PS_STRINGS,
867f36ba452SJake Burkholder 	VM_PROT_ALL,
868f36ba452SJake Burkholder 	exec_copyout_strings,
869f36ba452SJake Burkholder 	exec_setregs
870e1743d02SSøren Schmidt };
871e1743d02SSøren Schmidt 
872514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
873c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
8743ebc1248SPeter Wemm 					EM_386,
87521a3ee0eSDavid E. O'Brien 					"Linux",
876ea5a2b2eSSøren Schmidt 					"/compat/linux",
8775cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
878ea5a2b2eSSøren Schmidt 					&elf_linux_sysvec
8795cf588ebSPeter Wemm 				 };
8805cf588ebSPeter Wemm 
881514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
882c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
8833ebc1248SPeter Wemm 					EM_386,
88421a3ee0eSDavid E. O'Brien 					"Linux",
8854e138a28SMike Smith 					"/compat/linux",
8864e138a28SMike Smith 					"/lib/ld-linux.so.2",
8874e138a28SMike Smith 					&elf_linux_sysvec
8884e138a28SMike Smith 				 };
8894e138a28SMike Smith 
890514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
891514058dcSAlexander Langer 					&linux_brand,
892514058dcSAlexander Langer 					&linux_glibc2brand,
893514058dcSAlexander Langer 					NULL
894514058dcSAlexander Langer 				};
895514058dcSAlexander Langer 
896aa855a59SPeter Wemm static int
897c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
898d30ea4f5SPeter Wemm {
899514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
900514058dcSAlexander Langer 	int error;
901f41325dbSPeter Wemm 	struct linux_ioctl_handler **lihp;
902514058dcSAlexander Langer 
903514058dcSAlexander Langer 	error = 0;
904514058dcSAlexander Langer 
905aa855a59SPeter Wemm 	switch(type) {
906aa855a59SPeter Wemm 	case MOD_LOAD:
907aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
908aa855a59SPeter Wemm 		     ++brandinfo)
9093ebc1248SPeter Wemm 			if (elf32_insert_brand_entry(*brandinfo) < 0)
910aa855a59SPeter Wemm 				error = EINVAL;
911466b14d7SMarcel Moolenaar 		if (error == 0) {
912f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
913f41325dbSPeter Wemm 				linux_ioctl_register_handler(*lihp);
91443bef515SMarcel Moolenaar 			if (bootverbose)
915466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler installed\n");
916466b14d7SMarcel Moolenaar 		} else
917466b14d7SMarcel Moolenaar 			printf("cannot insert Linux ELF brand handler\n");
918aa855a59SPeter Wemm 		break;
919aa855a59SPeter Wemm 	case MOD_UNLOAD:
920aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
921aa855a59SPeter Wemm 		     ++brandinfo)
9223ebc1248SPeter Wemm 			if (elf32_brand_inuse(*brandinfo))
923d2758342SMark Newton 				error = EBUSY;
924d2758342SMark Newton 		if (error == 0) {
925d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
926d2758342SMark Newton 			     *brandinfo != NULL; ++brandinfo)
9273ebc1248SPeter Wemm 				if (elf32_remove_brand_entry(*brandinfo) < 0)
928aa855a59SPeter Wemm 					error = EINVAL;
929d2758342SMark Newton 		}
930466b14d7SMarcel Moolenaar 		if (error == 0) {
931f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
932f41325dbSPeter Wemm 				linux_ioctl_unregister_handler(*lihp);
933466b14d7SMarcel Moolenaar 			if (bootverbose)
934466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler removed\n");
935466b14d7SMarcel Moolenaar 		} else
936aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
937aa855a59SPeter Wemm 		break;
938aa855a59SPeter Wemm 	default:
939aa855a59SPeter Wemm 		break;
940d30ea4f5SPeter Wemm 	}
941aa855a59SPeter Wemm 	return error;
942aa855a59SPeter Wemm }
943466b14d7SMarcel Moolenaar 
944aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
945aa855a59SPeter Wemm 	"linuxelf",
946aa855a59SPeter Wemm 	linux_elf_modevent,
947aa855a59SPeter Wemm 	0
948aa855a59SPeter Wemm };
949466b14d7SMarcel Moolenaar 
950aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
951