xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision 98fd9ce8c9cd079df6b9909b9fc6df19d1078056)
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  *
2898fd9ce8SJohn Fieber  *  $Id: linux_sysvec.c,v 1.34 1998/09/17 22:08:29 msmith 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>
53d66a5066SPeter Wemm #include <sys/exec.h>
545cf588ebSPeter Wemm #include <sys/kernel.h>
55d66a5066SPeter Wemm #include <machine/cpu.h>
56d66a5066SPeter Wemm 
57d66a5066SPeter Wemm #include <i386/linux/linux.h>
58d66a5066SPeter Wemm #include <i386/linux/linux_proto.h>
59e1743d02SSøren Schmidt 
60ecbb00a2SDoug Rabson static int	linux_fixup __P((long **stack_base,
61303b270bSEivind Eklund 				 struct image_params *iparams));
62ecbb00a2SDoug Rabson static int	elf_linux_fixup __P((long **stack_base,
63303b270bSEivind Eklund 				     struct image_params *iparams));
64303b270bSEivind Eklund static void	linux_prepsyscall __P((struct trapframe *tf, int *args,
65303b270bSEivind Eklund 				       u_int *code, caddr_t *params));
66303b270bSEivind Eklund static void     linux_sendsig __P((sig_t catcher, int sig, int mask,
67303b270bSEivind Eklund 				   u_long code));
68d66a5066SPeter Wemm 
69d66a5066SPeter Wemm /*
70d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
71d66a5066SPeter Wemm  */
729d767d02SBruce Evans static int bsd_to_linux_errno[ELAST] = {
73d66a5066SPeter Wemm   	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
74d66a5066SPeter Wemm  	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
75d66a5066SPeter Wemm  	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
76d66a5066SPeter Wemm  	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
77d66a5066SPeter Wemm  	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
78d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
79d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
80d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
81958a0829SSøren Schmidt   	-6, -43, -42
82d66a5066SPeter Wemm };
83d66a5066SPeter Wemm 
84d66a5066SPeter Wemm int bsd_to_linux_signal[NSIG] = {
85d66a5066SPeter Wemm 	0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT,
86d66a5066SPeter Wemm 	LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0,
87d66a5066SPeter Wemm 	LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV,
88d66a5066SPeter Wemm 	0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM,
89d66a5066SPeter Wemm 	LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT,
90d66a5066SPeter Wemm 	LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO,
91d66a5066SPeter Wemm 	LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF,
92d66a5066SPeter Wemm 	LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2
93d66a5066SPeter Wemm };
94d66a5066SPeter Wemm 
95d66a5066SPeter Wemm int linux_to_bsd_signal[LINUX_NSIG] = {
9698fd9ce8SJohn Fieber 	0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS,
97d66a5066SPeter Wemm 	SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM,
9898fd9ce8SJohn Fieber 	SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG,
9998fd9ce8SJohn Fieber 	SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGURG, 0
100d66a5066SPeter Wemm };
101d66a5066SPeter Wemm 
102288078beSEivind Eklund /*
103288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
104288078beSEivind Eklund  * means, deal with it here.
105288078beSEivind Eklund  */
106288078beSEivind Eklund static int
107288078beSEivind Eklund translate_traps(int signal, int trap_code)
108288078beSEivind Eklund {
109d563a53aSEivind Eklund 	if (signal != SIGBUS)
110d563a53aSEivind Eklund 		return signal;
111288078beSEivind Eklund 	switch (trap_code) {
112288078beSEivind Eklund 	case T_PROTFLT:
113288078beSEivind Eklund 	case T_TSSFLT:
114288078beSEivind Eklund 	case T_DOUBLEFLT:
115288078beSEivind Eklund 	case T_PAGEFLT:
116288078beSEivind Eklund 		return SIGSEGV;
117288078beSEivind Eklund 	default:
118288078beSEivind Eklund 		return signal;
119288078beSEivind Eklund 	}
120288078beSEivind Eklund }
121288078beSEivind Eklund 
122303b270bSEivind Eklund static int
123ecbb00a2SDoug Rabson linux_fixup(long **stack_base, struct image_params *imgp)
124d66a5066SPeter Wemm {
125ecbb00a2SDoug Rabson 	long *argv, *envp;
126d66a5066SPeter Wemm 
127d66a5066SPeter Wemm 	argv = *stack_base;
128d66a5066SPeter Wemm 	envp = *stack_base + (imgp->argc + 1);
129d66a5066SPeter Wemm 	(*stack_base)--;
13086a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
131d66a5066SPeter Wemm 	(*stack_base)--;
13286a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
133d66a5066SPeter Wemm 	(*stack_base)--;
13486a14a7aSBruce Evans 	**stack_base = imgp->argc;
135e1743d02SSøren Schmidt 	return 0;
136d66a5066SPeter Wemm }
137d66a5066SPeter Wemm 
138303b270bSEivind Eklund static int
139ecbb00a2SDoug Rabson elf_linux_fixup(long **stack_base, struct image_params *imgp)
140e1743d02SSøren Schmidt {
141e1743d02SSøren Schmidt 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
142ecbb00a2SDoug Rabson 	long *pos;
143d66a5066SPeter Wemm 
144e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
145e1743d02SSøren Schmidt 
146e1743d02SSøren Schmidt 	if (args->trace) {
147e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
148e1743d02SSøren Schmidt 	}
149e1743d02SSøren Schmidt 	if (args->execfd != -1) {
150e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
151e1743d02SSøren Schmidt 	}
152e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
153e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
154e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
155e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
156e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
157e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
158e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
159e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_cred->p_ruid);
160e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_cred->p_svuid);
161e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_cred->p_rgid);
162e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_cred->p_svgid);
163e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
164e1743d02SSøren Schmidt 
165e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
166e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
167e1743d02SSøren Schmidt 
168e1743d02SSøren Schmidt 	(*stack_base)--;
169ecbb00a2SDoug Rabson 	**stack_base = (long)imgp->argc;
170e1743d02SSøren Schmidt 	return 0;
171e1743d02SSøren Schmidt }
172d66a5066SPeter Wemm 
173d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
174d66a5066SPeter Wemm 
175d66a5066SPeter Wemm /*
176d66a5066SPeter Wemm  * Send an interrupt to process.
177d66a5066SPeter Wemm  *
178d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
179d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
180d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
181d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
182d66a5066SPeter Wemm  * frame pointer, it returns to the user
183d66a5066SPeter Wemm  * specified pc, psl.
184d66a5066SPeter Wemm  */
185d66a5066SPeter Wemm 
186303b270bSEivind Eklund static void
187b36546f6SPeter Wemm linux_sendsig(sig_t catcher, int sig, int mask, u_long code)
188d66a5066SPeter Wemm {
189d66a5066SPeter Wemm 	register struct proc *p = curproc;
190213fdd80SPeter Wemm 	register struct trapframe *regs;
191d66a5066SPeter Wemm 	struct linux_sigframe *fp, frame;
192d66a5066SPeter Wemm 	struct sigacts *psp = p->p_sigacts;
193d66a5066SPeter Wemm 	int oonstack;
194d66a5066SPeter Wemm 
195d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
196d66a5066SPeter Wemm 	oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
197d66a5066SPeter Wemm 
198d66a5066SPeter Wemm #ifdef DEBUG
199e4e6ae13SBruce Evans 	printf("Linux-emul(%ld): linux_sendsig(%p, %d, %d, %lu)\n",
200e4e6ae13SBruce Evans 	    (long)p->p_pid, catcher, sig, mask, code);
201d66a5066SPeter Wemm #endif
202d66a5066SPeter Wemm 	/*
203d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
204d66a5066SPeter Wemm 	 */
205d66a5066SPeter Wemm 	if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
206d66a5066SPeter Wemm 	    (psp->ps_sigonstack & sigmask(sig))) {
207d66a5066SPeter Wemm 		fp = (struct linux_sigframe *)(psp->ps_sigstk.ss_sp +
208d66a5066SPeter Wemm 		    psp->ps_sigstk.ss_size - sizeof(struct linux_sigframe));
209d66a5066SPeter Wemm 		psp->ps_sigstk.ss_flags |= SS_ONSTACK;
210d66a5066SPeter Wemm 	} else {
211213fdd80SPeter Wemm 		fp = (struct linux_sigframe *)regs->tf_esp - 1;
212d66a5066SPeter Wemm 	}
213d66a5066SPeter Wemm 
214d66a5066SPeter Wemm 	/*
215d66a5066SPeter Wemm 	 * grow() will return FALSE if the fp will not fit inside the stack
216d66a5066SPeter Wemm 	 *	and the stack can not be grown. useracc will return FALSE
217d66a5066SPeter Wemm 	 *	if access is denied.
218d66a5066SPeter Wemm 	 */
219d66a5066SPeter Wemm 	if ((grow(p, (int)fp) == FALSE) ||
220d66a5066SPeter Wemm 	    (useracc((caddr_t)fp, sizeof (struct linux_sigframe), B_WRITE) == FALSE)) {
221d66a5066SPeter Wemm 		/*
222d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
223d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
224d66a5066SPeter Wemm 		 */
225d66a5066SPeter Wemm 		SIGACTION(p, SIGILL) = SIG_DFL;
226d66a5066SPeter Wemm 		sig = sigmask(SIGILL);
227d66a5066SPeter Wemm 		p->p_sigignore &= ~sig;
228d66a5066SPeter Wemm 		p->p_sigcatch &= ~sig;
229d66a5066SPeter Wemm 		p->p_sigmask &= ~sig;
230d66a5066SPeter Wemm 		psignal(p, SIGILL);
231d66a5066SPeter Wemm 		return;
232d66a5066SPeter Wemm 	}
233d66a5066SPeter Wemm 
234d66a5066SPeter Wemm 	/*
235d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
236d66a5066SPeter Wemm 	 */
237d66a5066SPeter Wemm 	if (p->p_sysent->sv_sigtbl) {
238d66a5066SPeter Wemm 		if (sig < p->p_sysent->sv_sigsize)
239d66a5066SPeter Wemm 			sig = p->p_sysent->sv_sigtbl[sig];
240d66a5066SPeter Wemm 		else
241d66a5066SPeter Wemm 			sig = p->p_sysent->sv_sigsize + 1;
242d66a5066SPeter Wemm 	}
243d66a5066SPeter Wemm 
244d66a5066SPeter Wemm 	frame.sf_handler = catcher;
245d66a5066SPeter Wemm 	frame.sf_sig = sig;
246d66a5066SPeter Wemm 
247d66a5066SPeter Wemm 	/*
248d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
249d66a5066SPeter Wemm 	 */
250d66a5066SPeter Wemm 	frame.sf_sc.sc_mask   = mask;
251d66a5066SPeter Wemm 	__asm("movl %%gs,%w0" : "=r" (frame.sf_sc.sc_gs));
252d66a5066SPeter Wemm 	__asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
253213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
254213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
255213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
256213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
257213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
258213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
259213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
260213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
261213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
262213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
263213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
264213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
265213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
266213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
267213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
268d66a5066SPeter Wemm 	frame.sf_sc.sc_trapno = code;	/* XXX ???? */
269d66a5066SPeter Wemm 
270d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
271d66a5066SPeter Wemm 		/*
272d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
273d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
274d66a5066SPeter Wemm 		 */
275d66a5066SPeter Wemm 		sigexit(p, SIGILL);
276d66a5066SPeter Wemm 		/* NOTREACHED */
277d66a5066SPeter Wemm 	}
278d66a5066SPeter Wemm 
279d66a5066SPeter Wemm 	/*
280d66a5066SPeter Wemm 	 * Build context to run handler in.
281d66a5066SPeter Wemm 	 */
282213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
283213fdd80SPeter Wemm 	regs->tf_eip = (int)(((char *)PS_STRINGS) - *(p->p_sysent->sv_szsigcode));
284213fdd80SPeter Wemm 	regs->tf_eflags &= ~PSL_VM;
285213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
286213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
287213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
288213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
289d66a5066SPeter Wemm }
290d66a5066SPeter Wemm 
291d66a5066SPeter Wemm /*
292d66a5066SPeter Wemm  * System call to cleanup state after a signal
293d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
294d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
295d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
296d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
297d66a5066SPeter Wemm  * make sure that the user has not modified the
298d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
299d66a5066SPeter Wemm  * a machine fault.
300d66a5066SPeter Wemm  */
301d66a5066SPeter Wemm int
302cb226aaaSPoul-Henning Kamp linux_sigreturn(p, args)
303d66a5066SPeter Wemm 	struct proc *p;
304d66a5066SPeter Wemm 	struct linux_sigreturn_args *args;
305d66a5066SPeter Wemm {
306d66a5066SPeter Wemm 	struct linux_sigcontext *scp, context;
307213fdd80SPeter Wemm 	register struct trapframe *regs;
308d66a5066SPeter Wemm 	int eflags;
309d66a5066SPeter Wemm 
310d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
311d66a5066SPeter Wemm 
312d66a5066SPeter Wemm #ifdef DEBUG
313e4e6ae13SBruce Evans 	printf("Linux-emul(%ld): linux_sigreturn(%p)\n",
314e4e6ae13SBruce Evans 	    (long)p->p_pid, (void *)args->scp);
315d66a5066SPeter Wemm #endif
316d66a5066SPeter Wemm 	/*
317d66a5066SPeter Wemm 	 * The trampoline code hands us the context.
318d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
319d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
320d66a5066SPeter Wemm 	 */
321ecbb00a2SDoug Rabson 	scp = SCARG(args,scp);
322d66a5066SPeter Wemm 	if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
323d66a5066SPeter Wemm 		return (EFAULT);
324d66a5066SPeter Wemm 
325d66a5066SPeter Wemm 	/*
326d66a5066SPeter Wemm 	 * Check for security violations.
327d66a5066SPeter Wemm 	 */
328d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
329d66a5066SPeter Wemm 	eflags = context.sc_eflags;
330d66a5066SPeter Wemm 	/*
331d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
332d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
333d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
334d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
335d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
336d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
337d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
338d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
339d66a5066SPeter Wemm 	 */
340213fdd80SPeter Wemm 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
341d66a5066SPeter Wemm     		return(EINVAL);
342d66a5066SPeter Wemm 	}
343d66a5066SPeter Wemm 
344d66a5066SPeter Wemm 	/*
345d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
346d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
347d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
348d66a5066SPeter Wemm 	 */
34940d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
350d66a5066SPeter Wemm 	if (!CS_SECURE(context.sc_cs)) {
351d66a5066SPeter Wemm 		trapsignal(p, SIGBUS, T_PROTFLT);
352d66a5066SPeter Wemm 		return(EINVAL);
353d66a5066SPeter Wemm 	}
354d66a5066SPeter Wemm 
355d66a5066SPeter Wemm 	p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
356d66a5066SPeter Wemm 	p->p_sigmask = context.sc_mask &~
357d66a5066SPeter Wemm 		(sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
358d66a5066SPeter Wemm 	/*
359d66a5066SPeter Wemm 	 * Restore signal context.
360d66a5066SPeter Wemm 	 */
361d66a5066SPeter Wemm 	/* %fs and %gs were restored by the trampoline. */
362213fdd80SPeter Wemm 	regs->tf_es     = context.sc_es;
363213fdd80SPeter Wemm 	regs->tf_ds     = context.sc_ds;
364213fdd80SPeter Wemm 	regs->tf_edi    = context.sc_edi;
365213fdd80SPeter Wemm 	regs->tf_esi    = context.sc_esi;
366213fdd80SPeter Wemm 	regs->tf_ebp    = context.sc_ebp;
367213fdd80SPeter Wemm 	regs->tf_ebx    = context.sc_ebx;
368213fdd80SPeter Wemm 	regs->tf_edx    = context.sc_edx;
369213fdd80SPeter Wemm 	regs->tf_ecx    = context.sc_ecx;
370213fdd80SPeter Wemm 	regs->tf_eax    = context.sc_eax;
371213fdd80SPeter Wemm 	regs->tf_eip    = context.sc_eip;
372213fdd80SPeter Wemm 	regs->tf_cs     = context.sc_cs;
373213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
374213fdd80SPeter Wemm 	regs->tf_esp    = context.sc_esp_at_signal;
375213fdd80SPeter Wemm 	regs->tf_ss     = context.sc_ss;
376d66a5066SPeter Wemm 
377d66a5066SPeter Wemm 	return (EJUSTRETURN);
378d66a5066SPeter Wemm }
379d66a5066SPeter Wemm 
380303b270bSEivind Eklund static void
381d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
382d66a5066SPeter Wemm {
383d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
384d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
385d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
386d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
387d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
388d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
389d66a5066SPeter Wemm }
390d66a5066SPeter Wemm 
391d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
392e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
393d66a5066SPeter Wemm 	linux_sysent,
394d66a5066SPeter Wemm 	0xff,
395d66a5066SPeter Wemm 	NSIG,
396d66a5066SPeter Wemm 	bsd_to_linux_signal,
397d66a5066SPeter Wemm 	ELAST,
398d66a5066SPeter Wemm 	bsd_to_linux_errno,
399288078beSEivind Eklund 	translate_traps,
400d66a5066SPeter Wemm 	linux_fixup,
401d66a5066SPeter Wemm 	linux_sendsig,
402d66a5066SPeter Wemm 	linux_sigcode,
403d66a5066SPeter Wemm 	&linux_szsigcode,
404d66a5066SPeter Wemm 	linux_prepsyscall,
40522d4b0fbSJohn Polstra 	"Linux a.out",
40622d4b0fbSJohn Polstra 	aout_coredump
407d66a5066SPeter Wemm };
408e1743d02SSøren Schmidt 
409e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
410e1743d02SSøren Schmidt         LINUX_SYS_MAXSYSCALL,
411e1743d02SSøren Schmidt         linux_sysent,
412e1743d02SSøren Schmidt         0xff,
413e1743d02SSøren Schmidt         NSIG,
414e1743d02SSøren Schmidt         bsd_to_linux_signal,
415e1743d02SSøren Schmidt         ELAST,
416e1743d02SSøren Schmidt         bsd_to_linux_errno,
417288078beSEivind Eklund         translate_traps,
418e1743d02SSøren Schmidt         elf_linux_fixup,
419e1743d02SSøren Schmidt         linux_sendsig,
420e1743d02SSøren Schmidt         linux_sigcode,
421e1743d02SSøren Schmidt         &linux_szsigcode,
422e1743d02SSøren Schmidt         linux_prepsyscall,
42322d4b0fbSJohn Polstra 	"Linux ELF",
42422d4b0fbSJohn Polstra 	elf_coredump
425e1743d02SSøren Schmidt };
426e1743d02SSøren Schmidt 
4275cf588ebSPeter Wemm /*
4285cf588ebSPeter Wemm  * Installed either via SYSINIT() or via LKM stubs.
4295cf588ebSPeter Wemm  */
430d131a704SEivind Eklund Elf32_Brandinfo linux_brand = {
431ea5a2b2eSSøren Schmidt 					"Linux",
432ea5a2b2eSSøren Schmidt 					"/compat/linux",
4335cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
434ea5a2b2eSSøren Schmidt 					&elf_linux_sysvec
4355cf588ebSPeter Wemm 				 };
4365cf588ebSPeter Wemm 
4374e138a28SMike Smith Elf32_Brandinfo linux_glibc2brand = {
4384e138a28SMike Smith 					"Linux",
4394e138a28SMike Smith 					"/compat/linux",
4404e138a28SMike Smith 					"/lib/ld-linux.so.2",
4414e138a28SMike Smith 					&elf_linux_sysvec
4424e138a28SMike Smith 				 };
4434e138a28SMike Smith 
4445cf588ebSPeter Wemm #ifndef LKM
4455cf588ebSPeter Wemm /*
4465cf588ebSPeter Wemm  * XXX: this is WRONG, it needs to be SI_SUB_EXEC, but this is just at the
4475cf588ebSPeter Wemm  * "proof of concept" stage and will be fixed shortly
4485cf588ebSPeter Wemm  */
44917bd614dSBruce Evans static void linux_elf_init __P((void *dummy));
45017bd614dSBruce Evans 
451d30ea4f5SPeter Wemm static void
452d30ea4f5SPeter Wemm linux_elf_init(dummy)
453d30ea4f5SPeter Wemm 	void *dummy;
454d30ea4f5SPeter Wemm {
4554e138a28SMike Smith 	if ((elf_insert_brand_entry(&linux_brand) < 0) ||
4564e138a28SMike Smith 	    (elf_insert_brand_entry(&linux_glibc2brand) < 0))
457d30ea4f5SPeter Wemm 		printf("cannot insert Linux elf brand handler\n");
458d30ea4f5SPeter Wemm 	else if (bootverbose)
459d30ea4f5SPeter Wemm 		printf("Linux-ELF exec handler installed\n");
460d30ea4f5SPeter Wemm }
461d30ea4f5SPeter Wemm 
462d30ea4f5SPeter Wemm SYSINIT(linuxelf, SI_SUB_VFS, SI_ORDER_ANY, linux_elf_init, NULL);
4635cf588ebSPeter Wemm #endif
464