xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision c3aac50f284c6cca5b4f2eb46aaa13812cb8b630)
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>
405e26fb6fSJordan K. Hubbard #include <sys/buf.h>
41aad9af2bSBruce Evans #include <sys/proc.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>
55aa855a59SPeter Wemm #include <sys/module.h>
56d66a5066SPeter Wemm #include <machine/cpu.h>
57d66a5066SPeter Wemm 
58d66a5066SPeter Wemm #include <i386/linux/linux.h>
59d66a5066SPeter Wemm #include <i386/linux/linux_proto.h>
60e1743d02SSøren Schmidt 
61ecbb00a2SDoug Rabson static int	linux_fixup __P((long **stack_base,
62303b270bSEivind Eklund 				 struct image_params *iparams));
63ecbb00a2SDoug Rabson static int	elf_linux_fixup __P((long **stack_base,
64303b270bSEivind Eklund 				     struct image_params *iparams));
65303b270bSEivind Eklund static void	linux_prepsyscall __P((struct trapframe *tf, int *args,
66303b270bSEivind Eklund 				       u_int *code, caddr_t *params));
67303b270bSEivind Eklund static void     linux_sendsig __P((sig_t catcher, int sig, int mask,
68303b270bSEivind Eklund 				   u_long code));
69d66a5066SPeter Wemm 
70d66a5066SPeter Wemm /*
71d66a5066SPeter Wemm  * Linux syscalls return negative errno's, we do positive and map them
72d66a5066SPeter Wemm  */
7385f118c8SDmitrij Tejblum static int bsd_to_linux_errno[ELAST + 1] = {
74d66a5066SPeter Wemm   	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
75d66a5066SPeter Wemm  	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
76d66a5066SPeter Wemm  	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
77d66a5066SPeter Wemm  	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
78d66a5066SPeter Wemm  	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
79d66a5066SPeter Wemm 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
80d66a5066SPeter Wemm 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
81d66a5066SPeter Wemm 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
8285f118c8SDmitrij Tejblum   	-6, -6, -43, -42, -75, -6, -84
83d66a5066SPeter Wemm };
84d66a5066SPeter Wemm 
85d66a5066SPeter Wemm int bsd_to_linux_signal[NSIG] = {
86d66a5066SPeter Wemm 	0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT,
87d66a5066SPeter Wemm 	LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0,
88d66a5066SPeter Wemm 	LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV,
89d66a5066SPeter Wemm 	0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM,
90d66a5066SPeter Wemm 	LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT,
91d66a5066SPeter Wemm 	LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO,
92d66a5066SPeter Wemm 	LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF,
93d66a5066SPeter Wemm 	LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2
94d66a5066SPeter Wemm };
95d66a5066SPeter Wemm 
96d66a5066SPeter Wemm int linux_to_bsd_signal[LINUX_NSIG] = {
9798fd9ce8SJohn Fieber 	0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS,
98d66a5066SPeter Wemm 	SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM,
9998fd9ce8SJohn Fieber 	SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG,
10098fd9ce8SJohn Fieber 	SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGURG, 0
101d66a5066SPeter Wemm };
102d66a5066SPeter Wemm 
103288078beSEivind Eklund /*
104288078beSEivind Eklund  * If FreeBSD & Linux have a difference of opinion about what a trap
105288078beSEivind Eklund  * means, deal with it here.
106288078beSEivind Eklund  */
107288078beSEivind Eklund static int
108288078beSEivind Eklund translate_traps(int signal, int trap_code)
109288078beSEivind Eklund {
110d563a53aSEivind Eklund 	if (signal != SIGBUS)
111d563a53aSEivind Eklund 		return signal;
112288078beSEivind Eklund 	switch (trap_code) {
113288078beSEivind Eklund 	case T_PROTFLT:
114288078beSEivind Eklund 	case T_TSSFLT:
115288078beSEivind Eklund 	case T_DOUBLEFLT:
116288078beSEivind Eklund 	case T_PAGEFLT:
117288078beSEivind Eklund 		return SIGSEGV;
118288078beSEivind Eklund 	default:
119288078beSEivind Eklund 		return signal;
120288078beSEivind Eklund 	}
121288078beSEivind Eklund }
122288078beSEivind Eklund 
123303b270bSEivind Eklund static int
124ecbb00a2SDoug Rabson linux_fixup(long **stack_base, struct image_params *imgp)
125d66a5066SPeter Wemm {
126ecbb00a2SDoug Rabson 	long *argv, *envp;
127d66a5066SPeter Wemm 
128d66a5066SPeter Wemm 	argv = *stack_base;
129d66a5066SPeter Wemm 	envp = *stack_base + (imgp->argc + 1);
130d66a5066SPeter Wemm 	(*stack_base)--;
13186a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)envp;
132d66a5066SPeter Wemm 	(*stack_base)--;
13386a14a7aSBruce Evans 	**stack_base = (intptr_t)(void *)argv;
134d66a5066SPeter Wemm 	(*stack_base)--;
13586a14a7aSBruce Evans 	**stack_base = imgp->argc;
136e1743d02SSøren Schmidt 	return 0;
137d66a5066SPeter Wemm }
138d66a5066SPeter Wemm 
139303b270bSEivind Eklund static int
140ecbb00a2SDoug Rabson elf_linux_fixup(long **stack_base, struct image_params *imgp)
141e1743d02SSøren Schmidt {
142e1743d02SSøren Schmidt 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
143ecbb00a2SDoug Rabson 	long *pos;
144d66a5066SPeter Wemm 
145e1743d02SSøren Schmidt 	pos = *stack_base + (imgp->argc + imgp->envc + 2);
146e1743d02SSøren Schmidt 
147e1743d02SSøren Schmidt 	if (args->trace) {
148e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
149e1743d02SSøren Schmidt 	}
150e1743d02SSøren Schmidt 	if (args->execfd != -1) {
151e1743d02SSøren Schmidt 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
152e1743d02SSøren Schmidt 	}
153e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
154e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
155e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
156e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
157e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
158e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
159e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
160e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_cred->p_ruid);
161e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_cred->p_svuid);
162e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_cred->p_rgid);
163e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_cred->p_svgid);
164e1743d02SSøren Schmidt 	AUXARGS_ENTRY(pos, AT_NULL, 0);
165e1743d02SSøren Schmidt 
166e1743d02SSøren Schmidt 	free(imgp->auxargs, M_TEMP);
167e1743d02SSøren Schmidt 	imgp->auxargs = NULL;
168e1743d02SSøren Schmidt 
169e1743d02SSøren Schmidt 	(*stack_base)--;
170ecbb00a2SDoug Rabson 	**stack_base = (long)imgp->argc;
171e1743d02SSøren Schmidt 	return 0;
172e1743d02SSøren Schmidt }
173d66a5066SPeter Wemm 
174d66a5066SPeter Wemm extern int _ucodesel, _udatasel;
175d66a5066SPeter Wemm 
176d66a5066SPeter Wemm /*
177d66a5066SPeter Wemm  * Send an interrupt to process.
178d66a5066SPeter Wemm  *
179d66a5066SPeter Wemm  * Stack is set up to allow sigcode stored
180d66a5066SPeter Wemm  * in u. to call routine, followed by kcall
181d66a5066SPeter Wemm  * to sigreturn routine below.  After sigreturn
182d66a5066SPeter Wemm  * resets the signal mask, the stack, and the
183d66a5066SPeter Wemm  * frame pointer, it returns to the user
184d66a5066SPeter Wemm  * specified pc, psl.
185d66a5066SPeter Wemm  */
186d66a5066SPeter Wemm 
187303b270bSEivind Eklund static void
188b36546f6SPeter Wemm linux_sendsig(sig_t catcher, int sig, int mask, u_long code)
189d66a5066SPeter Wemm {
190d66a5066SPeter Wemm 	register struct proc *p = curproc;
191213fdd80SPeter Wemm 	register struct trapframe *regs;
192d66a5066SPeter Wemm 	struct linux_sigframe *fp, frame;
193d66a5066SPeter Wemm 	struct sigacts *psp = p->p_sigacts;
194d66a5066SPeter Wemm 	int oonstack;
195d66a5066SPeter Wemm 
196d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
197d66a5066SPeter Wemm 	oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
198d66a5066SPeter Wemm 
199d66a5066SPeter Wemm #ifdef DEBUG
200e4e6ae13SBruce Evans 	printf("Linux-emul(%ld): linux_sendsig(%p, %d, %d, %lu)\n",
201e4e6ae13SBruce Evans 	    (long)p->p_pid, catcher, sig, mask, code);
202d66a5066SPeter Wemm #endif
203d66a5066SPeter Wemm 	/*
204d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
205d66a5066SPeter Wemm 	 */
206d66a5066SPeter Wemm 	if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
207d66a5066SPeter Wemm 	    (psp->ps_sigonstack & sigmask(sig))) {
208d66a5066SPeter Wemm 		fp = (struct linux_sigframe *)(psp->ps_sigstk.ss_sp +
209d66a5066SPeter Wemm 		    psp->ps_sigstk.ss_size - sizeof(struct linux_sigframe));
210d66a5066SPeter Wemm 		psp->ps_sigstk.ss_flags |= SS_ONSTACK;
211d66a5066SPeter Wemm 	} else {
212213fdd80SPeter Wemm 		fp = (struct linux_sigframe *)regs->tf_esp - 1;
213d66a5066SPeter Wemm 	}
214d66a5066SPeter Wemm 
215d66a5066SPeter Wemm 	/*
216d66a5066SPeter Wemm 	 * grow() will return FALSE if the fp will not fit inside the stack
217d66a5066SPeter Wemm 	 *	and the stack can not be grown. useracc will return FALSE
218d66a5066SPeter Wemm 	 *	if access is denied.
219d66a5066SPeter Wemm 	 */
2206626c604SJulian Elischer 	if ((grow_stack (p, (int)fp) == FALSE) ||
221d66a5066SPeter Wemm 	    (useracc((caddr_t)fp, sizeof (struct linux_sigframe), B_WRITE) == FALSE)) {
222d66a5066SPeter Wemm 		/*
223d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
224d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
225d66a5066SPeter Wemm 		 */
226d66a5066SPeter Wemm 		SIGACTION(p, SIGILL) = SIG_DFL;
227d66a5066SPeter Wemm 		sig = sigmask(SIGILL);
228d66a5066SPeter Wemm 		p->p_sigignore &= ~sig;
229d66a5066SPeter Wemm 		p->p_sigcatch &= ~sig;
230d66a5066SPeter Wemm 		p->p_sigmask &= ~sig;
231d66a5066SPeter Wemm 		psignal(p, SIGILL);
232d66a5066SPeter Wemm 		return;
233d66a5066SPeter Wemm 	}
234d66a5066SPeter Wemm 
235d66a5066SPeter Wemm 	/*
236d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
237d66a5066SPeter Wemm 	 */
238d66a5066SPeter Wemm 	if (p->p_sysent->sv_sigtbl) {
239d66a5066SPeter Wemm 		if (sig < p->p_sysent->sv_sigsize)
240d66a5066SPeter Wemm 			sig = p->p_sysent->sv_sigtbl[sig];
241d66a5066SPeter Wemm 		else
242d66a5066SPeter Wemm 			sig = p->p_sysent->sv_sigsize + 1;
243d66a5066SPeter Wemm 	}
244d66a5066SPeter Wemm 
245d66a5066SPeter Wemm 	frame.sf_handler = catcher;
246d66a5066SPeter Wemm 	frame.sf_sig = sig;
247d66a5066SPeter Wemm 
248d66a5066SPeter Wemm 	/*
249d66a5066SPeter Wemm 	 * Build the signal context to be used by sigreturn.
250d66a5066SPeter Wemm 	 */
251d66a5066SPeter Wemm 	frame.sf_sc.sc_mask   = mask;
2525206bca1SLuoqi Chen 	frame.sf_sc.sc_gs     = rgs();
2535206bca1SLuoqi Chen 	frame.sf_sc.sc_fs     = regs->tf_fs;
254213fdd80SPeter Wemm 	frame.sf_sc.sc_es     = regs->tf_es;
255213fdd80SPeter Wemm 	frame.sf_sc.sc_ds     = regs->tf_ds;
256213fdd80SPeter Wemm 	frame.sf_sc.sc_edi    = regs->tf_edi;
257213fdd80SPeter Wemm 	frame.sf_sc.sc_esi    = regs->tf_esi;
258213fdd80SPeter Wemm 	frame.sf_sc.sc_ebp    = regs->tf_ebp;
259213fdd80SPeter Wemm 	frame.sf_sc.sc_ebx    = regs->tf_ebx;
260213fdd80SPeter Wemm 	frame.sf_sc.sc_edx    = regs->tf_edx;
261213fdd80SPeter Wemm 	frame.sf_sc.sc_ecx    = regs->tf_ecx;
262213fdd80SPeter Wemm 	frame.sf_sc.sc_eax    = regs->tf_eax;
263213fdd80SPeter Wemm 	frame.sf_sc.sc_eip    = regs->tf_eip;
264213fdd80SPeter Wemm 	frame.sf_sc.sc_cs     = regs->tf_cs;
265213fdd80SPeter Wemm 	frame.sf_sc.sc_eflags = regs->tf_eflags;
266213fdd80SPeter Wemm 	frame.sf_sc.sc_esp_at_signal = regs->tf_esp;
267213fdd80SPeter Wemm 	frame.sf_sc.sc_ss     = regs->tf_ss;
268213fdd80SPeter Wemm 	frame.sf_sc.sc_err    = regs->tf_err;
269d66a5066SPeter Wemm 	frame.sf_sc.sc_trapno = code;	/* XXX ???? */
270d66a5066SPeter Wemm 
271d66a5066SPeter Wemm 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
272d66a5066SPeter Wemm 		/*
273d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
274d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
275d66a5066SPeter Wemm 		 */
276d66a5066SPeter Wemm 		sigexit(p, SIGILL);
277d66a5066SPeter Wemm 		/* NOTREACHED */
278d66a5066SPeter Wemm 	}
279d66a5066SPeter Wemm 
280d66a5066SPeter Wemm 	/*
281d66a5066SPeter Wemm 	 * Build context to run handler in.
282d66a5066SPeter Wemm 	 */
283213fdd80SPeter Wemm 	regs->tf_esp = (int)fp;
2844c56fcdeSBruce Evans 	regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
285213fdd80SPeter Wemm 	regs->tf_eflags &= ~PSL_VM;
286213fdd80SPeter Wemm 	regs->tf_cs = _ucodesel;
287213fdd80SPeter Wemm 	regs->tf_ds = _udatasel;
288213fdd80SPeter Wemm 	regs->tf_es = _udatasel;
2895206bca1SLuoqi Chen 	regs->tf_fs = _udatasel;
290213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
291d66a5066SPeter Wemm }
292d66a5066SPeter Wemm 
293d66a5066SPeter Wemm /*
294d66a5066SPeter Wemm  * System call to cleanup state after a signal
295d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
296d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
297d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
298d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
299d66a5066SPeter Wemm  * make sure that the user has not modified the
300d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
301d66a5066SPeter Wemm  * a machine fault.
302d66a5066SPeter Wemm  */
303d66a5066SPeter Wemm int
304cb226aaaSPoul-Henning Kamp linux_sigreturn(p, args)
305d66a5066SPeter Wemm 	struct proc *p;
306d66a5066SPeter Wemm 	struct linux_sigreturn_args *args;
307d66a5066SPeter Wemm {
308d66a5066SPeter Wemm 	struct linux_sigcontext *scp, context;
309213fdd80SPeter Wemm 	register struct trapframe *regs;
310d66a5066SPeter Wemm 	int eflags;
311d66a5066SPeter Wemm 
312d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
313d66a5066SPeter Wemm 
314d66a5066SPeter Wemm #ifdef DEBUG
315e4e6ae13SBruce Evans 	printf("Linux-emul(%ld): linux_sigreturn(%p)\n",
316e4e6ae13SBruce Evans 	    (long)p->p_pid, (void *)args->scp);
317d66a5066SPeter Wemm #endif
318d66a5066SPeter Wemm 	/*
319d66a5066SPeter Wemm 	 * The trampoline code hands us the context.
320d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
321d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
322d66a5066SPeter Wemm 	 */
323ecbb00a2SDoug Rabson 	scp = SCARG(args,scp);
324d66a5066SPeter Wemm 	if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
325d66a5066SPeter Wemm 		return (EFAULT);
326d66a5066SPeter Wemm 
327d66a5066SPeter Wemm 	/*
328d66a5066SPeter Wemm 	 * Check for security violations.
329d66a5066SPeter Wemm 	 */
330d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
331d66a5066SPeter Wemm 	eflags = context.sc_eflags;
332d66a5066SPeter Wemm 	/*
333d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
334d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
335d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
336d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
337d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
338d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
339d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
340d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
341d66a5066SPeter Wemm 	 */
342213fdd80SPeter Wemm 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
343d66a5066SPeter Wemm     		return(EINVAL);
344d66a5066SPeter Wemm 	}
345d66a5066SPeter Wemm 
346d66a5066SPeter Wemm 	/*
347d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
348d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
349d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
350d66a5066SPeter Wemm 	 */
35140d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
352d66a5066SPeter Wemm 	if (!CS_SECURE(context.sc_cs)) {
353d66a5066SPeter Wemm 		trapsignal(p, SIGBUS, T_PROTFLT);
354d66a5066SPeter Wemm 		return(EINVAL);
355d66a5066SPeter Wemm 	}
356d66a5066SPeter Wemm 
357d66a5066SPeter Wemm 	p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
358d66a5066SPeter Wemm 	p->p_sigmask = context.sc_mask &~
359d66a5066SPeter Wemm 		(sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
360d66a5066SPeter Wemm 	/*
361d66a5066SPeter Wemm 	 * Restore signal context.
362d66a5066SPeter Wemm 	 */
3635206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
3645206bca1SLuoqi Chen 	regs->tf_fs     = context.sc_fs;
365213fdd80SPeter Wemm 	regs->tf_es     = context.sc_es;
366213fdd80SPeter Wemm 	regs->tf_ds     = context.sc_ds;
367213fdd80SPeter Wemm 	regs->tf_edi    = context.sc_edi;
368213fdd80SPeter Wemm 	regs->tf_esi    = context.sc_esi;
369213fdd80SPeter Wemm 	regs->tf_ebp    = context.sc_ebp;
370213fdd80SPeter Wemm 	regs->tf_ebx    = context.sc_ebx;
371213fdd80SPeter Wemm 	regs->tf_edx    = context.sc_edx;
372213fdd80SPeter Wemm 	regs->tf_ecx    = context.sc_ecx;
373213fdd80SPeter Wemm 	regs->tf_eax    = context.sc_eax;
374213fdd80SPeter Wemm 	regs->tf_eip    = context.sc_eip;
375213fdd80SPeter Wemm 	regs->tf_cs     = context.sc_cs;
376213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
377213fdd80SPeter Wemm 	regs->tf_esp    = context.sc_esp_at_signal;
378213fdd80SPeter Wemm 	regs->tf_ss     = context.sc_ss;
379d66a5066SPeter Wemm 
380d66a5066SPeter Wemm 	return (EJUSTRETURN);
381d66a5066SPeter Wemm }
382d66a5066SPeter Wemm 
383303b270bSEivind Eklund static void
384d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
385d66a5066SPeter Wemm {
386d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
387d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
388d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
389d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
390d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
391d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
392d66a5066SPeter Wemm }
393d66a5066SPeter Wemm 
394d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
395e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
396d66a5066SPeter Wemm 	linux_sysent,
397d66a5066SPeter Wemm 	0xff,
398d66a5066SPeter Wemm 	NSIG,
399d66a5066SPeter Wemm 	bsd_to_linux_signal,
40085f118c8SDmitrij Tejblum 	ELAST + 1,
401d66a5066SPeter Wemm 	bsd_to_linux_errno,
402288078beSEivind Eklund 	translate_traps,
403d66a5066SPeter Wemm 	linux_fixup,
404d66a5066SPeter Wemm 	linux_sendsig,
405d66a5066SPeter Wemm 	linux_sigcode,
406d66a5066SPeter Wemm 	&linux_szsigcode,
407d66a5066SPeter Wemm 	linux_prepsyscall,
40822d4b0fbSJohn Polstra 	"Linux a.out",
40922d4b0fbSJohn Polstra 	aout_coredump
410d66a5066SPeter Wemm };
411e1743d02SSøren Schmidt 
412e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
413e1743d02SSøren Schmidt         LINUX_SYS_MAXSYSCALL,
414e1743d02SSøren Schmidt         linux_sysent,
415e1743d02SSøren Schmidt         0xff,
416e1743d02SSøren Schmidt         NSIG,
417e1743d02SSøren Schmidt         bsd_to_linux_signal,
41885f118c8SDmitrij Tejblum         ELAST + 1,
419e1743d02SSøren Schmidt         bsd_to_linux_errno,
420288078beSEivind Eklund         translate_traps,
421e1743d02SSøren Schmidt         elf_linux_fixup,
422e1743d02SSøren Schmidt         linux_sendsig,
423e1743d02SSøren Schmidt         linux_sigcode,
424e1743d02SSøren Schmidt         &linux_szsigcode,
425e1743d02SSøren Schmidt         linux_prepsyscall,
42622d4b0fbSJohn Polstra 	"Linux ELF",
42722d4b0fbSJohn Polstra 	elf_coredump
428e1743d02SSøren Schmidt };
429e1743d02SSøren Schmidt 
430514058dcSAlexander Langer static 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 
437514058dcSAlexander Langer static 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 
444514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
445514058dcSAlexander Langer 					&linux_brand,
446514058dcSAlexander Langer 					&linux_glibc2brand,
447514058dcSAlexander Langer 					NULL
448514058dcSAlexander Langer 				};
449514058dcSAlexander Langer 
450aa855a59SPeter Wemm static int
451c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
452d30ea4f5SPeter Wemm {
453514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
454514058dcSAlexander Langer 	int error;
455514058dcSAlexander Langer 
456514058dcSAlexander Langer 	error = 0;
457514058dcSAlexander Langer 
458aa855a59SPeter Wemm 	switch(type) {
459aa855a59SPeter Wemm 	case MOD_LOAD:
460aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
461aa855a59SPeter Wemm 		    ++brandinfo)
462514058dcSAlexander Langer 			if (elf_insert_brand_entry(*brandinfo) < 0)
463aa855a59SPeter Wemm 				error = EINVAL;
464514058dcSAlexander Langer 		if (error)
465d30ea4f5SPeter Wemm 			printf("cannot insert Linux elf brand handler\n");
466d30ea4f5SPeter Wemm 		else if (bootverbose)
467d30ea4f5SPeter Wemm 			printf("Linux-ELF exec handler installed\n");
468aa855a59SPeter Wemm 		break;
469aa855a59SPeter Wemm 	case MOD_UNLOAD:
470aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
471aa855a59SPeter Wemm 		    ++brandinfo)
472d2758342SMark Newton 			if (elf_brand_inuse(*brandinfo)) {
473d2758342SMark Newton 				error = EBUSY;
474d2758342SMark Newton 			}
475d2758342SMark Newton 
476d2758342SMark Newton 		if (error == 0) {
477d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
478d2758342SMark Newton 			    *brandinfo != NULL; ++brandinfo)
479aa855a59SPeter Wemm 				if (elf_remove_brand_entry(*brandinfo) < 0)
480aa855a59SPeter Wemm 					error = EINVAL;
481d2758342SMark Newton 		}
482aa855a59SPeter Wemm 		if (error)
483aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
484aa855a59SPeter Wemm 		else if (bootverbose)
485aa855a59SPeter Wemm 			printf("Linux-elf exec handler removed\n");
486aa855a59SPeter Wemm 		break;
487aa855a59SPeter Wemm 	default:
488aa855a59SPeter Wemm 		break;
489d30ea4f5SPeter Wemm 	}
490aa855a59SPeter Wemm 	return error;
491aa855a59SPeter Wemm }
492aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
493aa855a59SPeter Wemm 	"linuxelf",
494aa855a59SPeter Wemm 	linux_elf_modevent,
495aa855a59SPeter Wemm 	0
496aa855a59SPeter Wemm };
497aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
498