xref: /freebsd/sys/amd64/linux32/linux32_sysvec.c (revision ea0fabbc4fcb15d10fbcaad14c405826d5eefea3)
1ea0fabbcSTim J. Robbins /*-
2ea0fabbcSTim J. Robbins  * Copyright (c) 2004 Tim J. Robbins
3ea0fabbcSTim J. Robbins  * Copyright (c) 2003 Peter Wemm
4ea0fabbcSTim J. Robbins  * Copyright (c) 2002 Doug Rabson
5ea0fabbcSTim J. Robbins  * Copyright (c) 1998-1999 Andrew Gallatin
6ea0fabbcSTim J. Robbins  * Copyright (c) 1994-1996 S�ren Schmidt
7ea0fabbcSTim J. Robbins  * All rights reserved.
8ea0fabbcSTim J. Robbins  *
9ea0fabbcSTim J. Robbins  * Redistribution and use in source and binary forms, with or without
10ea0fabbcSTim J. Robbins  * modification, are permitted provided that the following conditions
11ea0fabbcSTim J. Robbins  * are met:
12ea0fabbcSTim J. Robbins  * 1. Redistributions of source code must retain the above copyright
13ea0fabbcSTim J. Robbins  *    notice, this list of conditions and the following disclaimer
14ea0fabbcSTim J. Robbins  *    in this position and unchanged.
15ea0fabbcSTim J. Robbins  * 2. Redistributions in binary form must reproduce the above copyright
16ea0fabbcSTim J. Robbins  *    notice, this list of conditions and the following disclaimer in the
17ea0fabbcSTim J. Robbins  *    documentation and/or other materials provided with the distribution.
18ea0fabbcSTim J. Robbins  * 3. The name of the author may not be used to endorse or promote products
19ea0fabbcSTim J. Robbins  *    derived from this software without specific prior written permission
20ea0fabbcSTim J. Robbins  *
21ea0fabbcSTim J. Robbins  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22ea0fabbcSTim J. Robbins  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23ea0fabbcSTim J. Robbins  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24ea0fabbcSTim J. Robbins  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25ea0fabbcSTim J. Robbins  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26ea0fabbcSTim J. Robbins  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27ea0fabbcSTim J. Robbins  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28ea0fabbcSTim J. Robbins  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29ea0fabbcSTim J. Robbins  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30ea0fabbcSTim J. Robbins  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31ea0fabbcSTim J. Robbins  */
32ea0fabbcSTim J. Robbins 
33ea0fabbcSTim J. Robbins #include <sys/cdefs.h>
34ea0fabbcSTim J. Robbins __FBSDID("$FreeBSD$");
35ea0fabbcSTim J. Robbins 
36ea0fabbcSTim J. Robbins /* XXX we use functions that might not exist. */
37ea0fabbcSTim J. Robbins #include "opt_compat.h"
38ea0fabbcSTim J. Robbins #include "opt_ia32.h"
39ea0fabbcSTim J. Robbins 
40ea0fabbcSTim J. Robbins #ifndef COMPAT_43
41ea0fabbcSTim J. Robbins #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
42ea0fabbcSTim J. Robbins #endif
43ea0fabbcSTim J. Robbins #ifndef IA32
44ea0fabbcSTim J. Robbins #error "Unable to compile Linux-emulator due to missing IA32 option!"
45ea0fabbcSTim J. Robbins #endif
46ea0fabbcSTim J. Robbins 
47ea0fabbcSTim J. Robbins #define	__ELF_WORD_SIZE	32
48ea0fabbcSTim J. Robbins 
49ea0fabbcSTim J. Robbins #include <sys/param.h>
50ea0fabbcSTim J. Robbins #include <sys/systm.h>
51ea0fabbcSTim J. Robbins #include <sys/exec.h>
52ea0fabbcSTim J. Robbins #include <sys/imgact.h>
53ea0fabbcSTim J. Robbins #include <sys/imgact_elf.h>
54ea0fabbcSTim J. Robbins #include <sys/kernel.h>
55ea0fabbcSTim J. Robbins #include <sys/lock.h>
56ea0fabbcSTim J. Robbins #include <sys/malloc.h>
57ea0fabbcSTim J. Robbins #include <sys/module.h>
58ea0fabbcSTim J. Robbins #include <sys/mutex.h>
59ea0fabbcSTim J. Robbins #include <sys/proc.h>
60ea0fabbcSTim J. Robbins #include <sys/signalvar.h>
61ea0fabbcSTim J. Robbins #include <sys/sysctl.h>
62ea0fabbcSTim J. Robbins #include <sys/syscallsubr.h>
63ea0fabbcSTim J. Robbins #include <sys/sysent.h>
64ea0fabbcSTim J. Robbins #include <sys/sysproto.h>
65ea0fabbcSTim J. Robbins #include <sys/user.h>
66ea0fabbcSTim J. Robbins #include <sys/vnode.h>
67ea0fabbcSTim J. Robbins 
68ea0fabbcSTim J. Robbins #include <vm/vm.h>
69ea0fabbcSTim J. Robbins #include <vm/pmap.h>
70ea0fabbcSTim J. Robbins #include <vm/vm_extern.h>
71ea0fabbcSTim J. Robbins #include <vm/vm_map.h>
72ea0fabbcSTim J. Robbins #include <vm/vm_object.h>
73ea0fabbcSTim J. Robbins #include <vm/vm_page.h>
74ea0fabbcSTim J. Robbins #include <vm/vm_param.h>
75ea0fabbcSTim J. Robbins 
76ea0fabbcSTim J. Robbins #include <machine/cpu.h>
77ea0fabbcSTim J. Robbins #include <machine/md_var.h>
78ea0fabbcSTim J. Robbins #include <machine/specialreg.h>
79ea0fabbcSTim J. Robbins 
80ea0fabbcSTim J. Robbins #include <amd64/linux32/linux.h>
81ea0fabbcSTim J. Robbins #include <amd64/linux32/linux32_proto.h>
82ea0fabbcSTim J. Robbins #include <compat/linux/linux_mib.h>
83ea0fabbcSTim J. Robbins #include <compat/linux/linux_signal.h>
84ea0fabbcSTim J. Robbins #include <compat/linux/linux_util.h>
85ea0fabbcSTim J. Robbins 
86ea0fabbcSTim J. Robbins MODULE_VERSION(linux, 1);
87ea0fabbcSTim J. Robbins MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
88ea0fabbcSTim J. Robbins MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
89ea0fabbcSTim J. Robbins MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
90ea0fabbcSTim J. Robbins 
91ea0fabbcSTim J. Robbins MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
92ea0fabbcSTim J. Robbins 
93ea0fabbcSTim J. Robbins #define	AUXARGS_ENTRY_32(pos, id, val)	\
94ea0fabbcSTim J. Robbins 	do {				\
95ea0fabbcSTim J. Robbins 		suword32(pos++, id);	\
96ea0fabbcSTim J. Robbins 		suword32(pos++, val);	\
97ea0fabbcSTim J. Robbins 	} while (0)
98ea0fabbcSTim J. Robbins 
99ea0fabbcSTim J. Robbins #if BYTE_ORDER == LITTLE_ENDIAN
100ea0fabbcSTim J. Robbins #define SHELLMAGIC      0x2123 /* #! */
101ea0fabbcSTim J. Robbins #else
102ea0fabbcSTim J. Robbins #define SHELLMAGIC      0x2321
103ea0fabbcSTim J. Robbins #endif
104ea0fabbcSTim J. Robbins 
105ea0fabbcSTim J. Robbins /*
106ea0fabbcSTim J. Robbins  * Allow the sendsig functions to use the ldebug() facility
107ea0fabbcSTim J. Robbins  * even though they are not syscalls themselves. Map them
108ea0fabbcSTim J. Robbins  * to syscall 0. This is slightly less bogus than using
109ea0fabbcSTim J. Robbins  * ldebug(sigreturn).
110ea0fabbcSTim J. Robbins  */
111ea0fabbcSTim J. Robbins #define	LINUX_SYS_linux_rt_sendsig	0
112ea0fabbcSTim J. Robbins #define	LINUX_SYS_linux_sendsig		0
113ea0fabbcSTim J. Robbins 
114ea0fabbcSTim J. Robbins extern char linux_sigcode[];
115ea0fabbcSTim J. Robbins extern int linux_szsigcode;
116ea0fabbcSTim J. Robbins 
117ea0fabbcSTim J. Robbins extern struct sysent linux_sysent[LINUX_SYS_MAXSYSCALL];
118ea0fabbcSTim J. Robbins 
119ea0fabbcSTim J. Robbins SET_DECLARE(linux_ioctl_handler_set, struct linux_ioctl_handler);
120ea0fabbcSTim J. Robbins 
121ea0fabbcSTim J. Robbins static int	elf_linux_fixup(register_t **stack_base,
122ea0fabbcSTim J. Robbins 		    struct image_params *iparams);
123ea0fabbcSTim J. Robbins static register_t *linux_copyout_strings(struct image_params *imgp);
124ea0fabbcSTim J. Robbins static void	linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
125ea0fabbcSTim J. Robbins 		    caddr_t *params);
126ea0fabbcSTim J. Robbins static void     linux_sendsig(sig_t catcher, int sig, sigset_t *mask,
127ea0fabbcSTim J. Robbins 		    u_long code);
128ea0fabbcSTim J. Robbins static void	exec_linux_setregs(struct thread *td, u_long entry,
129ea0fabbcSTim J. Robbins 				   u_long stack, u_long ps_strings);
130ea0fabbcSTim J. Robbins static void	linux32_fixlimits(struct image_params *imgp);
131ea0fabbcSTim J. Robbins 
132ea0fabbcSTim J. Robbins /*
133ea0fabbcSTim J. Robbins  * Linux syscalls return negative errno's, we do positive and map them
134ea0fabbcSTim J. Robbins  */
135ea0fabbcSTim J. Robbins static int bsd_to_linux_errno[ELAST + 1] = {
136ea0fabbcSTim J. Robbins 	-0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9,
137ea0fabbcSTim J. Robbins 	-10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
138ea0fabbcSTim J. Robbins 	-20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
139ea0fabbcSTim J. Robbins 	-30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
140ea0fabbcSTim J. Robbins 	-90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
141ea0fabbcSTim J. Robbins 	-100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
142ea0fabbcSTim J. Robbins 	-110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
143ea0fabbcSTim J. Robbins 	-116, -66,  -6,  -6,  -6,  -6,  -6, -37, -38,  -9,
144ea0fabbcSTim J. Robbins 	-6, -6, -43, -42, -75, -6, -84
145ea0fabbcSTim J. Robbins };
146ea0fabbcSTim J. Robbins 
147ea0fabbcSTim J. Robbins int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
148ea0fabbcSTim J. Robbins 	LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
149ea0fabbcSTim J. Robbins 	LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
150ea0fabbcSTim J. Robbins 	LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
151ea0fabbcSTim J. Robbins 	LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
152ea0fabbcSTim J. Robbins 	LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
153ea0fabbcSTim J. Robbins 	LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
154ea0fabbcSTim J. Robbins 	LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, LINUX_SIGWINCH,
155ea0fabbcSTim J. Robbins 	0, LINUX_SIGUSR1, LINUX_SIGUSR2
156ea0fabbcSTim J. Robbins };
157ea0fabbcSTim J. Robbins 
158ea0fabbcSTim J. Robbins int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
159ea0fabbcSTim J. Robbins 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
160ea0fabbcSTim J. Robbins 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
161ea0fabbcSTim J. Robbins 	SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2,
162ea0fabbcSTim J. Robbins 	SIGPIPE, SIGALRM, SIGTERM, SIGBUS,
163ea0fabbcSTim J. Robbins 	SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
164ea0fabbcSTim J. Robbins 	SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
165ea0fabbcSTim J. Robbins 	SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
166ea0fabbcSTim J. Robbins 	SIGIO, SIGURG, SIGSYS
167ea0fabbcSTim J. Robbins };
168ea0fabbcSTim J. Robbins 
169ea0fabbcSTim J. Robbins #define LINUX_T_UNKNOWN  255
170ea0fabbcSTim J. Robbins static int _bsd_to_linux_trapcode[] = {
171ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 0 */
172ea0fabbcSTim J. Robbins 	6,			/* 1  T_PRIVINFLT */
173ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 2 */
174ea0fabbcSTim J. Robbins 	3,			/* 3  T_BPTFLT */
175ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 4 */
176ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 5 */
177ea0fabbcSTim J. Robbins 	16,			/* 6  T_ARITHTRAP */
178ea0fabbcSTim J. Robbins 	254,			/* 7  T_ASTFLT */
179ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 8 */
180ea0fabbcSTim J. Robbins 	13,			/* 9  T_PROTFLT */
181ea0fabbcSTim J. Robbins 	1,			/* 10 T_TRCTRAP */
182ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 11 */
183ea0fabbcSTim J. Robbins 	14,			/* 12 T_PAGEFLT */
184ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 13 */
185ea0fabbcSTim J. Robbins 	17,			/* 14 T_ALIGNFLT */
186ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 15 */
187ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 16 */
188ea0fabbcSTim J. Robbins 	LINUX_T_UNKNOWN,	/* 17 */
189ea0fabbcSTim J. Robbins 	0,			/* 18 T_DIVIDE */
190ea0fabbcSTim J. Robbins 	2,			/* 19 T_NMI */
191ea0fabbcSTim J. Robbins 	4,			/* 20 T_OFLOW */
192ea0fabbcSTim J. Robbins 	5,			/* 21 T_BOUND */
193ea0fabbcSTim J. Robbins 	7,			/* 22 T_DNA */
194ea0fabbcSTim J. Robbins 	8,			/* 23 T_DOUBLEFLT */
195ea0fabbcSTim J. Robbins 	9,			/* 24 T_FPOPFLT */
196ea0fabbcSTim J. Robbins 	10,			/* 25 T_TSSFLT */
197ea0fabbcSTim J. Robbins 	11,			/* 26 T_SEGNPFLT */
198ea0fabbcSTim J. Robbins 	12,			/* 27 T_STKFLT */
199ea0fabbcSTim J. Robbins 	18,			/* 28 T_MCHK */
200ea0fabbcSTim J. Robbins 	19,			/* 29 T_XMMFLT */
201ea0fabbcSTim J. Robbins 	15			/* 30 T_RESERVED */
202ea0fabbcSTim J. Robbins };
203ea0fabbcSTim J. Robbins #define bsd_to_linux_trapcode(code) \
204ea0fabbcSTim J. Robbins     ((code)<sizeof(_bsd_to_linux_trapcode)/sizeof(*_bsd_to_linux_trapcode)? \
205ea0fabbcSTim J. Robbins      _bsd_to_linux_trapcode[(code)]: \
206ea0fabbcSTim J. Robbins      LINUX_T_UNKNOWN)
207ea0fabbcSTim J. Robbins 
208ea0fabbcSTim J. Robbins struct linux32_ps_strings {
209ea0fabbcSTim J. Robbins 	u_int32_t ps_argvstr;	/* first of 0 or more argument strings */
210ea0fabbcSTim J. Robbins 	int	ps_nargvstr;	/* the number of argument strings */
211ea0fabbcSTim J. Robbins 	u_int32_t ps_envstr;	/* first of 0 or more environment strings */
212ea0fabbcSTim J. Robbins 	int	ps_nenvstr;	/* the number of environment strings */
213ea0fabbcSTim J. Robbins };
214ea0fabbcSTim J. Robbins 
215ea0fabbcSTim J. Robbins /*
216ea0fabbcSTim J. Robbins  * If FreeBSD & Linux have a difference of opinion about what a trap
217ea0fabbcSTim J. Robbins  * means, deal with it here.
218ea0fabbcSTim J. Robbins  *
219ea0fabbcSTim J. Robbins  * MPSAFE
220ea0fabbcSTim J. Robbins  */
221ea0fabbcSTim J. Robbins static int
222ea0fabbcSTim J. Robbins translate_traps(int signal, int trap_code)
223ea0fabbcSTim J. Robbins {
224ea0fabbcSTim J. Robbins 	if (signal != SIGBUS)
225ea0fabbcSTim J. Robbins 		return signal;
226ea0fabbcSTim J. Robbins 	switch (trap_code) {
227ea0fabbcSTim J. Robbins 	case T_PROTFLT:
228ea0fabbcSTim J. Robbins 	case T_TSSFLT:
229ea0fabbcSTim J. Robbins 	case T_DOUBLEFLT:
230ea0fabbcSTim J. Robbins 	case T_PAGEFLT:
231ea0fabbcSTim J. Robbins 		return SIGSEGV;
232ea0fabbcSTim J. Robbins 	default:
233ea0fabbcSTim J. Robbins 		return signal;
234ea0fabbcSTim J. Robbins 	}
235ea0fabbcSTim J. Robbins }
236ea0fabbcSTim J. Robbins 
237ea0fabbcSTim J. Robbins static int
238ea0fabbcSTim J. Robbins elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
239ea0fabbcSTim J. Robbins {
240ea0fabbcSTim J. Robbins 	Elf32_Auxargs *args;
241ea0fabbcSTim J. Robbins 	Elf32_Addr *base;
242ea0fabbcSTim J. Robbins 	Elf32_Addr *pos;
243ea0fabbcSTim J. Robbins 
244ea0fabbcSTim J. Robbins 	KASSERT(curthread->td_proc == imgp->proc &&
245ea0fabbcSTim J. Robbins 	    (curthread->td_proc->p_flag & P_SA) == 0,
246ea0fabbcSTim J. Robbins 	    ("unsafe elf_linux_fixup(), should be curproc"));
247ea0fabbcSTim J. Robbins 	base = (Elf32_Addr *)*stack_base;
248ea0fabbcSTim J. Robbins 	args = (Elf32_Auxargs *)imgp->auxargs;
249ea0fabbcSTim J. Robbins 	pos = base + (imgp->argc + imgp->envc + 2);
250ea0fabbcSTim J. Robbins 
251ea0fabbcSTim J. Robbins 	if (args->trace)
252ea0fabbcSTim J. Robbins 		AUXARGS_ENTRY_32(pos, AT_DEBUG, 1);
253ea0fabbcSTim J. Robbins 	if (args->execfd != -1)
254ea0fabbcSTim J. Robbins 		AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
255ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr);
256ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent);
257ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum);
258ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_PAGESZ, args->pagesz);
259ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags);
260ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry);
261ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_BASE, args->base);
262ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
263ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
264ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
265ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
266ea0fabbcSTim J. Robbins 	AUXARGS_ENTRY_32(pos, AT_NULL, 0);
267ea0fabbcSTim J. Robbins 
268ea0fabbcSTim J. Robbins 	free(imgp->auxargs, M_TEMP);
269ea0fabbcSTim J. Robbins 	imgp->auxargs = NULL;
270ea0fabbcSTim J. Robbins 
271ea0fabbcSTim J. Robbins 	base--;
272ea0fabbcSTim J. Robbins 	suword32(base, (uint32_t)imgp->argc);
273ea0fabbcSTim J. Robbins 	*stack_base = (register_t *)base;
274ea0fabbcSTim J. Robbins 	return 0;
275ea0fabbcSTim J. Robbins }
276ea0fabbcSTim J. Robbins 
277ea0fabbcSTim J. Robbins extern int _ucodesel, _ucode32sel, _udatasel;
278ea0fabbcSTim J. Robbins extern unsigned long linux_sznonrtsigcode;
279ea0fabbcSTim J. Robbins 
280ea0fabbcSTim J. Robbins static void
281ea0fabbcSTim J. Robbins linux_rt_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
282ea0fabbcSTim J. Robbins {
283ea0fabbcSTim J. Robbins 	struct thread *td = curthread;
284ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
285ea0fabbcSTim J. Robbins 	struct sigacts *psp;
286ea0fabbcSTim J. Robbins 	struct trapframe *regs;
287ea0fabbcSTim J. Robbins 	struct l_rt_sigframe *fp, frame;
288ea0fabbcSTim J. Robbins 	int oonstack;
289ea0fabbcSTim J. Robbins 
290ea0fabbcSTim J. Robbins 	PROC_LOCK_ASSERT(p, MA_OWNED);
291ea0fabbcSTim J. Robbins 	psp = p->p_sigacts;
292ea0fabbcSTim J. Robbins 	mtx_assert(&psp->ps_mtx, MA_OWNED);
293ea0fabbcSTim J. Robbins 	regs = td->td_frame;
294ea0fabbcSTim J. Robbins 	oonstack = sigonstack(regs->tf_rsp);
295ea0fabbcSTim J. Robbins 
296ea0fabbcSTim J. Robbins #ifdef DEBUG
297ea0fabbcSTim J. Robbins 	if (ldebug(rt_sendsig))
298ea0fabbcSTim J. Robbins 		printf(ARGS(rt_sendsig, "%p, %d, %p, %lu"),
299ea0fabbcSTim J. Robbins 		    catcher, sig, (void*)mask, code);
300ea0fabbcSTim J. Robbins #endif
301ea0fabbcSTim J. Robbins 	/*
302ea0fabbcSTim J. Robbins 	 * Allocate space for the signal handler context.
303ea0fabbcSTim J. Robbins 	 */
304ea0fabbcSTim J. Robbins 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
305ea0fabbcSTim J. Robbins 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
306ea0fabbcSTim J. Robbins 		fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp +
307ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe));
308ea0fabbcSTim J. Robbins 	} else
309ea0fabbcSTim J. Robbins 		fp = (struct l_rt_sigframe *)regs->tf_rsp - 1;
310ea0fabbcSTim J. Robbins 	mtx_unlock(&psp->ps_mtx);
311ea0fabbcSTim J. Robbins 
312ea0fabbcSTim J. Robbins 	/*
313ea0fabbcSTim J. Robbins 	 * Build the argument list for the signal handler.
314ea0fabbcSTim J. Robbins 	 */
315ea0fabbcSTim J. Robbins 	if (p->p_sysent->sv_sigtbl)
316ea0fabbcSTim J. Robbins 		if (sig <= p->p_sysent->sv_sigsize)
317ea0fabbcSTim J. Robbins 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
318ea0fabbcSTim J. Robbins 
319ea0fabbcSTim J. Robbins 	bzero(&frame, sizeof(frame));
320ea0fabbcSTim J. Robbins 
321ea0fabbcSTim J. Robbins 	frame.sf_handler = PTROUT(catcher);
322ea0fabbcSTim J. Robbins 	frame.sf_sig = sig;
323ea0fabbcSTim J. Robbins 	frame.sf_siginfo = PTROUT(&fp->sf_si);
324ea0fabbcSTim J. Robbins 	frame.sf_ucontext = PTROUT(&fp->sf_sc);
325ea0fabbcSTim J. Robbins 
326ea0fabbcSTim J. Robbins 	/* Fill in POSIX parts */
327ea0fabbcSTim J. Robbins 	frame.sf_si.lsi_signo = sig;
328ea0fabbcSTim J. Robbins 	frame.sf_si.lsi_code = code;
329ea0fabbcSTim J. Robbins 	frame.sf_si.lsi_addr = PTROUT(regs->tf_err);
330ea0fabbcSTim J. Robbins 
331ea0fabbcSTim J. Robbins 	/*
332ea0fabbcSTim J. Robbins 	 * Build the signal context to be used by sigreturn.
333ea0fabbcSTim J. Robbins 	 */
334ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_flags = 0;		/* XXX ??? */
335ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_link = 0;		/* XXX ??? */
336ea0fabbcSTim J. Robbins 
337ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp);
338ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size;
339ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK)
340ea0fabbcSTim J. Robbins 	    ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
341ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
342ea0fabbcSTim J. Robbins 
343ea0fabbcSTim J. Robbins 	bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask);
344ea0fabbcSTim J. Robbins 
345ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_mask   = frame.sf_sc.uc_sigmask.__bits[0];
346ea0fabbcSTim J. Robbins         frame.sf_sc.uc_mcontext.sc_gs     = rgs();
347ea0fabbcSTim J. Robbins         frame.sf_sc.uc_mcontext.sc_fs     = rfs();
348ea0fabbcSTim J. Robbins         __asm __volatile("movl %%es,%0" :
349ea0fabbcSTim J. Robbins 	    "=rm" (frame.sf_sc.uc_mcontext.sc_es));
350ea0fabbcSTim J. Robbins         __asm __volatile("movl %%ds,%0" :
351ea0fabbcSTim J. Robbins 	    "=rm" (frame.sf_sc.uc_mcontext.sc_ds));
352ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_edi    = regs->tf_rdi;
353ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_esi    = regs->tf_rsi;
354ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ebp    = regs->tf_rbp;
355ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ebx    = regs->tf_rbx;
356ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_edx    = regs->tf_rdx;
357ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ecx    = regs->tf_rcx;
358ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eax    = regs->tf_rax;
359ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eip    = regs->tf_rip;
360ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_cs     = regs->tf_cs;
361ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags;
362ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp;
363ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_ss     = regs->tf_ss;
364ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_err    = regs->tf_err;
365ea0fabbcSTim J. Robbins 	frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code);
366ea0fabbcSTim J. Robbins 
367ea0fabbcSTim J. Robbins #ifdef DEBUG
368ea0fabbcSTim J. Robbins 	if (ldebug(rt_sendsig))
369ea0fabbcSTim J. Robbins 		printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
370ea0fabbcSTim J. Robbins 		    frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp,
371ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask);
372ea0fabbcSTim J. Robbins #endif
373ea0fabbcSTim J. Robbins 
374ea0fabbcSTim J. Robbins 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
375ea0fabbcSTim J. Robbins 		/*
376ea0fabbcSTim J. Robbins 		 * Process has trashed its stack; give it an illegal
377ea0fabbcSTim J. Robbins 		 * instruction to halt it in its tracks.
378ea0fabbcSTim J. Robbins 		 */
379ea0fabbcSTim J. Robbins #ifdef DEBUG
380ea0fabbcSTim J. Robbins 		if (ldebug(rt_sendsig))
381ea0fabbcSTim J. Robbins 			printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"),
382ea0fabbcSTim J. Robbins 			    fp, oonstack);
383ea0fabbcSTim J. Robbins #endif
384ea0fabbcSTim J. Robbins 		PROC_LOCK(p);
385ea0fabbcSTim J. Robbins 		sigexit(td, SIGILL);
386ea0fabbcSTim J. Robbins 	}
387ea0fabbcSTim J. Robbins 
388ea0fabbcSTim J. Robbins 	/*
389ea0fabbcSTim J. Robbins 	 * Build context to run handler in.
390ea0fabbcSTim J. Robbins 	 */
391ea0fabbcSTim J. Robbins 	regs->tf_rsp = PTROUT(fp);
392ea0fabbcSTim J. Robbins 	regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode) +
393ea0fabbcSTim J. Robbins 	    linux_sznonrtsigcode;
394ea0fabbcSTim J. Robbins 	regs->tf_rflags &= ~PSL_T;
395ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
396ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
397ea0fabbcSTim J. Robbins 	load_ds(_udatasel);
398ea0fabbcSTim J. Robbins 	td->td_pcb->pcb_ds = _udatasel;
399ea0fabbcSTim J. Robbins 	load_es(_udatasel);
400ea0fabbcSTim J. Robbins 	td->td_pcb->pcb_es = _udatasel;
401ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
402ea0fabbcSTim J. Robbins 	mtx_lock(&psp->ps_mtx);
403ea0fabbcSTim J. Robbins }
404ea0fabbcSTim J. Robbins 
405ea0fabbcSTim J. Robbins 
406ea0fabbcSTim J. Robbins /*
407ea0fabbcSTim J. Robbins  * Send an interrupt to process.
408ea0fabbcSTim J. Robbins  *
409ea0fabbcSTim J. Robbins  * Stack is set up to allow sigcode stored
410ea0fabbcSTim J. Robbins  * in u. to call routine, followed by kcall
411ea0fabbcSTim J. Robbins  * to sigreturn routine below.  After sigreturn
412ea0fabbcSTim J. Robbins  * resets the signal mask, the stack, and the
413ea0fabbcSTim J. Robbins  * frame pointer, it returns to the user
414ea0fabbcSTim J. Robbins  * specified pc, psl.
415ea0fabbcSTim J. Robbins  */
416ea0fabbcSTim J. Robbins static void
417ea0fabbcSTim J. Robbins linux_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
418ea0fabbcSTim J. Robbins {
419ea0fabbcSTim J. Robbins 	struct thread *td = curthread;
420ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
421ea0fabbcSTim J. Robbins 	struct sigacts *psp;
422ea0fabbcSTim J. Robbins 	struct trapframe *regs;
423ea0fabbcSTim J. Robbins 	struct l_sigframe *fp, frame;
424ea0fabbcSTim J. Robbins 	l_sigset_t lmask;
425ea0fabbcSTim J. Robbins 	int oonstack, i;
426ea0fabbcSTim J. Robbins 
427ea0fabbcSTim J. Robbins 	PROC_LOCK_ASSERT(p, MA_OWNED);
428ea0fabbcSTim J. Robbins 	psp = p->p_sigacts;
429ea0fabbcSTim J. Robbins 	mtx_assert(&psp->ps_mtx, MA_OWNED);
430ea0fabbcSTim J. Robbins 	if (SIGISMEMBER(psp->ps_siginfo, sig)) {
431ea0fabbcSTim J. Robbins 		/* Signal handler installed with SA_SIGINFO. */
432ea0fabbcSTim J. Robbins 		linux_rt_sendsig(catcher, sig, mask, code);
433ea0fabbcSTim J. Robbins 		return;
434ea0fabbcSTim J. Robbins 	}
435ea0fabbcSTim J. Robbins 
436ea0fabbcSTim J. Robbins 	regs = td->td_frame;
437ea0fabbcSTim J. Robbins 	oonstack = sigonstack(regs->tf_rsp);
438ea0fabbcSTim J. Robbins 
439ea0fabbcSTim J. Robbins #ifdef DEBUG
440ea0fabbcSTim J. Robbins 	if (ldebug(sendsig))
441ea0fabbcSTim J. Robbins 		printf(ARGS(sendsig, "%p, %d, %p, %lu"),
442ea0fabbcSTim J. Robbins 		    catcher, sig, (void*)mask, code);
443ea0fabbcSTim J. Robbins #endif
444ea0fabbcSTim J. Robbins 
445ea0fabbcSTim J. Robbins 	/*
446ea0fabbcSTim J. Robbins 	 * Allocate space for the signal handler context.
447ea0fabbcSTim J. Robbins 	 */
448ea0fabbcSTim J. Robbins 	if ((td->td_pflags & TDP_ALTSTACK) && !oonstack &&
449ea0fabbcSTim J. Robbins 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
450ea0fabbcSTim J. Robbins 		fp = (struct l_sigframe *)(td->td_sigstk.ss_sp +
451ea0fabbcSTim J. Robbins 		    td->td_sigstk.ss_size - sizeof(struct l_sigframe));
452ea0fabbcSTim J. Robbins 	} else
453ea0fabbcSTim J. Robbins 		fp = (struct l_sigframe *)regs->tf_rsp - 1;
454ea0fabbcSTim J. Robbins 	mtx_unlock(&psp->ps_mtx);
455ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
456ea0fabbcSTim J. Robbins 
457ea0fabbcSTim J. Robbins 	/*
458ea0fabbcSTim J. Robbins 	 * Build the argument list for the signal handler.
459ea0fabbcSTim J. Robbins 	 */
460ea0fabbcSTim J. Robbins 	if (p->p_sysent->sv_sigtbl)
461ea0fabbcSTim J. Robbins 		if (sig <= p->p_sysent->sv_sigsize)
462ea0fabbcSTim J. Robbins 			sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
463ea0fabbcSTim J. Robbins 
464ea0fabbcSTim J. Robbins 	bzero(&frame, sizeof(frame));
465ea0fabbcSTim J. Robbins 
466ea0fabbcSTim J. Robbins 	frame.sf_handler = PTROUT(catcher);
467ea0fabbcSTim J. Robbins 	frame.sf_sig = sig;
468ea0fabbcSTim J. Robbins 
469ea0fabbcSTim J. Robbins 	bsd_to_linux_sigset(mask, &lmask);
470ea0fabbcSTim J. Robbins 
471ea0fabbcSTim J. Robbins 	/*
472ea0fabbcSTim J. Robbins 	 * Build the signal context to be used by sigreturn.
473ea0fabbcSTim J. Robbins 	 */
474ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_mask   = lmask.__bits[0];
475ea0fabbcSTim J. Robbins         frame.sf_sc.sc_gs     = rgs();
476ea0fabbcSTim J. Robbins         frame.sf_sc.sc_fs     = rfs();
477ea0fabbcSTim J. Robbins         __asm __volatile("movl %%es,%0" : "=rm" (frame.sf_sc.sc_es));
478ea0fabbcSTim J. Robbins         __asm __volatile("movl %%ds,%0" : "=rm" (frame.sf_sc.sc_ds));
479ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_edi    = regs->tf_rdi;
480ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_esi    = regs->tf_rsi;
481ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ebp    = regs->tf_rbp;
482ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ebx    = regs->tf_rbx;
483ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_edx    = regs->tf_rdx;
484ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ecx    = regs->tf_rcx;
485ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eax    = regs->tf_rax;
486ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eip    = regs->tf_rip;
487ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_cs     = regs->tf_cs;
488ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_eflags = regs->tf_rflags;
489ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_esp_at_signal = regs->tf_rsp;
490ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_ss     = regs->tf_ss;
491ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_err    = regs->tf_err;
492ea0fabbcSTim J. Robbins 	frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code);
493ea0fabbcSTim J. Robbins 
494ea0fabbcSTim J. Robbins 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
495ea0fabbcSTim J. Robbins 		frame.sf_extramask[i] = lmask.__bits[i+1];
496ea0fabbcSTim J. Robbins 
497ea0fabbcSTim J. Robbins 	if (copyout(&frame, fp, sizeof(frame)) != 0) {
498ea0fabbcSTim J. Robbins 		/*
499ea0fabbcSTim J. Robbins 		 * Process has trashed its stack; give it an illegal
500ea0fabbcSTim J. Robbins 		 * instruction to halt it in its tracks.
501ea0fabbcSTim J. Robbins 		 */
502ea0fabbcSTim J. Robbins 		PROC_LOCK(p);
503ea0fabbcSTim J. Robbins 		sigexit(td, SIGILL);
504ea0fabbcSTim J. Robbins 	}
505ea0fabbcSTim J. Robbins 
506ea0fabbcSTim J. Robbins 	/*
507ea0fabbcSTim J. Robbins 	 * Build context to run handler in.
508ea0fabbcSTim J. Robbins 	 */
509ea0fabbcSTim J. Robbins 	regs->tf_rsp = PTROUT(fp);
510ea0fabbcSTim J. Robbins 	regs->tf_rip = LINUX32_PS_STRINGS - *(p->p_sysent->sv_szsigcode);
511ea0fabbcSTim J. Robbins 	regs->tf_rflags &= ~PSL_T;
512ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
513ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
514ea0fabbcSTim J. Robbins 	load_ds(_udatasel);
515ea0fabbcSTim J. Robbins 	td->td_pcb->pcb_ds = _udatasel;
516ea0fabbcSTim J. Robbins 	load_es(_udatasel);
517ea0fabbcSTim J. Robbins 	td->td_pcb->pcb_es = _udatasel;
518ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
519ea0fabbcSTim J. Robbins 	mtx_lock(&psp->ps_mtx);
520ea0fabbcSTim J. Robbins }
521ea0fabbcSTim J. Robbins 
522ea0fabbcSTim J. Robbins /*
523ea0fabbcSTim J. Robbins  * System call to cleanup state after a signal
524ea0fabbcSTim J. Robbins  * has been taken.  Reset signal mask and
525ea0fabbcSTim J. Robbins  * stack state from context left by sendsig (above).
526ea0fabbcSTim J. Robbins  * Return to previous pc and psl as specified by
527ea0fabbcSTim J. Robbins  * context left by sendsig. Check carefully to
528ea0fabbcSTim J. Robbins  * make sure that the user has not modified the
529ea0fabbcSTim J. Robbins  * psl to gain improper privileges or to cause
530ea0fabbcSTim J. Robbins  * a machine fault.
531ea0fabbcSTim J. Robbins  */
532ea0fabbcSTim J. Robbins int
533ea0fabbcSTim J. Robbins linux_sigreturn(struct thread *td, struct linux_sigreturn_args *args)
534ea0fabbcSTim J. Robbins {
535ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
536ea0fabbcSTim J. Robbins 	struct l_sigframe frame;
537ea0fabbcSTim J. Robbins 	struct trapframe *regs;
538ea0fabbcSTim J. Robbins 	l_sigset_t lmask;
539ea0fabbcSTim J. Robbins 	int eflags, i;
540ea0fabbcSTim J. Robbins 
541ea0fabbcSTim J. Robbins 	regs = td->td_frame;
542ea0fabbcSTim J. Robbins 
543ea0fabbcSTim J. Robbins #ifdef DEBUG
544ea0fabbcSTim J. Robbins 	if (ldebug(sigreturn))
545ea0fabbcSTim J. Robbins 		printf(ARGS(sigreturn, "%p"), (void *)args->sfp);
546ea0fabbcSTim J. Robbins #endif
547ea0fabbcSTim J. Robbins 	/*
548ea0fabbcSTim J. Robbins 	 * The trampoline code hands us the sigframe.
549ea0fabbcSTim J. Robbins 	 * It is unsafe to keep track of it ourselves, in the event that a
550ea0fabbcSTim J. Robbins 	 * program jumps out of a signal handler.
551ea0fabbcSTim J. Robbins 	 */
552ea0fabbcSTim J. Robbins 	if (copyin(args->sfp, &frame, sizeof(frame)) != 0)
553ea0fabbcSTim J. Robbins 		return (EFAULT);
554ea0fabbcSTim J. Robbins 
555ea0fabbcSTim J. Robbins 	/*
556ea0fabbcSTim J. Robbins 	 * Check for security violations.
557ea0fabbcSTim J. Robbins 	 */
558ea0fabbcSTim J. Robbins #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
559ea0fabbcSTim J. Robbins 	eflags = frame.sf_sc.sc_eflags;
560ea0fabbcSTim J. Robbins 	/*
561ea0fabbcSTim J. Robbins 	 * XXX do allow users to change the privileged flag PSL_RF.  The
562ea0fabbcSTim J. Robbins 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
563ea0fabbcSTim J. Robbins 	 * sometimes set it there too.  tf_eflags is kept in the signal
564ea0fabbcSTim J. Robbins 	 * context during signal handling and there is no other place
565ea0fabbcSTim J. Robbins 	 * to remember it, so the PSL_RF bit may be corrupted by the
566ea0fabbcSTim J. Robbins 	 * signal handler without us knowing.  Corruption of the PSL_RF
567ea0fabbcSTim J. Robbins 	 * bit at worst causes one more or one less debugger trap, so
568ea0fabbcSTim J. Robbins 	 * allowing it is fairly harmless.
569ea0fabbcSTim J. Robbins 	 */
570ea0fabbcSTim J. Robbins 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF))
571ea0fabbcSTim J. Robbins 		return(EINVAL);
572ea0fabbcSTim J. Robbins 
573ea0fabbcSTim J. Robbins 	/*
574ea0fabbcSTim J. Robbins 	 * Don't allow users to load a valid privileged %cs.  Let the
575ea0fabbcSTim J. Robbins 	 * hardware check for invalid selectors, excess privilege in
576ea0fabbcSTim J. Robbins 	 * other selectors, invalid %eip's and invalid %esp's.
577ea0fabbcSTim J. Robbins 	 */
578ea0fabbcSTim J. Robbins #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
579ea0fabbcSTim J. Robbins 	if (!CS_SECURE(frame.sf_sc.sc_cs)) {
580ea0fabbcSTim J. Robbins 		trapsignal(td, SIGBUS, T_PROTFLT);
581ea0fabbcSTim J. Robbins 		return(EINVAL);
582ea0fabbcSTim J. Robbins 	}
583ea0fabbcSTim J. Robbins 
584ea0fabbcSTim J. Robbins 	lmask.__bits[0] = frame.sf_sc.sc_mask;
585ea0fabbcSTim J. Robbins 	for (i = 0; i < (LINUX_NSIG_WORDS-1); i++)
586ea0fabbcSTim J. Robbins 		lmask.__bits[i+1] = frame.sf_extramask[i];
587ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
588ea0fabbcSTim J. Robbins 	linux_to_bsd_sigset(&lmask, &td->td_sigmask);
589ea0fabbcSTim J. Robbins 	SIG_CANTMASK(td->td_sigmask);
590ea0fabbcSTim J. Robbins 	signotify(td);
591ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
592ea0fabbcSTim J. Robbins 
593ea0fabbcSTim J. Robbins 	/*
594ea0fabbcSTim J. Robbins 	 * Restore signal context.
595ea0fabbcSTim J. Robbins 	 */
596ea0fabbcSTim J. Robbins 	/* Selectors were restored by the trampoline. */
597ea0fabbcSTim J. Robbins 	regs->tf_rdi    = frame.sf_sc.sc_edi;
598ea0fabbcSTim J. Robbins 	regs->tf_rsi    = frame.sf_sc.sc_esi;
599ea0fabbcSTim J. Robbins 	regs->tf_rbp    = frame.sf_sc.sc_ebp;
600ea0fabbcSTim J. Robbins 	regs->tf_rbx    = frame.sf_sc.sc_ebx;
601ea0fabbcSTim J. Robbins 	regs->tf_rdx    = frame.sf_sc.sc_edx;
602ea0fabbcSTim J. Robbins 	regs->tf_rcx    = frame.sf_sc.sc_ecx;
603ea0fabbcSTim J. Robbins 	regs->tf_rax    = frame.sf_sc.sc_eax;
604ea0fabbcSTim J. Robbins 	regs->tf_rip    = frame.sf_sc.sc_eip;
605ea0fabbcSTim J. Robbins 	regs->tf_cs     = frame.sf_sc.sc_cs;
606ea0fabbcSTim J. Robbins 	regs->tf_rflags = eflags;
607ea0fabbcSTim J. Robbins 	regs->tf_rsp    = frame.sf_sc.sc_esp_at_signal;
608ea0fabbcSTim J. Robbins 	regs->tf_ss     = frame.sf_sc.sc_ss;
609ea0fabbcSTim J. Robbins 
610ea0fabbcSTim J. Robbins 	return (EJUSTRETURN);
611ea0fabbcSTim J. Robbins }
612ea0fabbcSTim J. Robbins 
613ea0fabbcSTim J. Robbins /*
614ea0fabbcSTim J. Robbins  * System call to cleanup state after a signal
615ea0fabbcSTim J. Robbins  * has been taken.  Reset signal mask and
616ea0fabbcSTim J. Robbins  * stack state from context left by rt_sendsig (above).
617ea0fabbcSTim J. Robbins  * Return to previous pc and psl as specified by
618ea0fabbcSTim J. Robbins  * context left by sendsig. Check carefully to
619ea0fabbcSTim J. Robbins  * make sure that the user has not modified the
620ea0fabbcSTim J. Robbins  * psl to gain improper privileges or to cause
621ea0fabbcSTim J. Robbins  * a machine fault.
622ea0fabbcSTim J. Robbins  */
623ea0fabbcSTim J. Robbins int
624ea0fabbcSTim J. Robbins linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
625ea0fabbcSTim J. Robbins {
626ea0fabbcSTim J. Robbins 	struct proc *p = td->td_proc;
627ea0fabbcSTim J. Robbins 	struct l_ucontext uc;
628ea0fabbcSTim J. Robbins 	struct l_sigcontext *context;
629ea0fabbcSTim J. Robbins 	l_stack_t *lss;
630ea0fabbcSTim J. Robbins 	stack_t ss;
631ea0fabbcSTim J. Robbins 	struct trapframe *regs;
632ea0fabbcSTim J. Robbins 	int eflags;
633ea0fabbcSTim J. Robbins 
634ea0fabbcSTim J. Robbins 	regs = td->td_frame;
635ea0fabbcSTim J. Robbins 
636ea0fabbcSTim J. Robbins #ifdef DEBUG
637ea0fabbcSTim J. Robbins 	if (ldebug(rt_sigreturn))
638ea0fabbcSTim J. Robbins 		printf(ARGS(rt_sigreturn, "%p"), (void *)args->ucp);
639ea0fabbcSTim J. Robbins #endif
640ea0fabbcSTim J. Robbins 	/*
641ea0fabbcSTim J. Robbins 	 * The trampoline code hands us the ucontext.
642ea0fabbcSTim J. Robbins 	 * It is unsafe to keep track of it ourselves, in the event that a
643ea0fabbcSTim J. Robbins 	 * program jumps out of a signal handler.
644ea0fabbcSTim J. Robbins 	 */
645ea0fabbcSTim J. Robbins 	if (copyin(args->ucp, &uc, sizeof(uc)) != 0)
646ea0fabbcSTim J. Robbins 		return (EFAULT);
647ea0fabbcSTim J. Robbins 
648ea0fabbcSTim J. Robbins 	context = &uc.uc_mcontext;
649ea0fabbcSTim J. Robbins 
650ea0fabbcSTim J. Robbins 	/*
651ea0fabbcSTim J. Robbins 	 * Check for security violations.
652ea0fabbcSTim J. Robbins 	 */
653ea0fabbcSTim J. Robbins #define	EFLAGS_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
654ea0fabbcSTim J. Robbins 	eflags = context->sc_eflags;
655ea0fabbcSTim J. Robbins 	/*
656ea0fabbcSTim J. Robbins 	 * XXX do allow users to change the privileged flag PSL_RF.  The
657ea0fabbcSTim J. Robbins 	 * cpu sets PSL_RF in tf_eflags for faults.  Debuggers should
658ea0fabbcSTim J. Robbins 	 * sometimes set it there too.  tf_eflags is kept in the signal
659ea0fabbcSTim J. Robbins 	 * context during signal handling and there is no other place
660ea0fabbcSTim J. Robbins 	 * to remember it, so the PSL_RF bit may be corrupted by the
661ea0fabbcSTim J. Robbins 	 * signal handler without us knowing.  Corruption of the PSL_RF
662ea0fabbcSTim J. Robbins 	 * bit at worst causes one more or one less debugger trap, so
663ea0fabbcSTim J. Robbins 	 * allowing it is fairly harmless.
664ea0fabbcSTim J. Robbins 	 */
665ea0fabbcSTim J. Robbins 	if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF))
666ea0fabbcSTim J. Robbins 		return(EINVAL);
667ea0fabbcSTim J. Robbins 
668ea0fabbcSTim J. Robbins 	/*
669ea0fabbcSTim J. Robbins 	 * Don't allow users to load a valid privileged %cs.  Let the
670ea0fabbcSTim J. Robbins 	 * hardware check for invalid selectors, excess privilege in
671ea0fabbcSTim J. Robbins 	 * other selectors, invalid %eip's and invalid %esp's.
672ea0fabbcSTim J. Robbins 	 */
673ea0fabbcSTim J. Robbins #define	CS_SECURE(cs)	(ISPL(cs) == SEL_UPL)
674ea0fabbcSTim J. Robbins 	if (!CS_SECURE(context->sc_cs)) {
675ea0fabbcSTim J. Robbins 		trapsignal(td, SIGBUS, T_PROTFLT);
676ea0fabbcSTim J. Robbins 		return(EINVAL);
677ea0fabbcSTim J. Robbins 	}
678ea0fabbcSTim J. Robbins 
679ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
680ea0fabbcSTim J. Robbins 	linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask);
681ea0fabbcSTim J. Robbins 	SIG_CANTMASK(td->td_sigmask);
682ea0fabbcSTim J. Robbins 	signotify(td);
683ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
684ea0fabbcSTim J. Robbins 
685ea0fabbcSTim J. Robbins 	/*
686ea0fabbcSTim J. Robbins 	 * Restore signal context
687ea0fabbcSTim J. Robbins 	 */
688ea0fabbcSTim J. Robbins 	/* Selectors were restored by the trampoline. */
689ea0fabbcSTim J. Robbins 	regs->tf_rdi    = context->sc_edi;
690ea0fabbcSTim J. Robbins 	regs->tf_rsi    = context->sc_esi;
691ea0fabbcSTim J. Robbins 	regs->tf_rbp    = context->sc_ebp;
692ea0fabbcSTim J. Robbins 	regs->tf_rbx    = context->sc_ebx;
693ea0fabbcSTim J. Robbins 	regs->tf_rdx    = context->sc_edx;
694ea0fabbcSTim J. Robbins 	regs->tf_rcx    = context->sc_ecx;
695ea0fabbcSTim J. Robbins 	regs->tf_rax    = context->sc_eax;
696ea0fabbcSTim J. Robbins 	regs->tf_rip    = context->sc_eip;
697ea0fabbcSTim J. Robbins 	regs->tf_cs     = context->sc_cs;
698ea0fabbcSTim J. Robbins 	regs->tf_rflags = eflags;
699ea0fabbcSTim J. Robbins 	regs->tf_rsp    = context->sc_esp_at_signal;
700ea0fabbcSTim J. Robbins 	regs->tf_ss     = context->sc_ss;
701ea0fabbcSTim J. Robbins 
702ea0fabbcSTim J. Robbins 	/*
703ea0fabbcSTim J. Robbins 	 * call sigaltstack & ignore results..
704ea0fabbcSTim J. Robbins 	 */
705ea0fabbcSTim J. Robbins 	lss = &uc.uc_stack;
706ea0fabbcSTim J. Robbins 	ss.ss_sp = PTRIN(lss->ss_sp);
707ea0fabbcSTim J. Robbins 	ss.ss_size = lss->ss_size;
708ea0fabbcSTim J. Robbins 	ss.ss_flags = linux_to_bsd_sigaltstack(lss->ss_flags);
709ea0fabbcSTim J. Robbins 
710ea0fabbcSTim J. Robbins #ifdef DEBUG
711ea0fabbcSTim J. Robbins 	if (ldebug(rt_sigreturn))
712ea0fabbcSTim J. Robbins 		printf(LMSG("rt_sigret flags: 0x%x, sp: %p, ss: 0x%x, mask: 0x%x"),
713ea0fabbcSTim J. Robbins 		    ss.ss_flags, ss.ss_sp, ss.ss_size, context->sc_mask);
714ea0fabbcSTim J. Robbins #endif
715ea0fabbcSTim J. Robbins 	(void)kern_sigaltstack(td, &ss, NULL);
716ea0fabbcSTim J. Robbins 
717ea0fabbcSTim J. Robbins 	return (EJUSTRETURN);
718ea0fabbcSTim J. Robbins }
719ea0fabbcSTim J. Robbins 
720ea0fabbcSTim J. Robbins /*
721ea0fabbcSTim J. Robbins  * MPSAFE
722ea0fabbcSTim J. Robbins  */
723ea0fabbcSTim J. Robbins static void
724ea0fabbcSTim J. Robbins linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
725ea0fabbcSTim J. Robbins {
726ea0fabbcSTim J. Robbins 	args[0] = tf->tf_rbx;
727ea0fabbcSTim J. Robbins 	args[1] = tf->tf_rcx;
728ea0fabbcSTim J. Robbins 	args[2] = tf->tf_rdx;
729ea0fabbcSTim J. Robbins 	args[3] = tf->tf_rsi;
730ea0fabbcSTim J. Robbins 	args[4] = tf->tf_rdi;
731ea0fabbcSTim J. Robbins 	args[5] = tf->tf_rbp;	/* Unconfirmed */
732ea0fabbcSTim J. Robbins 	*params = NULL;		/* no copyin */
733ea0fabbcSTim J. Robbins }
734ea0fabbcSTim J. Robbins 
735ea0fabbcSTim J. Robbins /*
736ea0fabbcSTim J. Robbins  * If a linux binary is exec'ing something, try this image activator
737ea0fabbcSTim J. Robbins  * first.  We override standard shell script execution in order to
738ea0fabbcSTim J. Robbins  * be able to modify the interpreter path.  We only do this if a linux
739ea0fabbcSTim J. Robbins  * binary is doing the exec, so we do not create an EXEC module for it.
740ea0fabbcSTim J. Robbins  */
741ea0fabbcSTim J. Robbins static int	exec_linux_imgact_try(struct image_params *iparams);
742ea0fabbcSTim J. Robbins 
743ea0fabbcSTim J. Robbins static int
744ea0fabbcSTim J. Robbins exec_linux_imgact_try(struct image_params *imgp)
745ea0fabbcSTim J. Robbins {
746ea0fabbcSTim J. Robbins     const char *head = (const char *)imgp->image_header;
747ea0fabbcSTim J. Robbins     int error = -1;
748ea0fabbcSTim J. Robbins 
749ea0fabbcSTim J. Robbins     /*
750ea0fabbcSTim J. Robbins      * The interpreter for shell scripts run from a linux binary needs
751ea0fabbcSTim J. Robbins      * to be located in /compat/linux if possible in order to recursively
752ea0fabbcSTim J. Robbins      * maintain linux path emulation.
753ea0fabbcSTim J. Robbins      */
754ea0fabbcSTim J. Robbins     if (((const short *)head)[0] == SHELLMAGIC) {
755ea0fabbcSTim J. Robbins 	    /*
756ea0fabbcSTim J. Robbins 	     * Run our normal shell image activator.  If it succeeds attempt
757ea0fabbcSTim J. Robbins 	     * to use the alternate path for the interpreter.  If an alternate
758ea0fabbcSTim J. Robbins 	     * path is found, use our stringspace to store it.
759ea0fabbcSTim J. Robbins 	     */
760ea0fabbcSTim J. Robbins 	    if ((error = exec_shell_imgact(imgp)) == 0) {
761ea0fabbcSTim J. Robbins 		    char *rpath = NULL;
762ea0fabbcSTim J. Robbins 
763ea0fabbcSTim J. Robbins 		    linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL,
764ea0fabbcSTim J. Robbins 			imgp->interpreter_name, &rpath, 0);
765ea0fabbcSTim J. Robbins 		    if (rpath != imgp->interpreter_name) {
766ea0fabbcSTim J. Robbins 			    int len = strlen(rpath) + 1;
767ea0fabbcSTim J. Robbins 
768ea0fabbcSTim J. Robbins 			    if (len <= MAXSHELLCMDLEN) {
769ea0fabbcSTim J. Robbins 				    memcpy(imgp->interpreter_name, rpath, len);
770ea0fabbcSTim J. Robbins 			    }
771ea0fabbcSTim J. Robbins 			    free(rpath, M_TEMP);
772ea0fabbcSTim J. Robbins 		    }
773ea0fabbcSTim J. Robbins 	    }
774ea0fabbcSTim J. Robbins     }
775ea0fabbcSTim J. Robbins     return(error);
776ea0fabbcSTim J. Robbins }
777ea0fabbcSTim J. Robbins 
778ea0fabbcSTim J. Robbins /*
779ea0fabbcSTim J. Robbins  * Clear registers on exec
780ea0fabbcSTim J. Robbins  * XXX copied from ia32_signal.c.
781ea0fabbcSTim J. Robbins  */
782ea0fabbcSTim J. Robbins static void
783ea0fabbcSTim J. Robbins exec_linux_setregs(td, entry, stack, ps_strings)
784ea0fabbcSTim J. Robbins 	struct thread *td;
785ea0fabbcSTim J. Robbins 	u_long entry;
786ea0fabbcSTim J. Robbins 	u_long stack;
787ea0fabbcSTim J. Robbins 	u_long ps_strings;
788ea0fabbcSTim J. Robbins {
789ea0fabbcSTim J. Robbins 	struct trapframe *regs = td->td_frame;
790ea0fabbcSTim J. Robbins 	struct pcb *pcb = td->td_pcb;
791ea0fabbcSTim J. Robbins 
792ea0fabbcSTim J. Robbins 	wrmsr(MSR_FSBASE, 0);
793ea0fabbcSTim J. Robbins 	wrmsr(MSR_KGSBASE, 0);	/* User value while we're in the kernel */
794ea0fabbcSTim J. Robbins 	pcb->pcb_fsbase = 0;
795ea0fabbcSTim J. Robbins 	pcb->pcb_gsbase = 0;
796ea0fabbcSTim J. Robbins 	load_ds(_udatasel);
797ea0fabbcSTim J. Robbins 	load_es(_udatasel);
798ea0fabbcSTim J. Robbins 	load_fs(_udatasel);
799ea0fabbcSTim J. Robbins 	load_gs(0);
800ea0fabbcSTim J. Robbins 	pcb->pcb_ds = _udatasel;
801ea0fabbcSTim J. Robbins 	pcb->pcb_es = _udatasel;
802ea0fabbcSTim J. Robbins 	pcb->pcb_fs = _udatasel;
803ea0fabbcSTim J. Robbins 	pcb->pcb_gs = 0;
804ea0fabbcSTim J. Robbins 
805ea0fabbcSTim J. Robbins 	bzero((char *)regs, sizeof(struct trapframe));
806ea0fabbcSTim J. Robbins 	regs->tf_rip = entry;
807ea0fabbcSTim J. Robbins 	regs->tf_rsp = stack;
808ea0fabbcSTim J. Robbins 	regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
809ea0fabbcSTim J. Robbins 	regs->tf_ss = _udatasel;
810ea0fabbcSTim J. Robbins 	regs->tf_cs = _ucode32sel;
811ea0fabbcSTim J. Robbins 	regs->tf_rbx = ps_strings;
812ea0fabbcSTim J. Robbins 	load_cr0(rcr0() | CR0_MP | CR0_TS);
813ea0fabbcSTim J. Robbins 
814ea0fabbcSTim J. Robbins 	/* Return via doreti so that we can change to a different %cs */
815ea0fabbcSTim J. Robbins 	pcb->pcb_flags |= PCB_FULLCTX;
816ea0fabbcSTim J. Robbins 	td->td_retval[1] = 0;
817ea0fabbcSTim J. Robbins }
818ea0fabbcSTim J. Robbins 
819ea0fabbcSTim J. Robbins /*
820ea0fabbcSTim J. Robbins  * XXX copied from ia32_sysvec.c.
821ea0fabbcSTim J. Robbins  */
822ea0fabbcSTim J. Robbins static register_t *
823ea0fabbcSTim J. Robbins linux_copyout_strings(struct image_params *imgp)
824ea0fabbcSTim J. Robbins {
825ea0fabbcSTim J. Robbins 	int argc, envc;
826ea0fabbcSTim J. Robbins 	u_int32_t *vectp;
827ea0fabbcSTim J. Robbins 	char *stringp, *destp;
828ea0fabbcSTim J. Robbins 	u_int32_t *stack_base;
829ea0fabbcSTim J. Robbins 	struct linux32_ps_strings *arginfo;
830ea0fabbcSTim J. Robbins 	int sigcodesz;
831ea0fabbcSTim J. Robbins 
832ea0fabbcSTim J. Robbins 	/*
833ea0fabbcSTim J. Robbins 	 * Calculate string base and vector table pointers.
834ea0fabbcSTim J. Robbins 	 * Also deal with signal trampoline code for this exec type.
835ea0fabbcSTim J. Robbins 	 */
836ea0fabbcSTim J. Robbins 	arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
837ea0fabbcSTim J. Robbins 	sigcodesz = *(imgp->proc->p_sysent->sv_szsigcode);
838ea0fabbcSTim J. Robbins 	destp =	(caddr_t)arginfo - sigcodesz - SPARE_USRSPACE -
839ea0fabbcSTim J. Robbins 		roundup((ARG_MAX - imgp->stringspace), sizeof(char *));
840ea0fabbcSTim J. Robbins 
841ea0fabbcSTim J. Robbins 	/*
842ea0fabbcSTim J. Robbins 	 * install sigcode
843ea0fabbcSTim J. Robbins 	 */
844ea0fabbcSTim J. Robbins 	if (sigcodesz)
845ea0fabbcSTim J. Robbins 		copyout(imgp->proc->p_sysent->sv_sigcode,
846ea0fabbcSTim J. Robbins 			((caddr_t)arginfo - sigcodesz), szsigcode);
847ea0fabbcSTim J. Robbins 
848ea0fabbcSTim J. Robbins 	/*
849ea0fabbcSTim J. Robbins 	 * If we have a valid auxargs ptr, prepare some room
850ea0fabbcSTim J. Robbins 	 * on the stack.
851ea0fabbcSTim J. Robbins 	 */
852ea0fabbcSTim J. Robbins 	if (imgp->auxargs) {
853ea0fabbcSTim J. Robbins 		/*
854ea0fabbcSTim J. Robbins 		 * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
855ea0fabbcSTim J. Robbins 		 * lower compatibility.
856ea0fabbcSTim J. Robbins 		 */
857ea0fabbcSTim J. Robbins 		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size
858ea0fabbcSTim J. Robbins 			: (AT_COUNT * 2);
859ea0fabbcSTim J. Robbins 		/*
860ea0fabbcSTim J. Robbins 		 * The '+ 2' is for the null pointers at the end of each of
861ea0fabbcSTim J. Robbins 		 * the arg and env vector sets,and imgp->auxarg_size is room
862ea0fabbcSTim J. Robbins 		 * for argument of Runtime loader.
863ea0fabbcSTim J. Robbins 		 */
864ea0fabbcSTim J. Robbins 		vectp = (u_int32_t *) (destp - (imgp->argc + imgp->envc + 2 +
865ea0fabbcSTim J. Robbins 				       imgp->auxarg_size) * sizeof(u_int32_t));
866ea0fabbcSTim J. Robbins 
867ea0fabbcSTim J. Robbins 	} else
868ea0fabbcSTim J. Robbins 		/*
869ea0fabbcSTim J. Robbins 		 * The '+ 2' is for the null pointers at the end of each of
870ea0fabbcSTim J. Robbins 		 * the arg and env vector sets
871ea0fabbcSTim J. Robbins 		 */
872ea0fabbcSTim J. Robbins 		vectp = (u_int32_t *)
873ea0fabbcSTim J. Robbins 			(destp - (imgp->argc + imgp->envc + 2) * sizeof(u_int32_t));
874ea0fabbcSTim J. Robbins 
875ea0fabbcSTim J. Robbins 	/*
876ea0fabbcSTim J. Robbins 	 * vectp also becomes our initial stack base
877ea0fabbcSTim J. Robbins 	 */
878ea0fabbcSTim J. Robbins 	stack_base = vectp;
879ea0fabbcSTim J. Robbins 
880ea0fabbcSTim J. Robbins 	stringp = imgp->stringbase;
881ea0fabbcSTim J. Robbins 	argc = imgp->argc;
882ea0fabbcSTim J. Robbins 	envc = imgp->envc;
883ea0fabbcSTim J. Robbins 	/*
884ea0fabbcSTim J. Robbins 	 * Copy out strings - arguments and environment.
885ea0fabbcSTim J. Robbins 	 */
886ea0fabbcSTim J. Robbins 	copyout(stringp, destp, ARG_MAX - imgp->stringspace);
887ea0fabbcSTim J. Robbins 
888ea0fabbcSTim J. Robbins 	/*
889ea0fabbcSTim J. Robbins 	 * Fill in "ps_strings" struct for ps, w, etc.
890ea0fabbcSTim J. Robbins 	 */
891ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp);
892ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_nargvstr, argc);
893ea0fabbcSTim J. Robbins 
894ea0fabbcSTim J. Robbins 	/*
895ea0fabbcSTim J. Robbins 	 * Fill in argument portion of vector table.
896ea0fabbcSTim J. Robbins 	 */
897ea0fabbcSTim J. Robbins 	for (; argc > 0; --argc) {
898ea0fabbcSTim J. Robbins 		suword32(vectp++, (u_int32_t)(intptr_t)destp);
899ea0fabbcSTim J. Robbins 		while (*stringp++ != 0)
900ea0fabbcSTim J. Robbins 			destp++;
901ea0fabbcSTim J. Robbins 		destp++;
902ea0fabbcSTim J. Robbins 	}
903ea0fabbcSTim J. Robbins 
904ea0fabbcSTim J. Robbins 	/* a null vector table pointer separates the argp's from the envp's */
905ea0fabbcSTim J. Robbins 	suword32(vectp++, 0);
906ea0fabbcSTim J. Robbins 
907ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp);
908ea0fabbcSTim J. Robbins 	suword32(&arginfo->ps_nenvstr, envc);
909ea0fabbcSTim J. Robbins 
910ea0fabbcSTim J. Robbins 	/*
911ea0fabbcSTim J. Robbins 	 * Fill in environment portion of vector table.
912ea0fabbcSTim J. Robbins 	 */
913ea0fabbcSTim J. Robbins 	for (; envc > 0; --envc) {
914ea0fabbcSTim J. Robbins 		suword32(vectp++, (u_int32_t)(intptr_t)destp);
915ea0fabbcSTim J. Robbins 		while (*stringp++ != 0)
916ea0fabbcSTim J. Robbins 			destp++;
917ea0fabbcSTim J. Robbins 		destp++;
918ea0fabbcSTim J. Robbins 	}
919ea0fabbcSTim J. Robbins 
920ea0fabbcSTim J. Robbins 	/* end of vector table is a null pointer */
921ea0fabbcSTim J. Robbins 	suword32(vectp, 0);
922ea0fabbcSTim J. Robbins 
923ea0fabbcSTim J. Robbins 	return ((register_t *)stack_base);
924ea0fabbcSTim J. Robbins }
925ea0fabbcSTim J. Robbins 
926ea0fabbcSTim J. Robbins SYSCTL_NODE(_compat, OID_AUTO, linux32, CTLFLAG_RW, 0,
927ea0fabbcSTim J. Robbins     "32-bit Linux emulation");
928ea0fabbcSTim J. Robbins 
929ea0fabbcSTim J. Robbins static u_long	linux32_maxdsiz = LINUX32_MAXDSIZ;
930ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxdsiz, CTLFLAG_RW,
931ea0fabbcSTim J. Robbins     &linux32_maxdsiz, 0, "");
932ea0fabbcSTim J. Robbins static u_long	linux32_maxssiz = LINUX32_MAXSSIZ;
933ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxssiz, CTLFLAG_RW,
934ea0fabbcSTim J. Robbins     &linux32_maxssiz, 0, "");
935ea0fabbcSTim J. Robbins static u_long	linux32_maxvmem = LINUX32_MAXVMEM;
936ea0fabbcSTim J. Robbins SYSCTL_ULONG(_compat_linux32, OID_AUTO, maxvmem, CTLFLAG_RW,
937ea0fabbcSTim J. Robbins     &linux32_maxvmem, 0, "");
938ea0fabbcSTim J. Robbins 
939ea0fabbcSTim J. Robbins /*
940ea0fabbcSTim J. Robbins  * XXX copied from ia32_sysvec.c.
941ea0fabbcSTim J. Robbins  */
942ea0fabbcSTim J. Robbins static void
943ea0fabbcSTim J. Robbins linux32_fixlimits(struct image_params *imgp)
944ea0fabbcSTim J. Robbins {
945ea0fabbcSTim J. Robbins 	struct proc *p = imgp->proc;
946ea0fabbcSTim J. Robbins 	struct plimit *oldlim, *newlim;
947ea0fabbcSTim J. Robbins 
948ea0fabbcSTim J. Robbins 	if (linux32_maxdsiz == 0 && linux32_maxssiz == 0 &&
949ea0fabbcSTim J. Robbins 	    linux32_maxvmem == 0)
950ea0fabbcSTim J. Robbins 		return;
951ea0fabbcSTim J. Robbins 	newlim = lim_alloc();
952ea0fabbcSTim J. Robbins 	PROC_LOCK(p);
953ea0fabbcSTim J. Robbins 	oldlim = p->p_limit;
954ea0fabbcSTim J. Robbins 	lim_copy(newlim, oldlim);
955ea0fabbcSTim J. Robbins 	if (linux32_maxdsiz != 0) {
956ea0fabbcSTim J. Robbins 		if (newlim->pl_rlimit[RLIMIT_DATA].rlim_cur > linux32_maxdsiz)
957ea0fabbcSTim J. Robbins 		    newlim->pl_rlimit[RLIMIT_DATA].rlim_cur = linux32_maxdsiz;
958ea0fabbcSTim J. Robbins 		if (newlim->pl_rlimit[RLIMIT_DATA].rlim_max > linux32_maxdsiz)
959ea0fabbcSTim J. Robbins 		    newlim->pl_rlimit[RLIMIT_DATA].rlim_max = linux32_maxdsiz;
960ea0fabbcSTim J. Robbins 	}
961ea0fabbcSTim J. Robbins 	if (linux32_maxssiz != 0) {
962ea0fabbcSTim J. Robbins 		if (newlim->pl_rlimit[RLIMIT_STACK].rlim_cur > linux32_maxssiz)
963ea0fabbcSTim J. Robbins 		    newlim->pl_rlimit[RLIMIT_STACK].rlim_cur = linux32_maxssiz;
964ea0fabbcSTim J. Robbins 		if (newlim->pl_rlimit[RLIMIT_STACK].rlim_max > linux32_maxssiz)
965ea0fabbcSTim J. Robbins 		    newlim->pl_rlimit[RLIMIT_STACK].rlim_max = linux32_maxssiz;
966ea0fabbcSTim J. Robbins 	}
967ea0fabbcSTim J. Robbins 	if (linux32_maxvmem != 0) {
968ea0fabbcSTim J. Robbins 		if (newlim->pl_rlimit[RLIMIT_VMEM].rlim_cur > linux32_maxvmem)
969ea0fabbcSTim J. Robbins 		    newlim->pl_rlimit[RLIMIT_VMEM].rlim_cur = linux32_maxvmem;
970ea0fabbcSTim J. Robbins 		if (newlim->pl_rlimit[RLIMIT_VMEM].rlim_max > linux32_maxvmem)
971ea0fabbcSTim J. Robbins 		    newlim->pl_rlimit[RLIMIT_VMEM].rlim_max = linux32_maxvmem;
972ea0fabbcSTim J. Robbins 	}
973ea0fabbcSTim J. Robbins 	p->p_limit = newlim;
974ea0fabbcSTim J. Robbins 	PROC_UNLOCK(p);
975ea0fabbcSTim J. Robbins 	lim_free(oldlim);
976ea0fabbcSTim J. Robbins }
977ea0fabbcSTim J. Robbins 
978ea0fabbcSTim J. Robbins struct sysentvec elf_linux_sysvec = {
979ea0fabbcSTim J. Robbins 	LINUX_SYS_MAXSYSCALL,
980ea0fabbcSTim J. Robbins 	linux_sysent,
981ea0fabbcSTim J. Robbins 	0xff,
982ea0fabbcSTim J. Robbins 	LINUX_SIGTBLSZ,
983ea0fabbcSTim J. Robbins 	bsd_to_linux_signal,
984ea0fabbcSTim J. Robbins 	ELAST + 1,
985ea0fabbcSTim J. Robbins 	bsd_to_linux_errno,
986ea0fabbcSTim J. Robbins 	translate_traps,
987ea0fabbcSTim J. Robbins 	elf_linux_fixup,
988ea0fabbcSTim J. Robbins 	linux_sendsig,
989ea0fabbcSTim J. Robbins 	linux_sigcode,
990ea0fabbcSTim J. Robbins 	&linux_szsigcode,
991ea0fabbcSTim J. Robbins 	linux_prepsyscall,
992ea0fabbcSTim J. Robbins 	"Linux ELF32",
993ea0fabbcSTim J. Robbins 	elf32_coredump,
994ea0fabbcSTim J. Robbins 	exec_linux_imgact_try,
995ea0fabbcSTim J. Robbins 	LINUX_MINSIGSTKSZ,
996ea0fabbcSTim J. Robbins 	PAGE_SIZE,
997ea0fabbcSTim J. Robbins 	VM_MIN_ADDRESS,
998ea0fabbcSTim J. Robbins 	LINUX32_USRSTACK,
999ea0fabbcSTim J. Robbins 	LINUX32_USRSTACK,
1000ea0fabbcSTim J. Robbins 	LINUX32_PS_STRINGS,
1001ea0fabbcSTim J. Robbins 	VM_PROT_ALL,
1002ea0fabbcSTim J. Robbins 	linux_copyout_strings,
1003ea0fabbcSTim J. Robbins 	exec_linux_setregs,
1004ea0fabbcSTim J. Robbins 	linux32_fixlimits
1005ea0fabbcSTim J. Robbins };
1006ea0fabbcSTim J. Robbins 
1007ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_brand = {
1008ea0fabbcSTim J. Robbins 					ELFOSABI_LINUX,
1009ea0fabbcSTim J. Robbins 					EM_386,
1010ea0fabbcSTim J. Robbins 					"Linux",
1011ea0fabbcSTim J. Robbins 					"/compat/linux",
1012ea0fabbcSTim J. Robbins 					"/lib/ld-linux.so.1",
1013ea0fabbcSTim J. Robbins 					&elf_linux_sysvec,
1014ea0fabbcSTim J. Robbins 					NULL,
1015ea0fabbcSTim J. Robbins 				 };
1016ea0fabbcSTim J. Robbins 
1017ea0fabbcSTim J. Robbins static Elf32_Brandinfo linux_glibc2brand = {
1018ea0fabbcSTim J. Robbins 					ELFOSABI_LINUX,
1019ea0fabbcSTim J. Robbins 					EM_386,
1020ea0fabbcSTim J. Robbins 					"Linux",
1021ea0fabbcSTim J. Robbins 					"/compat/linux",
1022ea0fabbcSTim J. Robbins 					"/lib/ld-linux.so.2",
1023ea0fabbcSTim J. Robbins 					&elf_linux_sysvec,
1024ea0fabbcSTim J. Robbins 					NULL,
1025ea0fabbcSTim J. Robbins 				 };
1026ea0fabbcSTim J. Robbins 
1027ea0fabbcSTim J. Robbins Elf32_Brandinfo *linux_brandlist[] = {
1028ea0fabbcSTim J. Robbins 					&linux_brand,
1029ea0fabbcSTim J. Robbins 					&linux_glibc2brand,
1030ea0fabbcSTim J. Robbins 					NULL
1031ea0fabbcSTim J. Robbins 				};
1032ea0fabbcSTim J. Robbins 
1033ea0fabbcSTim J. Robbins static int
1034ea0fabbcSTim J. Robbins linux_elf_modevent(module_t mod, int type, void *data)
1035ea0fabbcSTim J. Robbins {
1036ea0fabbcSTim J. Robbins 	Elf32_Brandinfo **brandinfo;
1037ea0fabbcSTim J. Robbins 	int error;
1038ea0fabbcSTim J. Robbins 	struct linux_ioctl_handler **lihp;
1039ea0fabbcSTim J. Robbins 
1040ea0fabbcSTim J. Robbins 	error = 0;
1041ea0fabbcSTim J. Robbins 
1042ea0fabbcSTim J. Robbins 	switch(type) {
1043ea0fabbcSTim J. Robbins 	case MOD_LOAD:
1044ea0fabbcSTim J. Robbins 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1045ea0fabbcSTim J. Robbins 		     ++brandinfo)
1046ea0fabbcSTim J. Robbins 			if (elf32_insert_brand_entry(*brandinfo) < 0)
1047ea0fabbcSTim J. Robbins 				error = EINVAL;
1048ea0fabbcSTim J. Robbins 		if (error == 0) {
1049ea0fabbcSTim J. Robbins 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1050ea0fabbcSTim J. Robbins 				linux_ioctl_register_handler(*lihp);
1051ea0fabbcSTim J. Robbins 			if (bootverbose)
1052ea0fabbcSTim J. Robbins 				printf("Linux ELF exec handler installed\n");
1053ea0fabbcSTim J. Robbins 		} else
1054ea0fabbcSTim J. Robbins 			printf("cannot insert Linux ELF brand handler\n");
1055ea0fabbcSTim J. Robbins 		break;
1056ea0fabbcSTim J. Robbins 	case MOD_UNLOAD:
1057ea0fabbcSTim J. Robbins 		for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
1058ea0fabbcSTim J. Robbins 		     ++brandinfo)
1059ea0fabbcSTim J. Robbins 			if (elf32_brand_inuse(*brandinfo))
1060ea0fabbcSTim J. Robbins 				error = EBUSY;
1061ea0fabbcSTim J. Robbins 		if (error == 0) {
1062ea0fabbcSTim J. Robbins 			for (brandinfo = &linux_brandlist[0];
1063ea0fabbcSTim J. Robbins 			     *brandinfo != NULL; ++brandinfo)
1064ea0fabbcSTim J. Robbins 				if (elf32_remove_brand_entry(*brandinfo) < 0)
1065ea0fabbcSTim J. Robbins 					error = EINVAL;
1066ea0fabbcSTim J. Robbins 		}
1067ea0fabbcSTim J. Robbins 		if (error == 0) {
1068ea0fabbcSTim J. Robbins 			SET_FOREACH(lihp, linux_ioctl_handler_set)
1069ea0fabbcSTim J. Robbins 				linux_ioctl_unregister_handler(*lihp);
1070ea0fabbcSTim J. Robbins 			if (bootverbose)
1071ea0fabbcSTim J. Robbins 				printf("Linux ELF exec handler removed\n");
1072ea0fabbcSTim J. Robbins 			linux_mib_destroy();
1073ea0fabbcSTim J. Robbins 		} else
1074ea0fabbcSTim J. Robbins 			printf("Could not deinstall ELF interpreter entry\n");
1075ea0fabbcSTim J. Robbins 		break;
1076ea0fabbcSTim J. Robbins 	default:
1077ea0fabbcSTim J. Robbins 		break;
1078ea0fabbcSTim J. Robbins 	}
1079ea0fabbcSTim J. Robbins 	return error;
1080ea0fabbcSTim J. Robbins }
1081ea0fabbcSTim J. Robbins 
1082ea0fabbcSTim J. Robbins static moduledata_t linux_elf_mod = {
1083ea0fabbcSTim J. Robbins 	"linuxelf",
1084ea0fabbcSTim J. Robbins 	linux_elf_modevent,
1085ea0fabbcSTim J. Robbins 	0
1086ea0fabbcSTim J. Robbins };
1087ea0fabbcSTim J. Robbins 
1088ea0fabbcSTim J. Robbins DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY);
1089