xref: /freebsd/sys/i386/linux/linux_sysvec.c (revision 645682fd40b5855a1dfbca5ddb330dda7cf5ddc0)
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));
67956d3333SMarcel Moolenaar static void     linux_sendsig __P((sig_t catcher, int sig, sigset_t *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 
85956d3333SMarcel Moolenaar int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
86956d3333SMarcel Moolenaar 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
87956d3333SMarcel Moolenaar 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
88956d3333SMarcel Moolenaar 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 0,
89956d3333SMarcel Moolenaar 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
90956d3333SMarcel Moolenaar 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
91956d3333SMarcel Moolenaar 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
92956d3333SMarcel Moolenaar 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
93956d3333SMarcel Moolenaar 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
94d66a5066SPeter Wemm };
95d66a5066SPeter Wemm 
96956d3333SMarcel Moolenaar int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
97956d3333SMarcel Moolenaar 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
98956d3333SMarcel Moolenaar 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
99956d3333SMarcel Moolenaar 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
100956d3333SMarcel Moolenaar 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
101956d3333SMarcel Moolenaar 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
102956d3333SMarcel Moolenaar 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
103956d3333SMarcel Moolenaar 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
104956d3333SMarcel Moolenaar 	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
192956d3333SMarcel Moolenaar linux_sendsig(sig_t catcher, int sig, sigset_t *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;
201645682fdSLuoqi Chen 	oonstack = p->p_sigstk.ss_flags & SS_ONSTACK;
202d66a5066SPeter Wemm 
203d66a5066SPeter Wemm #ifdef DEBUG
204956d3333SMarcel Moolenaar 	printf("Linux-emul(%ld): linux_sendsig(%p, %d, %p, %lu)\n",
205956d3333SMarcel Moolenaar 	    (long)p->p_pid, catcher, sig, (void*)mask, code);
206d66a5066SPeter Wemm #endif
207d66a5066SPeter Wemm 	/*
208d66a5066SPeter Wemm 	 * Allocate space for the signal handler context.
209d66a5066SPeter Wemm 	 */
210645682fdSLuoqi Chen 	if ((p->p_flag & P_ALTSTACK) && !oonstack &&
211956d3333SMarcel Moolenaar 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
212645682fdSLuoqi Chen 		fp = (struct linux_sigframe *)(p->p_sigstk.ss_sp +
213645682fdSLuoqi Chen 		    p->p_sigstk.ss_size - sizeof(struct linux_sigframe));
214645682fdSLuoqi Chen 		p->p_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 	if ((grow_stack (p, (int)fp) == FALSE) ||
225d66a5066SPeter Wemm 	    (useracc((caddr_t)fp, sizeof (struct linux_sigframe), B_WRITE) == FALSE)) {
226d66a5066SPeter Wemm 		/*
227d66a5066SPeter Wemm 		 * Process has trashed its stack; give it an illegal
228d66a5066SPeter Wemm 		 * instruction to halt it in its tracks.
229d66a5066SPeter Wemm 		 */
230d66a5066SPeter Wemm 		SIGACTION(p, SIGILL) = SIG_DFL;
231956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigignore, SIGILL);
232956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigcatch, SIGILL);
233956d3333SMarcel Moolenaar 		SIGDELSET(p->p_sigmask, SIGILL);
234d66a5066SPeter Wemm 		psignal(p, SIGILL);
235d66a5066SPeter Wemm 		return;
236d66a5066SPeter Wemm 	}
237d66a5066SPeter Wemm 
238d66a5066SPeter Wemm 	/*
239d66a5066SPeter Wemm 	 * Build the argument list for the signal handler.
240d66a5066SPeter Wemm 	 */
241956d3333SMarcel Moolenaar 	if (p->p_sysent->sv_sigtbl)
242956d3333SMarcel Moolenaar 		if (sig <= p->p_sysent->sv_sigsize)
243956d3333SMarcel Moolenaar 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
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 	 */
251956d3333SMarcel Moolenaar 	frame.sf_sc.sc_mask   = mask->__bits[0];
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;
290645682fdSLuoqi Chen 	load_gs(_udatasel);
291213fdd80SPeter Wemm 	regs->tf_ss = _udatasel;
292d66a5066SPeter Wemm }
293d66a5066SPeter Wemm 
294d66a5066SPeter Wemm /*
295d66a5066SPeter Wemm  * System call to cleanup state after a signal
296d66a5066SPeter Wemm  * has been taken.  Reset signal mask and
297d66a5066SPeter Wemm  * stack state from context left by sendsig (above).
298d66a5066SPeter Wemm  * Return to previous pc and psl as specified by
299d66a5066SPeter Wemm  * context left by sendsig. Check carefully to
300d66a5066SPeter Wemm  * make sure that the user has not modified the
301d66a5066SPeter Wemm  * psl to gain improper privileges or to cause
302d66a5066SPeter Wemm  * a machine fault.
303d66a5066SPeter Wemm  */
304d66a5066SPeter Wemm int
305cb226aaaSPoul-Henning Kamp linux_sigreturn(p, args)
306d66a5066SPeter Wemm 	struct proc *p;
307d66a5066SPeter Wemm 	struct linux_sigreturn_args *args;
308d66a5066SPeter Wemm {
309d66a5066SPeter Wemm 	struct linux_sigcontext *scp, context;
310213fdd80SPeter Wemm 	register struct trapframe *regs;
311d66a5066SPeter Wemm 	int eflags;
312d66a5066SPeter Wemm 
313d66a5066SPeter Wemm 	regs = p->p_md.md_regs;
314d66a5066SPeter Wemm 
315d66a5066SPeter Wemm #ifdef DEBUG
316e4e6ae13SBruce Evans 	printf("Linux-emul(%ld): linux_sigreturn(%p)\n",
317e4e6ae13SBruce Evans 	    (long)p->p_pid, (void *)args->scp);
318d66a5066SPeter Wemm #endif
319d66a5066SPeter Wemm 	/*
320d66a5066SPeter Wemm 	 * The trampoline code hands us the context.
321d66a5066SPeter Wemm 	 * It is unsafe to keep track of it ourselves, in the event that a
322d66a5066SPeter Wemm 	 * program jumps out of a signal handler.
323d66a5066SPeter Wemm 	 */
324ecbb00a2SDoug Rabson 	scp = SCARG(args,scp);
325d66a5066SPeter Wemm 	if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
326d66a5066SPeter Wemm 		return (EFAULT);
327d66a5066SPeter Wemm 
328d66a5066SPeter Wemm 	/*
329d66a5066SPeter Wemm 	 * Check for security violations.
330d66a5066SPeter Wemm 	 */
331d66a5066SPeter Wemm #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
332d66a5066SPeter Wemm 	eflags = context.sc_eflags;
333d66a5066SPeter Wemm 	/*
334d66a5066SPeter Wemm 	 * XXX do allow users to change the privileged flag PSL_RF.  The
335d66a5066SPeter Wemm 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
336d66a5066SPeter Wemm 	 * sometimes set it there too.  tf_eflags is kept in the signal
337d66a5066SPeter Wemm 	 * context during signal handling and there is no other place
338d66a5066SPeter Wemm 	 * to remember it, so the PSL_RF bit may be corrupted by the
339d66a5066SPeter Wemm 	 * signal handler without us knowing.  Corruption of the PSL_RF
340d66a5066SPeter Wemm 	 * bit at worst causes one more or one less debugger trap, so
341d66a5066SPeter Wemm 	 * allowing it is fairly harmless.
342d66a5066SPeter Wemm 	 */
343213fdd80SPeter Wemm 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) {
344d66a5066SPeter Wemm     		return(EINVAL);
345d66a5066SPeter Wemm 	}
346d66a5066SPeter Wemm 
347d66a5066SPeter Wemm 	/*
348d66a5066SPeter Wemm 	 * Don't allow users to load a valid privileged %cs.  Let the
349d66a5066SPeter Wemm 	 * hardware check for invalid selectors, excess privilege in
350d66a5066SPeter Wemm 	 * other selectors, invalid %eip's and invalid %esp's.
351d66a5066SPeter Wemm 	 */
35240d50994SPhilippe Charnier #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
353d66a5066SPeter Wemm 	if (!CS_SECURE(context.sc_cs)) {
354d66a5066SPeter Wemm 		trapsignal(p, SIGBUS, T_PROTFLT);
355d66a5066SPeter Wemm 		return(EINVAL);
356d66a5066SPeter Wemm 	}
357d66a5066SPeter Wemm 
358645682fdSLuoqi Chen 	p->p_sigstk.ss_flags &= ~SS_ONSTACK;
359645682fdSLuoqi Chen 	SIGSETOLD(p->p_sigmask, context.sc_mask);
360645682fdSLuoqi Chen 	SIG_CANTMASK(p->p_sigmask);
361956d3333SMarcel Moolenaar 
362d66a5066SPeter Wemm 	/*
363d66a5066SPeter Wemm 	 * Restore signal context.
364d66a5066SPeter Wemm 	 */
3655206bca1SLuoqi Chen 	/* %gs was restored by the trampoline. */
3665206bca1SLuoqi Chen 	regs->tf_fs     = context.sc_fs;
367213fdd80SPeter Wemm 	regs->tf_es     = context.sc_es;
368213fdd80SPeter Wemm 	regs->tf_ds     = context.sc_ds;
369213fdd80SPeter Wemm 	regs->tf_edi    = context.sc_edi;
370213fdd80SPeter Wemm 	regs->tf_esi    = context.sc_esi;
371213fdd80SPeter Wemm 	regs->tf_ebp    = context.sc_ebp;
372213fdd80SPeter Wemm 	regs->tf_ebx    = context.sc_ebx;
373213fdd80SPeter Wemm 	regs->tf_edx    = context.sc_edx;
374213fdd80SPeter Wemm 	regs->tf_ecx    = context.sc_ecx;
375213fdd80SPeter Wemm 	regs->tf_eax    = context.sc_eax;
376213fdd80SPeter Wemm 	regs->tf_eip    = context.sc_eip;
377213fdd80SPeter Wemm 	regs->tf_cs     = context.sc_cs;
378213fdd80SPeter Wemm 	regs->tf_eflags = eflags;
379213fdd80SPeter Wemm 	regs->tf_esp    = context.sc_esp_at_signal;
380213fdd80SPeter Wemm 	regs->tf_ss     = context.sc_ss;
381d66a5066SPeter Wemm 
382d66a5066SPeter Wemm 	return (EJUSTRETURN);
383d66a5066SPeter Wemm }
384d66a5066SPeter Wemm 
385303b270bSEivind Eklund static void
386d66a5066SPeter Wemm linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
387d66a5066SPeter Wemm {
388d66a5066SPeter Wemm 	args[0] = tf->tf_ebx;
389d66a5066SPeter Wemm 	args[1] = tf->tf_ecx;
390d66a5066SPeter Wemm 	args[2] = tf->tf_edx;
391d66a5066SPeter Wemm 	args[3] = tf->tf_esi;
392d66a5066SPeter Wemm 	args[4] = tf->tf_edi;
393d66a5066SPeter Wemm 	*params = NULL;		/* no copyin */
394d66a5066SPeter Wemm }
395d66a5066SPeter Wemm 
396d66a5066SPeter Wemm struct sysentvec linux_sysvec = {
397e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
398d66a5066SPeter Wemm 	linux_sysent,
399d66a5066SPeter Wemm 	0xff,
400956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
401d66a5066SPeter Wemm 	bsd_to_linux_signal,
40285f118c8SDmitrij Tejblum 	ELAST + 1,
403d66a5066SPeter Wemm 	bsd_to_linux_errno,
404288078beSEivind Eklund 	translate_traps,
405d66a5066SPeter Wemm 	linux_fixup,
406d66a5066SPeter Wemm 	linux_sendsig,
407d66a5066SPeter Wemm 	linux_sigcode,
408d66a5066SPeter Wemm 	&linux_szsigcode,
409d66a5066SPeter Wemm 	linux_prepsyscall,
41022d4b0fbSJohn Polstra 	"Linux a.out",
41122d4b0fbSJohn Polstra 	aout_coredump
412d66a5066SPeter Wemm };
413e1743d02SSøren Schmidt 
414e1743d02SSøren Schmidt struct sysentvec elf_linux_sysvec = {
415e1743d02SSøren Schmidt 	LINUX_SYS_MAXSYSCALL,
416e1743d02SSøren Schmidt 	linux_sysent,
417e1743d02SSøren Schmidt 	0xff,
418956d3333SMarcel Moolenaar 	LINUX_SIGTBLSZ,
419e1743d02SSøren Schmidt 	bsd_to_linux_signal,
42085f118c8SDmitrij Tejblum 	ELAST + 1,
421e1743d02SSøren Schmidt 	bsd_to_linux_errno,
422288078beSEivind Eklund 	translate_traps,
423e1743d02SSøren Schmidt 	elf_linux_fixup,
424e1743d02SSøren Schmidt 	linux_sendsig,
425e1743d02SSøren Schmidt 	linux_sigcode,
426e1743d02SSøren Schmidt 	&linux_szsigcode,
427e1743d02SSøren Schmidt 	linux_prepsyscall,
42822d4b0fbSJohn Polstra 	"Linux ELF",
42922d4b0fbSJohn Polstra 	elf_coredump
430e1743d02SSøren Schmidt };
431e1743d02SSøren Schmidt 
432514058dcSAlexander Langer static Elf32_Brandinfo linux_brand = {
433ea5a2b2eSSøren Schmidt 					"Linux",
434ea5a2b2eSSøren Schmidt 					"/compat/linux",
4355cf588ebSPeter Wemm 					"/lib/ld-linux.so.1",
436ea5a2b2eSSøren Schmidt 					&elf_linux_sysvec
4375cf588ebSPeter Wemm 				 };
4385cf588ebSPeter Wemm 
439514058dcSAlexander Langer static Elf32_Brandinfo linux_glibc2brand = {
4404e138a28SMike Smith 					"Linux",
4414e138a28SMike Smith 					"/compat/linux",
4424e138a28SMike Smith 					"/lib/ld-linux.so.2",
4434e138a28SMike Smith 					&elf_linux_sysvec
4444e138a28SMike Smith 				 };
4454e138a28SMike Smith 
446514058dcSAlexander Langer Elf32_Brandinfo *linux_brandlist[] = {
447514058dcSAlexander Langer 					&linux_brand,
448514058dcSAlexander Langer 					&linux_glibc2brand,
449514058dcSAlexander Langer 					NULL
450514058dcSAlexander Langer 				};
451514058dcSAlexander Langer 
452aa855a59SPeter Wemm static int
453c25ded31SBruce Evans linux_elf_modevent(module_t mod, int type, void *data)
454d30ea4f5SPeter Wemm {
455514058dcSAlexander Langer 	Elf32_Brandinfo **brandinfo;
456514058dcSAlexander Langer 	int error;
457514058dcSAlexander Langer 
458514058dcSAlexander Langer 	error = 0;
459514058dcSAlexander Langer 
460aa855a59SPeter Wemm 	switch(type) {
461aa855a59SPeter Wemm 	case MOD_LOAD:
462aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
463aa855a59SPeter Wemm 		    ++brandinfo)
464514058dcSAlexander Langer 			if (elf_insert_brand_entry(*brandinfo) < 0)
465aa855a59SPeter Wemm 				error = EINVAL;
466514058dcSAlexander Langer 		if (error)
467d30ea4f5SPeter Wemm 			printf("cannot insert Linux elf brand handler\n");
468d30ea4f5SPeter Wemm 		else if (bootverbose)
469d30ea4f5SPeter Wemm 			printf("Linux-ELF exec handler installed\n");
470aa855a59SPeter Wemm 		break;
471aa855a59SPeter Wemm 	case MOD_UNLOAD:
472aa855a59SPeter Wemm 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
473aa855a59SPeter Wemm 		    ++brandinfo)
474d2758342SMark Newton 			if (elf_brand_inuse(*brandinfo)) {
475d2758342SMark Newton 				error = EBUSY;
476d2758342SMark Newton 			}
477d2758342SMark Newton 
478d2758342SMark Newton 		if (error == 0) {
479d2758342SMark Newton 			for (brandinfo = &linux_brandlist[0];
480d2758342SMark Newton 			    *brandinfo != NULL; ++brandinfo)
481aa855a59SPeter Wemm 				if (elf_remove_brand_entry(*brandinfo) < 0)
482aa855a59SPeter Wemm 					error = EINVAL;
483d2758342SMark Newton 		}
484aa855a59SPeter Wemm 		if (error)
485aa855a59SPeter Wemm 			printf("Could not deinstall ELF interpreter entry\n");
486aa855a59SPeter Wemm 		else if (bootverbose)
487aa855a59SPeter Wemm 			printf("Linux-elf exec handler removed\n");
488aa855a59SPeter Wemm 		break;
489aa855a59SPeter Wemm 	default:
490aa855a59SPeter Wemm 		break;
491d30ea4f5SPeter Wemm 	}
492aa855a59SPeter Wemm 	return error;
493aa855a59SPeter Wemm }
494aa855a59SPeter Wemm static moduledata_t linux_elf_mod = {
495aa855a59SPeter Wemm 	"linuxelf",
496aa855a59SPeter Wemm 	linux_elf_modevent,
497aa855a59SPeter Wemm 	0
498aa855a59SPeter Wemm };
499aa855a59SPeter Wemm DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
500