xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision 6626c6045c38a22c2dc57621a840ae612da0e2e3)
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  *
286626c604SJulian Elischer  *  $Id: linux_sysvec.c,v 1.40 1998/12/16 16:28:57 bde Exp $
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>
395e26fb6fSJordan K. Hubbard #include <sys/buf.h>
40aad9af2bSBruce Evans #include <sys/proc.h>
41d66a5066SPeter Wemm #include <sys/systm.h>
42d66a5066SPeter Wemm #include <sys/sysent.h>
43d66a5066SPeter Wemm #include <sys/imgact.h>
4422d4b0fbSJohn Polstra #include <sys/imgact_aout.h>
45e1743d02SSøren Schmidt #include <sys/imgact_elf.h>
46d66a5066SPeter Wemm #include <sys/signalvar.h>
47e1743d02SSøren Schmidt #include <sys/malloc.h>
48d66a5066SPeter Wemm #include <vm/vm.h>
49d66a5066SPeter Wemm #include <vm/vm_param.h>
50d66a5066SPeter Wemm #include <vm/vm_prot.h>
51d66a5066SPeter Wemm #include <vm/vm_page.h>
52d66a5066SPeter Wemm #include <vm/vm_extern.h>
536626c604SJulian Elischer #ifdef COMPAT_LINUX_THREADS
546626c604SJulian Elischer #include <sys/lock.h>             /* needed, for now, by vm_map.h */
556626c604SJulian Elischer #include <vm/vm_map.h>            /* needed, for now, for VM_STACK defines */
566626c604SJulian Elischer #endif /* COMPAT_LINUX_THREADS */
57d66a5066SPeter Wemm #include <sys/exec.h>
585cf588ebSPeter Wemm #include <sys/kernel.h>
59aa855a59SPeter Wemm #include <sys/module.h>
60d66a5066SPeter Wemm #include <machine/cpu.h>
61d66a5066SPeter Wemm 
62d66a5066SPeter Wemm #include <i386/linux/linux.h>
63d66a5066SPeter Wemm #include <i386/linux/linux_proto.h>
64e1743d02SSøren Schmidt 
65ecbb00a2SDoug Rabson static int	linux_fixup __P((long **stack_base,
66303b270bSEivind Eklund 				 struct image_params *iparams));
67ecbb00a2SDoug Rabson static int	elf_linux_fixup __P((long **stack_base,
68303b270bSEivind Eklund 				     struct image_params *iparams));
69303b270bSEivind Eklund static void	linux_prepsyscall __P((struct trapframe *tf, int *args,
70303b270bSEivind Eklund 				       u_int *code, caddr_t *params));
71303b270bSEivind Eklund static void     linux_sendsig __P((sig_t catcher, int sig, int mask,
72303b270bSEivind Eklund 				   u_long code));
73d66a5066SPeter Wemm 
74d66a5066SPeter Wemm /*
75d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
76d66a5066SPeter Wemm  */
7785f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
78d66a5066SPeter Wemm   	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
79d66a5066SPeter Wemm  	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
80d66a5066SPeter Wemm  	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
81d66a5066SPeter Wemm  	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
82d66a5066SPeter Wemm  	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
83d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
84d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
85d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
8685f118c8SDmitrij Tejblum   	-6, -6, -43, -42, -75, -6, -84
87d66a5066SPeter Wemm };
88d66a5066SPeter Wemm 
89d66a5066SPeter Wemm int bsd_to_linux_signal[NSIG] = {
90d66a5066SPeter Wemm 	0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT,
91d66a5066SPeter Wemm 	LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0,
92d66a5066SPeter Wemm 	LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV,
93d66a5066SPeter Wemm 	0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM,
94d66a5066SPeter Wemm 	LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT,
95d66a5066SPeter Wemm 	LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO,
96d66a5066SPeter Wemm 	LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF,
97d66a5066SPeter Wemm 	LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2
98d66a5066SPeter Wemm };
99d66a5066SPeter Wemm 
100d66a5066SPeter Wemm int linux_to_bsd_signal[LINUX_NSIG] = {
10198fd9ce8SJohn Fieber 	0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS,
102d66a5066SPeter Wemm 	SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM,
10398fd9ce8SJohn Fieber 	SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG,
10498fd9ce8SJohn Fieber 	SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGURG, 0
105d66a5066SPeter Wemm };
106d66a5066SPeter Wemm 
107288078beSEivind Eklund /*
108288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
109288078beSEivind Eklund  * means, deal with it here.
110288078beSEivind Eklund  */
111288078beSEivind Eklund static int
112288078beSEivind Eklund translate_traps(int signal, int trap_code)
113288078beSEivind Eklund {
114d563a53aSEivind Eklund 	if (signal != SIGBUS)
115d563a53aSEivind Eklund 		return signal;
116288078beSEivind Eklund 	switch (trap_code) {
117288078beSEivind Eklund 	case T_PROTFLT:
118288078beSEivind Eklund 	case T_TSSFLT:
119288078beSEivind Eklund 	case T_DOUBLEFLT:
120288078beSEivind Eklund 	case T_PAGEFLT:
121288078beSEivind Eklund 		return SIGSEGV;
122288078beSEivind Eklund 	default:
123288078beSEivind Eklund 		return signal;
124288078beSEivind Eklund 	}
125288078beSEivind Eklund }
126288078beSEivind Eklund 
127303b270bSEivind Eklund static int
128ecbb00a2SDoug Rabson linux_fixup(long **stack_base, struct image_params *imgp)
129d66a5066SPeter Wemm {
130ecbb00a2SDoug Rabson 	long *argv, *envp;
131d66a5066SPeter Wemm 
132d66a5066SPeter Wemm 	argv = *stack_base;
133d66a5066SPeter Wemm 	envp = *stack_base + (imgp->argc + 1);
134d66a5066SPeter Wemm 	(*stack_base)--;
13586a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
136d66a5066SPeter Wemm 	(*stack_base)--;
13786a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
138d66a5066SPeter Wemm 	(*stack_base)--;
13986a14a7aSBruce Evans 	**stack_base = imgp->argc;
140e1743d02SSøren Schmidt 	return 0;
141d66a5066SPeter Wemm }
142d66a5066SPeter Wemm 
143303b270bSEivind Eklund static int
144ecbb00a2SDoug Rabson elf_linux_fixup(long **stack_base, struct image_params *imgp)
145e1743d02SSøren Schmidt {
146e1743d02SSøren Schmidt 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
147ecbb00a2SDoug Rabson 	long *pos;
148d66a5066SPeter Wemm 
149e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
150e1743d02SSøren Schmidt 
151e1743d02SSøren Schmidt 	if (args->trace) {
152e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
153e1743d02SSøren Schmidt 	}
154e1743d02SSøren Schmidt 	if (args->execfd != -1) {
155e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
156e1743d02SSøren Schmidt 	}
157e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
158e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
159e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
160e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
161e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
162e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
163e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
164e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_cred->p_ruid);
165e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_cred->p_svuid);
166e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_cred->p_rgid);
167e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_cred->p_svgid);
168e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
169e1743d02SSøren Schmidt 
170e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
171e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
172e1743d02SSøren Schmidt 
173e1743d02SSøren Schmidt 	(*stack_base)--;
174ecbb00a2SDoug Rabson 	**stack_base = (long)imgp->argc;
175e1743d02SSøren Schmidt 	return 0;
176e1743d02SSøren Schmidt }
177d66a5066SPeter Wemm 
178d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
179d66a5066SPeter Wemm 
180d66a5066SPeter Wemm /*
181d66a5066SPeter Wemm  * Send an interrupt to process.
182d66a5066SPeter Wemm  *
183d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
184d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
185d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
186d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
187d66a5066SPeter Wemm  * frame pointer, it returns to the user
188d66a5066SPeter Wemm  * specified pc, psl.
189d66a5066SPeter Wemm  */
190d66a5066SPeter Wemm 
191303b270bSEivind Eklund static void
192b36546f6SPeter Wemm linux_sendsig(sig_t catcher, int sig, int mask, u_long code)
193d66a5066SPeter Wemm {
194d66a5066SPeter Wemm 	register struct proc *p = curproc;
195213fdd80SPeter Wemm 	register struct trapframe *regs;
196d66a5066SPeter Wemm 	struct linux_sigframe *fp, frame;
197d66a5066SPeter Wemm 	struct sigacts *psp = p->p_sigacts;
198d66a5066SPeter Wemm 	int oonstack;
199d66a5066SPeter Wemm 
200d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
201d66a5066SPeter Wemm 	oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
202d66a5066SPeter Wemm 
203d66a5066SPeter Wemm #ifdef DEBUG
204e4e6ae13SBruce Evans 	printf("Linux-emul(%ld): linux_sendsig(%p, %d, %d, %lu)\n",
205e4e6ae13SBruce Evans 	    (long)p->p_pid, catcher, sig, mask, code);
206d66a5066SPeter Wemm #endif
207d66a5066SPeter Wemm 	/*
208d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
209d66a5066SPeter Wemm 	 */
210d66a5066SPeter Wemm 	if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
211d66a5066SPeter Wemm 	    (psp->ps_sigonstack & sigmask(sig))) {
212d66a5066SPeter Wemm 		fp = (struct linux_sigframe *)(psp->ps_sigstk.ss_sp +
213d66a5066SPeter Wemm 		    psp->ps_sigstk.ss_size - sizeof(struct linux_sigframe));
214d66a5066SPeter Wemm 		psp->ps_sigstk.ss_flags |= SS_ONSTACK;
215d66a5066SPeter Wemm 	} else {
216213fdd80SPeter Wemm 		fp = (struct linux_sigframe *)regs->tf_esp - 1;
217d66a5066SPeter Wemm 	}
218d66a5066SPeter Wemm 
219d66a5066SPeter Wemm 	/*
220d66a5066SPeter Wemm 	 * grow() will return FALSE if the fp will not fit inside the stack
221d66a5066SPeter Wemm 	 *	and the stack can not be grown. useracc will return FALSE
222d66a5066SPeter Wemm 	 *	if access is denied.
223d66a5066SPeter Wemm 	 */
2246626c604SJulian Elischer #ifdef COMPAT_LINUX_THREADS
2256626c604SJulian Elischer #ifdef USE_VM_STACK
2266626c604SJulian Elischer #ifndef USE_VM_STACK_FOR_EXEC
2276626c604SJulian Elischer 	if ((((caddr_t)fp > p->p_vmspace->vm_maxsaddr &&
2286626c604SJulian Elischer 	      (caddr_t)fp < (caddr_t)USRSTACK &&
2296626c604SJulian Elischer 	      grow(p, (int)fp) == FALSE) ||
2306626c604SJulian Elischer 	     (((caddr_t)fp <= p->p_vmspace->vm_maxsaddr ||
2316626c604SJulian Elischer 	       (caddr_t)fp >= (caddr_t)USRSTACK) &&
2326626c604SJulian Elischer 	      grow_stack (p, (int)fp) == FALSE)) ||
2336626c604SJulian Elischer #else
2346626c604SJulian Elischer 	if ((grow_stack (p, (int)fp) == FALSE) ||
2356626c604SJulian Elischer #endif
2366626c604SJulian Elischer #else
2376626c604SJulian Elischer #endif /* COMPAT_LINUX_THREADS */
238d66a5066SPeter Wemm 	if ((grow(p, (int)fp) == FALSE) ||
2396626c604SJulian Elischer #ifdef COMPAT_LINUX_THREADS
2406626c604SJulian Elischer #endif
2416626c604SJulian Elischer #endif /* COMPAT_LINUX_THREADS */
242d66a5066SPeter Wemm 	    (useracc((caddr_t)fp, sizeof (struct linux_sigframe), B_WRITE) == FALSE)) {
243d66a5066SPeter Wemm 		/*
244d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
245d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
246d66a5066SPeter Wemm 		 */
247d66a5066SPeter Wemm 		SIGACTION(p, SIGILL) = SIG_DFL;
248d66a5066SPeter Wemm 		sig = sigmask(SIGILL);
249d66a5066SPeter Wemm 		p->p_sigignore &= ~sig;
250d66a5066SPeter Wemm 		p->p_sigcatch &= ~sig;
251d66a5066SPeter Wemm 		p->p_sigmask &= ~sig;
252d66a5066SPeter Wemm 		psignal(p, SIGILL);
253d66a5066SPeter Wemm 		return;
254d66a5066SPeter Wemm 	}
255d66a5066SPeter Wemm 
256d66a5066SPeter Wemm 	/*
257d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
258d66a5066SPeter Wemm 	 */
259d66a5066SPeter Wemm 	if (p->p_sysent->sv_sigtbl) {
260d66a5066SPeter Wemm 		if (sig < p->p_sysent->sv_sigsize)
261d66a5066SPeter Wemm 			sig = p->p_sysent->sv_sigtbl[sig];
262d66a5066SPeter Wemm 		else
263d66a5066SPeter Wemm 			sig = p->p_sysent->sv_sigsize + 1;
264d66a5066SPeter Wemm 	}
265d66a5066SPeter Wemm 
266d66a5066SPeter Wemm 	frame.sf_handler = catcher;
267d66a5066SPeter Wemm 	frame.sf_sig = sig;
268d66a5066SPeter Wemm 
269d66a5066SPeter Wemm 	/*
270d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
271d66a5066SPeter Wemm 	 */
272d66a5066SPeter Wemm 	frame.sf_sc.sc_mask   = mask;
273d66a5066SPeter Wemm 	__asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
274d66a5066SPeter Wemm 	__asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
275213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
276213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
277213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
278213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
279213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
280213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
281213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
282213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
283213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
284213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
285213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
286213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
287213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
288213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
289213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
290d66a5066SPeter Wemm 	frame.sf_sc.sc_trapno = code;	/* XXX ???? */
291d66a5066SPeter Wemm 
292d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
293d66a5066SPeter Wemm 		/*
294d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
295d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
296d66a5066SPeter Wemm 		 */
297d66a5066SPeter Wemm 		sigexit(p, SIGILL);
298d66a5066SPeter Wemm 		/* NOTREACHED */
299d66a5066SPeter Wemm 	}
300d66a5066SPeter Wemm 
301d66a5066SPeter Wemm 	/*
302d66a5066SPeter Wemm 	 * Build context to run handler in.
303d66a5066SPeter Wemm 	 */
304213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
3054c56fcdeSBruce Evans 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
306213fdd80SPeter Wemm 	regs->tf_eflags &= ~PSL_VM;
307213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
308213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
309213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
310213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
311d66a5066SPeter Wemm }
312d66a5066SPeter Wemm 
313d66a5066SPeter Wemm /*
314d66a5066SPeter Wemm  * System call to cleanup state after a signal
315d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
316d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
317d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
318d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
319d66a5066SPeter Wemm  * make sure that the user has not modified the
320d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
321d66a5066SPeter Wemm  * a machine fault.
322d66a5066SPeter Wemm  */
323d66a5066SPeter Wemm int
324cb226aaaSPoul-Henning Kamp linux_sigreturn(p, args)
325d66a5066SPeter Wemm 	struct proc *p;
326d66a5066SPeter Wemm 	struct linux_sigreturn_args *args;
327d66a5066SPeter Wemm {
328d66a5066SPeter Wemm 	struct linux_sigcontext *scp, context;
329213fdd80SPeter Wemm 	register struct trapframe *regs;
330d66a5066SPeter Wemm 	int eflags;
331d66a5066SPeter Wemm 
332d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
333d66a5066SPeter Wemm 
334d66a5066SPeter Wemm #ifdef DEBUG
335e4e6ae13SBruce Evans 	printf("Linux-emul(%ld): linux_sigreturn(%p)\n",
336e4e6ae13SBruce Evans 	    (long)p->p_pid, (void *)args->scp);
337d66a5066SPeter Wemm #endif
338d66a5066SPeter Wemm 	/*
339d66a5066SPeter Wemm 	 * The trampoline code hands us the context.
340d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
341d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
342d66a5066SPeter Wemm 	 */
343ecbb00a2SDoug Rabson 	scp = SCARG(args,scp);
344d66a5066SPeter Wemm 	if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
345d66a5066SPeter Wemm 		return (EFAULT);
346d66a5066SPeter Wemm 
347d66a5066SPeter Wemm 	/*
348d66a5066SPeter Wemm 	 * Check for security violations.
349d66a5066SPeter Wemm 	 */
350d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
351d66a5066SPeter Wemm 	eflags = context.sc_eflags;
352d66a5066SPeter Wemm 	/*
353d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
354d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
355d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
356d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
357d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
358d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
359d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
360d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
361d66a5066SPeter Wemm 	 */
362213fdd80SPeter Wemm 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
363d66a5066SPeter Wemm     		return(EINVAL);
364d66a5066SPeter Wemm 	}
365d66a5066SPeter Wemm 
366d66a5066SPeter Wemm 	/*
367d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
368d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
369d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
370d66a5066SPeter Wemm 	 */
37140d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
372d66a5066SPeter Wemm 	if (!CS_SECURE(context.sc_cs)) {
373d66a5066SPeter Wemm 		trapsignal(p, SIGBUS, T_PROTFLT);
374d66a5066SPeter Wemm 		return(EINVAL);
375d66a5066SPeter Wemm 	}
376d66a5066SPeter Wemm 
377d66a5066SPeter Wemm 	p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
378d66a5066SPeter Wemm 	p->p_sigmask = context.sc_mask &~
379d66a5066SPeter Wemm 		(sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
380d66a5066SPeter Wemm 	/*
381d66a5066SPeter Wemm 	 * Restore signal context.
382d66a5066SPeter Wemm 	 */
383d66a5066SPeter Wemm 	/* %fs and %gs were restored by the trampoline. */
384213fdd80SPeter Wemm 	regs->tf_es     = context.sc_es;
385213fdd80SPeter Wemm 	regs->tf_ds     = context.sc_ds;
386213fdd80SPeter Wemm 	regs->tf_edi    = context.sc_edi;
387213fdd80SPeter Wemm 	regs->tf_esi    = context.sc_esi;
388213fdd80SPeter Wemm 	regs->tf_ebp    = context.sc_ebp;
389213fdd80SPeter Wemm 	regs->tf_ebx    = context.sc_ebx;
390213fdd80SPeter Wemm 	regs->tf_edx    = context.sc_edx;
391213fdd80SPeter Wemm 	regs->tf_ecx    = context.sc_ecx;
392213fdd80SPeter Wemm 	regs->tf_eax    = context.sc_eax;
393213fdd80SPeter Wemm 	regs->tf_eip    = context.sc_eip;
394213fdd80SPeter Wemm 	regs->tf_cs     = context.sc_cs;
395213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
396213fdd80SPeter Wemm 	regs->tf_esp    = context.sc_esp_at_signal;
397213fdd80SPeter Wemm 	regs->tf_ss     = context.sc_ss;
398d66a5066SPeter Wemm 
399d66a5066SPeter Wemm 	return (EJUSTRETURN);
400d66a5066SPeter Wemm }
401d66a5066SPeter Wemm 
402303b270bSEivind Eklund static void
403d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
404d66a5066SPeter Wemm {
405d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
406d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
407d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
408d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
409d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
410d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
411d66a5066SPeter Wemm }
412d66a5066SPeter Wemm 
413d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
414e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
415d66a5066SPeter Wemm 	linux_sysent,
416d66a5066SPeter Wemm 	0xff,
417d66a5066SPeter Wemm 	NSIG,
418d66a5066SPeter Wemm 	bsd_to_linux_signal,
41985f118c8SDmitrij Tejblum 	ELAST + 1,
420d66a5066SPeter Wemm 	bsd_to_linux_errno,
421288078beSEivind Eklund 	translate_traps,
422d66a5066SPeter Wemm 	linux_fixup,
423d66a5066SPeter Wemm 	linux_sendsig,
424d66a5066SPeter Wemm 	linux_sigcode,
425d66a5066SPeter Wemm 	&linux_szsigcode,
426d66a5066SPeter Wemm 	linux_prepsyscall,
42722d4b0fbSJohn Polstra 	"Linux a.out",
42822d4b0fbSJohn Polstra 	aout_coredump
429d66a5066SPeter Wemm };
430e1743d02SSøren Schmidt 
431e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
432e1743d02SSøren Schmidt         LINUX_SYS_MAXSYSCALL,
433e1743d02SSøren Schmidt         linux_sysent,
434e1743d02SSøren Schmidt         0xff,
435e1743d02SSøren Schmidt         NSIG,
436e1743d02SSøren Schmidt         bsd_to_linux_signal,
43785f118c8SDmitrij Tejblum         ELAST + 1,
438e1743d02SSøren Schmidt         bsd_to_linux_errno,
439288078beSEivind Eklund         translate_traps,
440e1743d02SSøren Schmidt         elf_linux_fixup,
441e1743d02SSøren Schmidt         linux_sendsig,
442e1743d02SSøren Schmidt         linux_sigcode,
443e1743d02SSøren Schmidt         &linux_szsigcode,
444e1743d02SSøren Schmidt         linux_prepsyscall,
44522d4b0fbSJohn Polstra 	"Linux ELF",
44622d4b0fbSJohn Polstra 	elf_coredump
447e1743d02SSøren Schmidt };
448e1743d02SSøren Schmidt 
4495cf588ebSPeter Wemm /*
4505cf588ebSPeter Wemm  * Installed either via SYSINIT() or via LKM stubs.
4515cf588ebSPeter Wemm  */
452514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
453ea5a2b2eSSøren Schmidt 					"Linux",
454ea5a2b2eSSøren Schmidt 					"/compat/linux",
4555cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
456ea5a2b2eSSøren Schmidt 					&elf_linux_sysvec
4575cf588ebSPeter Wemm 				 };
4585cf588ebSPeter Wemm 
459514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
4604e138a28SMike Smith 					"Linux",
4614e138a28SMike Smith 					"/compat/linux",
4624e138a28SMike Smith 					"/lib/ld-linux.so.2",
4634e138a28SMike Smith 					&elf_linux_sysvec
4644e138a28SMike Smith 				 };
4654e138a28SMike Smith 
466514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
467514058dcSAlexander Langer 					&linux_brand,
468514058dcSAlexander Langer 					&linux_glibc2brand,
469514058dcSAlexander Langer 					NULL
470514058dcSAlexander Langer 				};
471514058dcSAlexander Langer 
472aa855a59SPeter Wemm static int
473c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
474d30ea4f5SPeter Wemm {
475514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
476514058dcSAlexander Langer 	int error;
477514058dcSAlexander Langer 
478514058dcSAlexander Langer 	error = 0;
479514058dcSAlexander Langer 
480aa855a59SPeter Wemm 	switch(type) {
481aa855a59SPeter Wemm 	case MOD_LOAD:
482aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
483aa855a59SPeter Wemm 		    ++brandinfo)
484514058dcSAlexander Langer 			if (elf_insert_brand_entry(*brandinfo) < 0)
485aa855a59SPeter Wemm 				error = EINVAL;
486514058dcSAlexander Langer 		if (error)
487d30ea4f5SPeter Wemm 			printf("cannot insert Linux elf brand handler\n");
488d30ea4f5SPeter Wemm 		else if (bootverbose)
489d30ea4f5SPeter Wemm 			printf("Linux-ELF exec handler installed\n");
490aa855a59SPeter Wemm 		break;
491aa855a59SPeter Wemm 	case MOD_UNLOAD:
492aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
493aa855a59SPeter Wemm 		    ++brandinfo)
494aa855a59SPeter Wemm 			if (elf_remove_brand_entry(*brandinfo) < 0)
495aa855a59SPeter Wemm 				error = EINVAL;
496aa855a59SPeter Wemm 		if (error)
497aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
498aa855a59SPeter Wemm 		else if (bootverbose)
499aa855a59SPeter Wemm 			printf("Linux-elf exec handler removed\n");
500aa855a59SPeter Wemm 		break;
501aa855a59SPeter Wemm 	default:
502aa855a59SPeter Wemm 		break;
503d30ea4f5SPeter Wemm 	}
504aa855a59SPeter Wemm 	return error;
505aa855a59SPeter Wemm }
506aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
507aa855a59SPeter Wemm 	"linuxelf",
508aa855a59SPeter Wemm 	linux_elf_modevent,
509aa855a59SPeter Wemm 	0
510aa855a59SPeter Wemm };
511aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
512