xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision 079b7badea4419a07a141547b7323f4c168f40fd)
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
15d66a5066SPeter Wemm  *    derived from this software withough 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"
335591b823SEivind Eklund 
345591b823SEivind Eklund #ifndef COMPAT_43
355591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
365591b823SEivind Eklund #endif
37d66a5066SPeter Wemm 
38d66a5066SPeter Wemm #include <sys/param.h>
3975f83872SPeter Wemm #include <sys/systm.h>
40d66a5066SPeter Wemm #include <sys/imgact.h>
4122d4b0fbSJohn Polstra #include <sys/imgact_aout.h>
42e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
437106ca0dSJohn Baldwin #include <sys/lock.h>
44e1743d02SSøren Schmidt #include <sys/malloc.h>
4523955314SAlfred Perlstein #include <sys/mutex.h>
46fb919e4dSMark Murray #include <sys/proc.h>
47fb919e4dSMark Murray #include <sys/signalvar.h>
48fb919e4dSMark Murray #include <sys/sysent.h>
49fb919e4dSMark Murray #include <sys/sysproto.h>
50fb919e4dSMark Murray 
51d66a5066SPeter Wemm #include <vm/vm.h>
52d66a5066SPeter Wemm #include <vm/vm_param.h>
53d66a5066SPeter Wemm #include <vm/vm_page.h>
54d66a5066SPeter Wemm #include <vm/vm_extern.h>
55d66a5066SPeter Wemm #include <sys/exec.h>
565cf588ebSPeter Wemm #include <sys/kernel.h>
57aa855a59SPeter Wemm #include <sys/module.h>
58d66a5066SPeter Wemm #include <machine/cpu.h>
59fb919e4dSMark Murray #include <sys/mutex.h>
60d66a5066SPeter Wemm 
61d66a5066SPeter Wemm #include <i386/linux/linux.h>
62ebea8660SMarcel Moolenaar #include <i386/linux/linux_proto.h>
63b595ab37SAndrew Gallatin #include <compat/linux/linux_signal.h>
64322bfdc3SMarcel Moolenaar #include <compat/linux/linux_util.h>
65e1743d02SSøren Schmidt 
661d91482dSPeter Wemm MODULE_VERSION(linux, 1);
67158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
68158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
69158eb277SDag-Erling Smørgrav MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
701d91482dSPeter Wemm 
7143bef515SMarcel Moolenaar MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
7243bef515SMarcel Moolenaar 
73d323ddf3SMatthew Dillon #if BYTE_ORDER == LITTLE_ENDIAN
74d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2123 /* #! */
75d323ddf3SMatthew Dillon #else
76d323ddf3SMatthew Dillon #define SHELLMAGIC      0x2321
77d323ddf3SMatthew Dillon #endif
78d323ddf3SMatthew Dillon 
79e061a6caSMarcel Moolenaar /*
80e061a6caSMarcel Moolenaar  * Allow the sendsig functions to use the ldebug() facility
81e061a6caSMarcel Moolenaar  * even though they are not syscalls themselves. Map them
82e061a6caSMarcel Moolenaar  * to syscall 0. This is slightly less bogus than using
83e061a6caSMarcel Moolenaar  * ldebug(sigreturn).
84e061a6caSMarcel Moolenaar  */
85e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_rt_sendsig	0
86e061a6caSMarcel Moolenaar #define	LINUX_SYS_linux_sendsig		0
87e061a6caSMarcel Moolenaar 
8843bef515SMarcel Moolenaar extern char linux_sigcode[];
8943bef515SMarcel Moolenaar extern int linux_szsigcode;
9043bef515SMarcel Moolenaar 
9143bef515SMarcel Moolenaar extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
9243bef515SMarcel Moolenaar 
93f41325dbSPeter Wemm SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
9443bef515SMarcel Moolenaar 
95654f6be1SBruce Evans static int	linux_fixup __P((register_t **stack_base,
96303b270bSEivind Eklund 				 struct image_params *iparams));
97654f6be1SBruce Evans static int	elf_linux_fixup __P((register_t **stack_base,
98303b270bSEivind Eklund 				     struct image_params *iparams));
99303b270bSEivind Eklund static void	linux_prepsyscall __P((struct trapframe *tf, int *args,
100303b270bSEivind Eklund 				       u_int *code, caddr_t *params));
101956d3333SMarcel Moolenaar static void     linux_sendsig __P((sig_t catcher, int sig, sigset_t *mask,
102303b270bSEivind Eklund 				   u_long code));
103d66a5066SPeter Wemm 
104d66a5066SPeter Wemm /*
105d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
106d66a5066SPeter Wemm  */
10785f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
108d66a5066SPeter Wemm   	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
109d66a5066SPeter Wemm  	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
110d66a5066SPeter Wemm  	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
111d66a5066SPeter Wemm  	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
112d66a5066SPeter Wemm  	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
113d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
114d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
115d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
11685f118c8SDmitrij Tejblum   	-6, -6, -43, -42, -75, -6, -84
117d66a5066SPeter Wemm };
118d66a5066SPeter Wemm 
119956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
120956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
121956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
122956d3333SMarcel Moolenaar 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 0,
123956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
124956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
125956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
126956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
127956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
128d66a5066SPeter Wemm };
129d66a5066SPeter Wemm 
130956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
131956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
132956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
133956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
134956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
135956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
136956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
137956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
138956d3333SMarcel Moolenaar 	SIGIO, SIGURG, 0
139d66a5066SPeter Wemm };
140d66a5066SPeter Wemm 
14127a828fcSPierre Beyssac #define LINUX_T_UNKNOWN  255
14227a828fcSPierre Beyssac static int _bsd_to_linux_trapcode[] = {
14327a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 0 */
14427a828fcSPierre Beyssac 	6,			/* 1  T_PRIVINFLT */
14527a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 2 */
14627a828fcSPierre Beyssac 	3,			/* 3  T_BPTFLT */
14727a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 4 */
14827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 5 */
14927a828fcSPierre Beyssac 	16,			/* 6  T_ARITHTRAP */
15027a828fcSPierre Beyssac 	254,			/* 7  T_ASTFLT */
15127a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 8 */
15227a828fcSPierre Beyssac 	13,			/* 9  T_PROTFLT */
15327a828fcSPierre Beyssac 	1,			/* 10 T_TRCTRAP */
15427a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 11 */
15527a828fcSPierre Beyssac 	14,			/* 12 T_PAGEFLT */
15627a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 13 */
15727a828fcSPierre Beyssac 	17,			/* 14 T_ALIGNFLT */
15827a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 15 */
15927a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 16 */
16027a828fcSPierre Beyssac 	LINUX_T_UNKNOWN,	/* 17 */
16127a828fcSPierre Beyssac 	0,			/* 18 T_DIVIDE */
16227a828fcSPierre Beyssac 	2,			/* 19 T_NMI */
16327a828fcSPierre Beyssac 	4,			/* 20 T_OFLOW */
16427a828fcSPierre Beyssac 	5,			/* 21 T_BOUND */
16527a828fcSPierre Beyssac 	7,			/* 22 T_DNA */
16627a828fcSPierre Beyssac 	8,			/* 23 T_DOUBLEFLT */
16727a828fcSPierre Beyssac 	9,			/* 24 T_FPOPFLT */
16827a828fcSPierre Beyssac 	10,			/* 25 T_TSSFLT */
16927a828fcSPierre Beyssac 	11,			/* 26 T_SEGNPFLT */
17027a828fcSPierre Beyssac 	12,			/* 27 T_STKFLT */
17127a828fcSPierre Beyssac 	18,			/* 28 T_MCHK */
17227a828fcSPierre Beyssac 	19,			/* 29 T_XMMFLT */
17327a828fcSPierre Beyssac 	15			/* 30 T_RESERVED */
17427a828fcSPierre Beyssac };
17527a828fcSPierre Beyssac #define bsd_to_linux_trapcode(code) \
17627a828fcSPierre Beyssac     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
17727a828fcSPierre Beyssac      _bsd_to_linux_trapcode[(code)]: \
17827a828fcSPierre Beyssac      LINUX_T_UNKNOWN)
17927a828fcSPierre Beyssac 
180288078beSEivind Eklund /*
181288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
182288078beSEivind Eklund  * means, deal with it here.
183356861dbSMatthew Dillon  *
184356861dbSMatthew Dillon  * MPSAFE
185288078beSEivind Eklund  */
186288078beSEivind Eklund static int
187288078beSEivind Eklund translate_traps(int signal, int trap_code)
188288078beSEivind Eklund {
189d563a53aSEivind Eklund 	if (signal != SIGBUS)
190d563a53aSEivind Eklund 		return signal;
191288078beSEivind Eklund 	switch (trap_code) {
192288078beSEivind Eklund 	case T_PROTFLT:
193288078beSEivind Eklund 	case T_TSSFLT:
194288078beSEivind Eklund 	case T_DOUBLEFLT:
195288078beSEivind Eklund 	case T_PAGEFLT:
196288078beSEivind Eklund 		return SIGSEGV;
197288078beSEivind Eklund 	default:
198288078beSEivind Eklund 		return signal;
199288078beSEivind Eklund 	}
200288078beSEivind Eklund }
201288078beSEivind Eklund 
202303b270bSEivind Eklund static int
203654f6be1SBruce Evans linux_fixup(register_t **stack_base, struct image_params *imgp)
204d66a5066SPeter Wemm {
205654f6be1SBruce Evans 	register_t *argv, *envp;
206d66a5066SPeter Wemm 
207d66a5066SPeter Wemm 	argv = *stack_base;
208d66a5066SPeter Wemm 	envp = *stack_base + (imgp->argc + 1);
209d66a5066SPeter Wemm 	(*stack_base)--;
21086a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
211d66a5066SPeter Wemm 	(*stack_base)--;
21286a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
213d66a5066SPeter Wemm 	(*stack_base)--;
21486a14a7aSBruce Evans 	**stack_base = imgp->argc;
215e1743d02SSøren Schmidt 	return 0;
216d66a5066SPeter Wemm }
217d66a5066SPeter Wemm 
218303b270bSEivind Eklund static int
219654f6be1SBruce Evans elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
220e1743d02SSøren Schmidt {
221e1743d02SSøren Schmidt 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
222654f6be1SBruce Evans 	register_t *pos;
223d66a5066SPeter Wemm 
224e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
225e1743d02SSøren Schmidt 
226e1743d02SSøren Schmidt 	if (args->trace) {
227e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
228e1743d02SSøren Schmidt 	}
229e1743d02SSøren Schmidt 	if (args->execfd != -1) {
230e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
231e1743d02SSøren Schmidt 	}
232e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
233e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
234e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
235e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
236e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
237e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
238e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
239611d9407SJohn Baldwin 	PROC_LOCK(imgp->proc);
240b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
241b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
242b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
243b1fc0ec1SRobert Watson 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
244611d9407SJohn Baldwin 	PROC_UNLOCK(imgp->proc);
245e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
246e1743d02SSøren Schmidt 
247e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
248e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
249e1743d02SSøren Schmidt 
250e1743d02SSøren Schmidt 	(*stack_base)--;
251ecbb00a2SDoug Rabson 	**stack_base = (long)imgp->argc;
252e1743d02SSøren Schmidt 	return 0;
253e1743d02SSøren Schmidt }
254d66a5066SPeter Wemm 
255d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
25602318dacSJake Burkholder extern unsigned long linux_sznonrtsigcode;
25779363394SAndrew Gallatin 
25879363394SAndrew Gallatin static void
25979363394SAndrew Gallatin linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
26079363394SAndrew Gallatin {
261b40ce416SJulian Elischer 	register struct thread *td = curthread;
262b40ce416SJulian Elischer 	register struct proc *p = td->td_proc;
26379363394SAndrew Gallatin 	register struct trapframe *regs;
2645002a60fSMarcel Moolenaar 	struct l_rt_sigframe *fp, frame;
26579363394SAndrew Gallatin 	int oonstack;
26679363394SAndrew Gallatin 
267df53e91cSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
268b40ce416SJulian Elischer 	regs = td->td_frame;
269d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
27079363394SAndrew Gallatin 
27179363394SAndrew Gallatin #ifdef DEBUG
2725002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
27324593369SJonathan Lemon 		printf(ARGS(rt_sendsig, "%p, %d, %p, %lu"),
27424593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
27579363394SAndrew Gallatin #endif
27679363394SAndrew Gallatin 	/*
27779363394SAndrew Gallatin 	 * Allocate space for the signal handler context.
27879363394SAndrew Gallatin 	 */
27979363394SAndrew Gallatin 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
280cc6ca9b3SMarcel Moolenaar 	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
2815002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)(p->p_sigstk.ss_sp +
2825002a60fSMarcel Moolenaar 		    p->p_sigstk.ss_size - sizeof(struct l_rt_sigframe));
283d034d459SMarcel Moolenaar 	} else
2845002a60fSMarcel Moolenaar 		fp = (struct l_rt_sigframe *)regs->tf_esp - 1;
285611d9407SJohn Baldwin 	PROC_UNLOCK(p);
28679363394SAndrew Gallatin 
28779363394SAndrew Gallatin 	/*
28879363394SAndrew Gallatin 	 * grow() will return FALSE if the fp will not fit inside the stack
28979363394SAndrew Gallatin 	 *	and the stack can not be grown. useracc will return FALSE
29079363394SAndrew Gallatin 	 *	if access is denied.
29179363394SAndrew Gallatin 	 */
29279363394SAndrew Gallatin 	if ((grow_stack (p, (int)fp) == FALSE) ||
2935002a60fSMarcel Moolenaar 	    !useracc((caddr_t)fp, sizeof (struct l_rt_sigframe),
29479363394SAndrew Gallatin 	    VM_PROT_WRITE)) {
29579363394SAndrew Gallatin 		/*
29679363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
29779363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
29879363394SAndrew Gallatin 		 */
299611d9407SJohn Baldwin 		PROC_LOCK(p);
30079363394SAndrew Gallatin 		SIGACTION(p, SIGILL) = SIG_DFL;
30179363394SAndrew Gallatin 		SIGDELSET(p->p_sigignore, SIGILL);
30279363394SAndrew Gallatin 		SIGDELSET(p->p_sigcatch, SIGILL);
30379363394SAndrew Gallatin 		SIGDELSET(p->p_sigmask, SIGILL);
30479363394SAndrew Gallatin #ifdef DEBUG
3055002a60fSMarcel Moolenaar 		if (ldebug(rt_sendsig))
30624593369SJonathan Lemon 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
30724593369SJonathan Lemon 			    fp, oonstack);
30879363394SAndrew Gallatin #endif
30979363394SAndrew Gallatin 		psignal(p, SIGILL);
31079363394SAndrew Gallatin 		return;
31179363394SAndrew Gallatin 	}
31279363394SAndrew Gallatin 
31379363394SAndrew Gallatin 	/*
31479363394SAndrew Gallatin 	 * Build the argument list for the signal handler.
31579363394SAndrew Gallatin 	 */
31679363394SAndrew Gallatin 	if (p->p_sysent->sv_sigtbl)
31779363394SAndrew Gallatin 		if (sig <= p->p_sysent->sv_sigsize)
31879363394SAndrew Gallatin 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
31979363394SAndrew Gallatin 
32079363394SAndrew Gallatin 	frame.sf_handler = catcher;
32179363394SAndrew Gallatin 	frame.sf_sig = sig;
32279363394SAndrew Gallatin 	frame.sf_siginfo = &fp->sf_si;
32379363394SAndrew Gallatin 	frame.sf_ucontext = &fp->sf_sc;
324cc6ca9b3SMarcel Moolenaar 
32579363394SAndrew Gallatin 	/* Fill siginfo structure. */
32679363394SAndrew Gallatin 	frame.sf_si.lsi_signo = sig;
32779363394SAndrew Gallatin 	frame.sf_si.lsi_code = code;
32879363394SAndrew Gallatin 	frame.sf_si.lsi_addr = (void *)regs->tf_err;
329cc6ca9b3SMarcel Moolenaar 
33079363394SAndrew Gallatin 	/*
33179363394SAndrew Gallatin 	 * Build the signal context to be used by sigreturn.
33279363394SAndrew Gallatin 	 */
333cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
334cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_link = NULL;		/* XXX ??? */
335cc6ca9b3SMarcel Moolenaar 
336611d9407SJohn Baldwin 	PROC_LOCK(p);
337cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_sp = p->p_sigstk.ss_sp;
338cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_size = p->p_sigstk.ss_size;
339d034d459SMarcel Moolenaar 	frame.sf_sc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK)
340d034d459SMarcel Moolenaar 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
341611d9407SJohn Baldwin 	PROC_UNLOCK(p);
342cc6ca9b3SMarcel Moolenaar 
343cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
344cc6ca9b3SMarcel Moolenaar 
345cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
34679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_gs     = rgs();
34779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_fs     = regs->tf_fs;
34879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_es     = regs->tf_es;
34979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ds     = regs->tf_ds;
35079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_edi;
35179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_esi;
35279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_ebp;
35379363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_ebx;
35479363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_edx;
35579363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_ecx;
35679363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_eax;
35779363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_eip;
35879363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
35979363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_eflags;
36079363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_esp;
36179363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
36279363394SAndrew Gallatin 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
36327a828fcSPierre Beyssac 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
36479363394SAndrew Gallatin 
36579363394SAndrew Gallatin #ifdef DEBUG
3665002a60fSMarcel Moolenaar 	if (ldebug(rt_sendsig))
36724593369SJonathan Lemon 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
36824593369SJonathan Lemon 		    frame.sf_sc.uc_stack.ss_flags, p->p_sigstk.ss_sp,
36924593369SJonathan Lemon 		    p->p_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
37079363394SAndrew Gallatin #endif
37179363394SAndrew Gallatin 
37279363394SAndrew Gallatin 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
37379363394SAndrew Gallatin 		/*
37479363394SAndrew Gallatin 		 * Process has trashed its stack; give it an illegal
37579363394SAndrew Gallatin 		 * instruction to halt it in its tracks.
37679363394SAndrew Gallatin 		 */
37719eb87d2SJohn Baldwin 		PROC_LOCK(p);
378b40ce416SJulian Elischer 		sigexit(td, SIGILL);
37979363394SAndrew Gallatin 		/* NOTREACHED */
38079363394SAndrew Gallatin 	}
38179363394SAndrew Gallatin 
38279363394SAndrew Gallatin 	/*
38379363394SAndrew Gallatin 	 * Build context to run handler in.
38479363394SAndrew Gallatin 	 */
38579363394SAndrew Gallatin 	regs->tf_esp = (int)fp;
38679363394SAndrew Gallatin 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode) +
38702318dacSJake Burkholder 	    linux_sznonrtsigcode;
388846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
38979363394SAndrew Gallatin 	regs->tf_cs = _ucodesel;
39079363394SAndrew Gallatin 	regs->tf_ds = _udatasel;
39179363394SAndrew Gallatin 	regs->tf_es = _udatasel;
39279363394SAndrew Gallatin 	regs->tf_fs = _udatasel;
39379363394SAndrew Gallatin 	regs->tf_ss = _udatasel;
394df53e91cSJohn Baldwin 	PROC_LOCK(p);
39579363394SAndrew Gallatin }
39679363394SAndrew Gallatin 
397d66a5066SPeter Wemm 
398d66a5066SPeter Wemm /*
399d66a5066SPeter Wemm  * Send an interrupt to process.
400d66a5066SPeter Wemm  *
401d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
402d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
403d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
404d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
405d66a5066SPeter Wemm  * frame pointer, it returns to the user
406d66a5066SPeter Wemm  * specified pc, psl.
407d66a5066SPeter Wemm  */
408d66a5066SPeter Wemm 
409303b270bSEivind Eklund static void
410956d3333SMarcel Moolenaar linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
411d66a5066SPeter Wemm {
412b40ce416SJulian Elischer 	register struct thread *td = curthread;
413b40ce416SJulian Elischer 	register struct proc *p = td->td_proc;
414213fdd80SPeter Wemm 	register struct trapframe *regs;
4155002a60fSMarcel Moolenaar 	struct l_sigframe *fp, frame;
4165002a60fSMarcel Moolenaar 	l_sigset_t lmask;
4172c4ab9ddSAndrew Gallatin 	int oonstack, i;
418d66a5066SPeter Wemm 
4192509e6c2SJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
420cc6ca9b3SMarcel Moolenaar 	if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) {
421cc6ca9b3SMarcel Moolenaar 		/* Signal handler installed with SA_SIGINFO. */
422cc6ca9b3SMarcel Moolenaar 		linux_rt_sendsig(catcher, sig, mask, code);
423cc6ca9b3SMarcel Moolenaar 		return;
424cc6ca9b3SMarcel Moolenaar 	}
425cc6ca9b3SMarcel Moolenaar 
426b40ce416SJulian Elischer 	regs = td->td_frame;
427d034d459SMarcel Moolenaar 	oonstack = sigonstack(regs->tf_esp);
428d66a5066SPeter Wemm 
429d66a5066SPeter Wemm #ifdef DEBUG
4305002a60fSMarcel Moolenaar 	if (ldebug(sendsig))
43124593369SJonathan Lemon 		printf(ARGS(sendsig, "%p, %d, %p, %lu"),
43224593369SJonathan Lemon 		    catcher, sig, (void*)mask, code);
433d66a5066SPeter Wemm #endif
43479363394SAndrew Gallatin 
435d66a5066SPeter Wemm 	/*
436d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
437d66a5066SPeter Wemm 	 */
438645682fdSLuoqi Chen 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
439cc6ca9b3SMarcel Moolenaar 	    SIGISMEMBER(p->p_sigacts->ps_sigonstack, sig)) {
4405002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)(p->p_sigstk.ss_sp +
4415002a60fSMarcel Moolenaar 		    p->p_sigstk.ss_size - sizeof(struct l_sigframe));
442d034d459SMarcel Moolenaar 	} else
4435002a60fSMarcel Moolenaar 		fp = (struct l_sigframe *)regs->tf_esp - 1;
444611d9407SJohn Baldwin 	PROC_UNLOCK(p);
445d66a5066SPeter Wemm 
446d66a5066SPeter Wemm 	/*
447d66a5066SPeter Wemm 	 * grow() will return FALSE if the fp will not fit inside the stack
448d66a5066SPeter Wemm 	 *	and the stack can not be grown. useracc will return FALSE
449d66a5066SPeter Wemm 	 *	if access is denied.
450d66a5066SPeter Wemm 	 */
4516626c604SJulian Elischer 	if ((grow_stack (p, (int)fp) == FALSE) ||
4525002a60fSMarcel Moolenaar 	    !useracc((caddr_t)fp, sizeof (struct l_sigframe),
45302c58685SPoul-Henning Kamp 	    VM_PROT_WRITE)) {
454d66a5066SPeter Wemm 		/*
455d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
456d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
457d66a5066SPeter Wemm 		 */
458611d9407SJohn Baldwin 		PROC_LOCK(p);
459d66a5066SPeter Wemm 		SIGACTION(p, SIGILL) = SIG_DFL;
460956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigignore, SIGILL);
461956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigcatch, SIGILL);
462956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigmask, SIGILL);
463d66a5066SPeter Wemm 		psignal(p, SIGILL);
464d66a5066SPeter Wemm 		return;
465d66a5066SPeter Wemm 	}
466d66a5066SPeter Wemm 
467d66a5066SPeter Wemm 	/*
468d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
469d66a5066SPeter Wemm 	 */
470956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
471956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
472956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
473d66a5066SPeter Wemm 
474d66a5066SPeter Wemm 	frame.sf_handler = catcher;
475d66a5066SPeter Wemm 	frame.sf_sig = sig;
476d66a5066SPeter Wemm 
477cc6ca9b3SMarcel Moolenaar 	bsd_to_linux_sigset(mask, &lmask);
478cc6ca9b3SMarcel Moolenaar 
479d66a5066SPeter Wemm 	/*
480d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
481d66a5066SPeter Wemm 	 */
482cc6ca9b3SMarcel Moolenaar 	frame.sf_sc.sc_mask   = lmask.__bits[0];
4835206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
4845206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
485213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
486213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
487213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
488213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
489213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
490213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
491213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
492213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
493213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
494213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
495213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
496213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
497213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
498213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
499213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
50027a828fcSPierre Beyssac 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code);
501cc6ca9b3SMarcel Moolenaar 
5025002a60fSMarcel Moolenaar 	bzero(&frame.sf_fpstate, sizeof(struct l_fpstate));
503cc6ca9b3SMarcel Moolenaar 
5042c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
505cc6ca9b3SMarcel Moolenaar 		frame.sf_extramask[i] = lmask.__bits[i+1];
506d66a5066SPeter Wemm 
507d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
508d66a5066SPeter Wemm 		/*
509d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
510d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
511d66a5066SPeter Wemm 		 */
51219eb87d2SJohn Baldwin 		PROC_LOCK(p);
513b40ce416SJulian Elischer 		sigexit(td, SIGILL);
514d66a5066SPeter Wemm 		/* NOTREACHED */
515d66a5066SPeter Wemm 	}
516d66a5066SPeter Wemm 
517d66a5066SPeter Wemm 	/*
518d66a5066SPeter Wemm 	 * Build context to run handler in.
519d66a5066SPeter Wemm 	 */
520213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
5214c56fcdeSBruce Evans 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
522846ac226SBruce Evans 	regs->tf_eflags &= ~(PSL_T | PSL_VM);
523213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
524213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
525213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
5265206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
527213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
5285002a60fSMarcel Moolenaar 	PROC_LOCK(p);
529d66a5066SPeter Wemm }
530d66a5066SPeter Wemm 
531d66a5066SPeter Wemm /*
532d66a5066SPeter Wemm  * System call to cleanup state after a signal
533d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
534d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
535d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
536d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
537d66a5066SPeter Wemm  * make sure that the user has not modified the
538d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
539d66a5066SPeter Wemm  * a machine fault.
540d66a5066SPeter Wemm  */
541d66a5066SPeter Wemm int
542b40ce416SJulian Elischer linux_sigreturn(td, args)
543b40ce416SJulian Elischer 	struct thread *td;
544d66a5066SPeter Wemm 	struct linux_sigreturn_args *args;
545d66a5066SPeter Wemm {
546b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
5475002a60fSMarcel Moolenaar 	struct l_sigframe frame;
548213fdd80SPeter Wemm 	register struct trapframe *regs;
5495002a60fSMarcel Moolenaar 	l_sigset_t lmask;
5502c4ab9ddSAndrew Gallatin 	int eflags, i;
551d66a5066SPeter Wemm 
552b40ce416SJulian Elischer 	regs = td->td_frame;
553d66a5066SPeter Wemm 
554d66a5066SPeter Wemm #ifdef DEBUG
55524593369SJonathan Lemon 	if (ldebug(sigreturn))
55624593369SJonathan Lemon 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
557d66a5066SPeter Wemm #endif
558d66a5066SPeter Wemm 	/*
559cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the sigframe.
560d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
561d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
562d66a5066SPeter Wemm 	 */
563cc6ca9b3SMarcel Moolenaar 	if (copyin((caddr_t)args->sfp, &frame, sizeof(frame)) != 0)
564d66a5066SPeter Wemm 		return (EFAULT);
565d66a5066SPeter Wemm 
566d66a5066SPeter Wemm 	/*
567d66a5066SPeter Wemm 	 * Check for security violations.
568d66a5066SPeter Wemm 	 */
569d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
570cc6ca9b3SMarcel Moolenaar 	eflags = frame.sf_sc.sc_eflags;
571d66a5066SPeter Wemm 	/*
572d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
573d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
574d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
575d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
576d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
577d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
578d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
579d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
580d66a5066SPeter Wemm 	 */
581213fdd80SPeter Wemm 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
582d66a5066SPeter Wemm     		return(EINVAL);
583d66a5066SPeter Wemm 	}
584d66a5066SPeter Wemm 
585d66a5066SPeter Wemm 	/*
586d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
587d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
588d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
589d66a5066SPeter Wemm 	 */
59040d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
591cc6ca9b3SMarcel Moolenaar 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
592d66a5066SPeter Wemm 		trapsignal(p, SIGBUS, T_PROTFLT);
593d66a5066SPeter Wemm 		return(EINVAL);
594d66a5066SPeter Wemm 	}
595d66a5066SPeter Wemm 
596cc6ca9b3SMarcel Moolenaar 	lmask.__bits[0] = frame.sf_sc.sc_mask;
5972c4ab9ddSAndrew Gallatin 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
598cc6ca9b3SMarcel Moolenaar 		lmask.__bits[i+1] = frame.sf_extramask[i];
599611d9407SJohn Baldwin 	PROC_LOCK(p);
600cc6ca9b3SMarcel Moolenaar 	linux_to_bsd_sigset(&lmask, &p->p_sigmask);
601645682fdSLuoqi Chen 	SIG_CANTMASK(p->p_sigmask);
602611d9407SJohn Baldwin 	PROC_UNLOCK(p);
603956d3333SMarcel Moolenaar 
604d66a5066SPeter Wemm 	/*
605d66a5066SPeter Wemm 	 * Restore signal context.
606d66a5066SPeter Wemm 	 */
6075206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
608cc6ca9b3SMarcel Moolenaar 	regs->tf_fs     = frame.sf_sc.sc_fs;
609cc6ca9b3SMarcel Moolenaar 	regs->tf_es     = frame.sf_sc.sc_es;
610cc6ca9b3SMarcel Moolenaar 	regs->tf_ds     = frame.sf_sc.sc_ds;
611cc6ca9b3SMarcel Moolenaar 	regs->tf_edi    = frame.sf_sc.sc_edi;
612cc6ca9b3SMarcel Moolenaar 	regs->tf_esi    = frame.sf_sc.sc_esi;
613cc6ca9b3SMarcel Moolenaar 	regs->tf_ebp    = frame.sf_sc.sc_ebp;
614cc6ca9b3SMarcel Moolenaar 	regs->tf_ebx    = frame.sf_sc.sc_ebx;
615cc6ca9b3SMarcel Moolenaar 	regs->tf_edx    = frame.sf_sc.sc_edx;
616cc6ca9b3SMarcel Moolenaar 	regs->tf_ecx    = frame.sf_sc.sc_ecx;
617cc6ca9b3SMarcel Moolenaar 	regs->tf_eax    = frame.sf_sc.sc_eax;
618cc6ca9b3SMarcel Moolenaar 	regs->tf_eip    = frame.sf_sc.sc_eip;
619cc6ca9b3SMarcel Moolenaar 	regs->tf_cs     = frame.sf_sc.sc_cs;
620213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
621cc6ca9b3SMarcel Moolenaar 	regs->tf_esp    = frame.sf_sc.sc_esp_at_signal;
622cc6ca9b3SMarcel Moolenaar 	regs->tf_ss     = frame.sf_sc.sc_ss;
623d66a5066SPeter Wemm 
624d66a5066SPeter Wemm 	return (EJUSTRETURN);
625d66a5066SPeter Wemm }
626d66a5066SPeter Wemm 
62779363394SAndrew Gallatin /*
62879363394SAndrew Gallatin  * System call to cleanup state after a signal
62979363394SAndrew Gallatin  * has been taken.  Reset signal mask and
63079363394SAndrew Gallatin  * stack state from context left by rt_sendsig (above).
63179363394SAndrew Gallatin  * Return to previous pc and psl as specified by
63279363394SAndrew Gallatin  * context left by sendsig. Check carefully to
63379363394SAndrew Gallatin  * make sure that the user has not modified the
63479363394SAndrew Gallatin  * psl to gain improper privileges or to cause
63579363394SAndrew Gallatin  * a machine fault.
63679363394SAndrew Gallatin  */
63779363394SAndrew Gallatin int
638b40ce416SJulian Elischer linux_rt_sigreturn(td, args)
639b40ce416SJulian Elischer 	struct thread *td;
64079363394SAndrew Gallatin 	struct linux_rt_sigreturn_args *args;
64179363394SAndrew Gallatin {
642b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
64379363394SAndrew Gallatin 	struct sigaltstack_args sasargs;
6445002a60fSMarcel Moolenaar 	struct l_ucontext uc;
6455002a60fSMarcel Moolenaar 	struct l_sigcontext *context;
6465002a60fSMarcel Moolenaar 	l_stack_t *lss;
64779363394SAndrew Gallatin 	stack_t *ss;
64879363394SAndrew Gallatin 	register struct trapframe *regs;
64979363394SAndrew Gallatin 	int eflags;
65079363394SAndrew Gallatin 	caddr_t sg = stackgap_init();
65179363394SAndrew Gallatin 
652b40ce416SJulian Elischer 	regs = td->td_frame;
65379363394SAndrew Gallatin 
65479363394SAndrew Gallatin #ifdef DEBUG
65524593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
65624593369SJonathan Lemon 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
65779363394SAndrew Gallatin #endif
65879363394SAndrew Gallatin 	/*
659cc6ca9b3SMarcel Moolenaar 	 * The trampoline code hands us the ucontext.
66079363394SAndrew Gallatin 	 * It is unsafe to keep track of it ourselves, in the event that a
66179363394SAndrew Gallatin 	 * program jumps out of a signal handler.
66279363394SAndrew Gallatin 	 */
66379363394SAndrew Gallatin 	if (copyin((caddr_t)args->ucp, &uc, sizeof(uc)) != 0)
66479363394SAndrew Gallatin 		return (EFAULT);
66579363394SAndrew Gallatin 
66679363394SAndrew Gallatin 	context = &uc.uc_mcontext;
66779363394SAndrew Gallatin 
66879363394SAndrew Gallatin 	/*
66979363394SAndrew Gallatin 	 * Check for security violations.
67079363394SAndrew Gallatin 	 */
67179363394SAndrew Gallatin #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
67279363394SAndrew Gallatin 	eflags = context->sc_eflags;
67379363394SAndrew Gallatin 	/*
67479363394SAndrew Gallatin 	 * XXX do allow users to change the privileged flag PSL_RF.  The
67579363394SAndrew Gallatin 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
67679363394SAndrew Gallatin 	 * sometimes set it there too.  tf_eflags is kept in the signal
67779363394SAndrew Gallatin 	 * context during signal handling and there is no other place
67879363394SAndrew Gallatin 	 * to remember it, so the PSL_RF bit may be corrupted by the
67979363394SAndrew Gallatin 	 * signal handler without us knowing.  Corruption of the PSL_RF
68079363394SAndrew Gallatin 	 * bit at worst causes one more or one less debugger trap, so
68179363394SAndrew Gallatin 	 * allowing it is fairly harmless.
68279363394SAndrew Gallatin 	 */
68379363394SAndrew Gallatin 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
68479363394SAndrew Gallatin     		return(EINVAL);
68579363394SAndrew Gallatin 	}
68679363394SAndrew Gallatin 
68779363394SAndrew Gallatin 	/*
68879363394SAndrew Gallatin 	 * Don't allow users to load a valid privileged %cs.  Let the
68979363394SAndrew Gallatin 	 * hardware check for invalid selectors, excess privilege in
69079363394SAndrew Gallatin 	 * other selectors, invalid %eip's and invalid %esp's.
69179363394SAndrew Gallatin 	 */
69279363394SAndrew Gallatin #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
69379363394SAndrew Gallatin 	if (!CS_SECURE(context->sc_cs)) {
69479363394SAndrew Gallatin 		trapsignal(p, SIGBUS, T_PROTFLT);
69579363394SAndrew Gallatin 		return(EINVAL);
69679363394SAndrew Gallatin 	}
69779363394SAndrew Gallatin 
698611d9407SJohn Baldwin 	PROC_LOCK(p);
699b595ab37SAndrew Gallatin 	linux_to_bsd_sigset(&uc.uc_sigmask, &p->p_sigmask);
70079363394SAndrew Gallatin 	SIG_CANTMASK(p->p_sigmask);
701611d9407SJohn Baldwin 	PROC_UNLOCK(p);
70279363394SAndrew Gallatin 
70379363394SAndrew Gallatin 	/*
704cc6ca9b3SMarcel Moolenaar 	 * Restore signal context
70579363394SAndrew Gallatin 	 */
70679363394SAndrew Gallatin 	/* %gs was restored by the trampoline. */
70779363394SAndrew Gallatin 	regs->tf_fs     = context->sc_fs;
70879363394SAndrew Gallatin 	regs->tf_es     = context->sc_es;
70979363394SAndrew Gallatin 	regs->tf_ds     = context->sc_ds;
71079363394SAndrew Gallatin 	regs->tf_edi    = context->sc_edi;
71179363394SAndrew Gallatin 	regs->tf_esi    = context->sc_esi;
71279363394SAndrew Gallatin 	regs->tf_ebp    = context->sc_ebp;
71379363394SAndrew Gallatin 	regs->tf_ebx    = context->sc_ebx;
71479363394SAndrew Gallatin 	regs->tf_edx    = context->sc_edx;
71579363394SAndrew Gallatin 	regs->tf_ecx    = context->sc_ecx;
71679363394SAndrew Gallatin 	regs->tf_eax    = context->sc_eax;
71779363394SAndrew Gallatin 	regs->tf_eip    = context->sc_eip;
71879363394SAndrew Gallatin 	regs->tf_cs     = context->sc_cs;
71979363394SAndrew Gallatin 	regs->tf_eflags = eflags;
72079363394SAndrew Gallatin 	regs->tf_esp    = context->sc_esp_at_signal;
72179363394SAndrew Gallatin 	regs->tf_ss     = context->sc_ss;
72279363394SAndrew Gallatin 
72379363394SAndrew Gallatin 	/*
72479363394SAndrew Gallatin 	 * call sigaltstack & ignore results..
72579363394SAndrew Gallatin 	 */
72679363394SAndrew Gallatin 	ss = stackgap_alloc(&sg, sizeof(stack_t));
72779363394SAndrew Gallatin 	lss = &uc.uc_stack;
72879363394SAndrew Gallatin 	ss->ss_sp = lss->ss_sp;
729806d7daaSMarcel Moolenaar 	ss->ss_size = lss->ss_size;
73079363394SAndrew Gallatin 	ss->ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
73179363394SAndrew Gallatin 
73279363394SAndrew Gallatin #ifdef DEBUG
73324593369SJonathan Lemon 	if (ldebug(rt_sigreturn))
73424593369SJonathan Lemon 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
73524593369SJonathan Lemon 		    ss->ss_flags, ss->ss_sp, ss->ss_size, context->sc_mask);
73679363394SAndrew Gallatin #endif
73779363394SAndrew Gallatin 	sasargs.ss = ss;
73879363394SAndrew Gallatin 	sasargs.oss = NULL;
739b40ce416SJulian Elischer 	(void) sigaltstack(td, &sasargs);
74079363394SAndrew Gallatin 
74179363394SAndrew Gallatin 	return (EJUSTRETURN);
74279363394SAndrew Gallatin }
74379363394SAndrew Gallatin 
744356861dbSMatthew Dillon /*
745356861dbSMatthew Dillon  * MPSAFE
746356861dbSMatthew Dillon  */
747303b270bSEivind Eklund static void
748d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
749d66a5066SPeter Wemm {
750d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
751d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
752d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
753d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
754d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
755d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
756d66a5066SPeter Wemm }
757d66a5066SPeter Wemm 
758d323ddf3SMatthew Dillon /*
759d323ddf3SMatthew Dillon  * If a linux binary is exec'ing something, try this image activator
760d323ddf3SMatthew Dillon  * first.  We override standard shell script execution in order to
761d323ddf3SMatthew Dillon  * be able to modify the interpreter path.  We only do this if a linux
762d323ddf3SMatthew Dillon  * binary is doing the exec, so we do not create an EXEC module for it.
763d323ddf3SMatthew Dillon  */
764d323ddf3SMatthew Dillon static int	exec_linux_imgact_try __P((struct image_params *iparams));
765d323ddf3SMatthew Dillon 
766d323ddf3SMatthew Dillon static int
767d323ddf3SMatthew Dillon exec_linux_imgact_try(imgp)
768d323ddf3SMatthew Dillon     struct image_params *imgp;
769d323ddf3SMatthew Dillon {
770d323ddf3SMatthew Dillon     const char *head = (const char *)imgp->image_header;
771d323ddf3SMatthew Dillon     int error = -1;
772d323ddf3SMatthew Dillon 
773d323ddf3SMatthew Dillon     /*
774d323ddf3SMatthew Dillon      * The interpreter for shell scripts run from a linux binary needs
775d323ddf3SMatthew Dillon      * to be located in /compat/linux if possible in order to recursively
776d323ddf3SMatthew Dillon      * maintain linux path emulation.
777d323ddf3SMatthew Dillon      */
778d323ddf3SMatthew Dillon     if (((const short *)head)[0] == SHELLMAGIC) {
779d323ddf3SMatthew Dillon 	    /*
780d323ddf3SMatthew Dillon 	     * Run our normal shell image activator.  If it succeeds attempt
781d323ddf3SMatthew Dillon 	     * to use the alternate path for the interpreter.  If an alternate
782d323ddf3SMatthew Dillon 	     * path is found, use our stringspace to store it.
783d323ddf3SMatthew Dillon 	     */
784d323ddf3SMatthew Dillon 	    if ((error = exec_shell_imgact(imgp)) == 0) {
785d323ddf3SMatthew Dillon 		    char *rpath = NULL;
786d323ddf3SMatthew Dillon 
787079b7badSJulian Elischer 		    linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL,
788d323ddf3SMatthew Dillon 			imgp->interpreter_name, &rpath, 0);
789d323ddf3SMatthew Dillon 		    if (rpath != imgp->interpreter_name) {
790d323ddf3SMatthew Dillon 			    int len = strlen(rpath) + 1;
791d323ddf3SMatthew Dillon 
792d323ddf3SMatthew Dillon 			    if (len <= MAXSHELLCMDLEN) {
793d323ddf3SMatthew Dillon 				    memcpy(imgp->interpreter_name, rpath, len);
794d323ddf3SMatthew Dillon 			    }
795d323ddf3SMatthew Dillon 			    free(rpath, M_TEMP);
796d323ddf3SMatthew Dillon 		    }
797d323ddf3SMatthew Dillon 	    }
798d323ddf3SMatthew Dillon     }
799d323ddf3SMatthew Dillon     return(error);
800d323ddf3SMatthew Dillon }
801d323ddf3SMatthew Dillon 
802d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
803e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
804d66a5066SPeter Wemm 	linux_sysent,
805d66a5066SPeter Wemm 	0xff,
806956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
807d66a5066SPeter Wemm 	bsd_to_linux_signal,
80885f118c8SDmitrij Tejblum 	ELAST + 1,
809d66a5066SPeter Wemm 	bsd_to_linux_errno,
810288078beSEivind Eklund 	translate_traps,
811d66a5066SPeter Wemm 	linux_fixup,
812d66a5066SPeter Wemm 	linux_sendsig,
813d66a5066SPeter Wemm 	linux_sigcode,
814d66a5066SPeter Wemm 	&linux_szsigcode,
815d66a5066SPeter Wemm 	linux_prepsyscall,
81622d4b0fbSJohn Polstra 	"Linux a.out",
817d323ddf3SMatthew Dillon 	aout_coredump,
818806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
819806d7daaSMarcel Moolenaar 	LINUX_MINSIGSTKSZ
820d66a5066SPeter Wemm };
821e1743d02SSøren Schmidt 
822e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
823e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
824e1743d02SSøren Schmidt 	linux_sysent,
825e1743d02SSøren Schmidt 	0xff,
826956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
827e1743d02SSøren Schmidt 	bsd_to_linux_signal,
82885f118c8SDmitrij Tejblum 	ELAST + 1,
829e1743d02SSøren Schmidt 	bsd_to_linux_errno,
830288078beSEivind Eklund 	translate_traps,
831e1743d02SSøren Schmidt 	elf_linux_fixup,
832e1743d02SSøren Schmidt 	linux_sendsig,
833e1743d02SSøren Schmidt 	linux_sigcode,
834e1743d02SSøren Schmidt 	&linux_szsigcode,
835e1743d02SSøren Schmidt 	linux_prepsyscall,
83622d4b0fbSJohn Polstra 	"Linux ELF",
837d323ddf3SMatthew Dillon 	elf_coredump,
838806d7daaSMarcel Moolenaar 	exec_linux_imgact_try,
839806d7daaSMarcel Moolenaar 	LINUX_MINSIGSTKSZ
840e1743d02SSøren Schmidt };
841e1743d02SSøren Schmidt 
842514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
843c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
84421a3ee0eSDavid E. O'Brien 					"Linux",
845ea5a2b2eSSøren Schmidt 					"/compat/linux",
8465cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
847ea5a2b2eSSøren Schmidt 					&elf_linux_sysvec
8485cf588ebSPeter Wemm 				 };
8495cf588ebSPeter Wemm 
850514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
851c815a20cSDavid E. O'Brien 					ELFOSABI_LINUX,
85221a3ee0eSDavid E. O'Brien 					"Linux",
8534e138a28SMike Smith 					"/compat/linux",
8544e138a28SMike Smith 					"/lib/ld-linux.so.2",
8554e138a28SMike Smith 					&elf_linux_sysvec
8564e138a28SMike Smith 				 };
8574e138a28SMike Smith 
858514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
859514058dcSAlexander Langer 					&linux_brand,
860514058dcSAlexander Langer 					&linux_glibc2brand,
861514058dcSAlexander Langer 					NULL
862514058dcSAlexander Langer 				};
863514058dcSAlexander Langer 
864aa855a59SPeter Wemm static int
865c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
866d30ea4f5SPeter Wemm {
867514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
868514058dcSAlexander Langer 	int error;
869f41325dbSPeter Wemm 	struct linux_ioctl_handler **lihp;
870514058dcSAlexander Langer 
871514058dcSAlexander Langer 	error = 0;
872514058dcSAlexander Langer 
873aa855a59SPeter Wemm 	switch(type) {
874aa855a59SPeter Wemm 	case MOD_LOAD:
875aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
876aa855a59SPeter Wemm 		     ++brandinfo)
877514058dcSAlexander Langer 			if (elf_insert_brand_entry(*brandinfo) < 0)
878aa855a59SPeter Wemm 				error = EINVAL;
879466b14d7SMarcel Moolenaar 		if (error == 0) {
880f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
881f41325dbSPeter Wemm 				linux_ioctl_register_handler(*lihp);
88243bef515SMarcel Moolenaar 			if (bootverbose)
883466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler installed\n");
884466b14d7SMarcel Moolenaar 		} else
885466b14d7SMarcel Moolenaar 			printf("cannot insert Linux ELF brand handler\n");
886aa855a59SPeter Wemm 		break;
887aa855a59SPeter Wemm 	case MOD_UNLOAD:
888aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
889aa855a59SPeter Wemm 		     ++brandinfo)
89043bef515SMarcel Moolenaar 			if (elf_brand_inuse(*brandinfo))
891d2758342SMark Newton 				error = EBUSY;
892d2758342SMark Newton 		if (error == 0) {
893d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
894d2758342SMark Newton 			     *brandinfo != NULL; ++brandinfo)
895aa855a59SPeter Wemm 				if (elf_remove_brand_entry(*brandinfo) < 0)
896aa855a59SPeter Wemm 					error = EINVAL;
897d2758342SMark Newton 		}
898466b14d7SMarcel Moolenaar 		if (error == 0) {
899f41325dbSPeter Wemm 			SET_FOREACH(lihp, linux_ioctl_handler_set)
900f41325dbSPeter Wemm 				linux_ioctl_unregister_handler(*lihp);
901466b14d7SMarcel Moolenaar 			if (bootverbose)
902466b14d7SMarcel Moolenaar 				printf("Linux ELF exec handler removed\n");
903466b14d7SMarcel Moolenaar 		} else
904aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
905aa855a59SPeter Wemm 		break;
906aa855a59SPeter Wemm 	default:
907aa855a59SPeter Wemm 		break;
908d30ea4f5SPeter Wemm 	}
909aa855a59SPeter Wemm 	return error;
910aa855a59SPeter Wemm }
911466b14d7SMarcel Moolenaar 
912aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
913aa855a59SPeter Wemm 	"linuxelf",
914aa855a59SPeter Wemm 	linux_elf_modevent,
915aa855a59SPeter Wemm 	0
916aa855a59SPeter Wemm };
917466b14d7SMarcel Moolenaar 
918aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
919