164921Smarcel/*-
264921Smarcel * Copyright (c) 2000 Marcel Moolenaar
364921Smarcel * All rights reserved.
464921Smarcel *
564921Smarcel * Redistribution and use in source and binary forms, with or without
664921Smarcel * modification, are permitted provided that the following conditions
764921Smarcel * are met:
864921Smarcel * 1. Redistributions of source code must retain the above copyright
9111798Sdes *    notice, this list of conditions and the following disclaimer
1064921Smarcel *    in this position and unchanged.
1164921Smarcel * 2. Redistributions in binary form must reproduce the above copyright
1264921Smarcel *    notice, this list of conditions and the following disclaimer in the
1364921Smarcel *    documentation and/or other materials provided with the distribution.
1464921Smarcel * 3. The name of the author may not be used to endorse or promote products
1565067Smarcel *    derived from this software without specific prior written permission.
1664921Smarcel *
1764921Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1864921Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1964921Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2064921Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2164921Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2264921Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2364921Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2464921Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2564921Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2664921Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2764921Smarcel */
2864921Smarcel
29115705Sobrien#include <sys/cdefs.h>
30115705Sobrien__FBSDID("$FreeBSD$");
31115705Sobrien
3264921Smarcel#include <sys/param.h>
3376166Smarkm#include <sys/systm.h>
34224778Srwatson#include <sys/capability.h>
35162472Snetchild#include <sys/file.h>
36162472Snetchild#include <sys/fcntl.h>
37140992Ssobomax#include <sys/imgact.h>
3884811Sjhb#include <sys/lock.h>
39140992Ssobomax#include <sys/malloc.h>
4064921Smarcel#include <sys/mman.h>
4176166Smarkm#include <sys/mutex.h>
42161310Snetchild#include <sys/sx.h>
43164033Srwatson#include <sys/priv.h>
4464921Smarcel#include <sys/proc.h>
45161310Snetchild#include <sys/queue.h>
4676166Smarkm#include <sys/resource.h>
4776166Smarkm#include <sys/resourcevar.h>
48134838Sdfr#include <sys/signalvar.h>
49102814Siedowse#include <sys/syscallsubr.h>
5064921Smarcel#include <sys/sysproto.h>
5164921Smarcel#include <sys/unistd.h>
52161310Snetchild#include <sys/wait.h>
53166188Sjeff#include <sys/sched.h>
5464921Smarcel
5564921Smarcel#include <machine/frame.h>
5664921Smarcel#include <machine/psl.h>
5764921Smarcel#include <machine/segments.h>
5864921Smarcel#include <machine/sysarch.h>
5964921Smarcel
6067238Sgallatin#include <vm/vm.h>
6167238Sgallatin#include <vm/pmap.h>
6267238Sgallatin#include <vm/vm_map.h>
6367238Sgallatin
6464921Smarcel#include <i386/linux/linux.h>
6568583Smarcel#include <i386/linux/linux_proto.h>
6664921Smarcel#include <compat/linux/linux_ipc.h>
67218030Sdchagin#include <compat/linux/linux_misc.h>
6864921Smarcel#include <compat/linux/linux_signal.h>
6964921Smarcel#include <compat/linux/linux_util.h>
70161310Snetchild#include <compat/linux/linux_emul.h>
7164921Smarcel
72161310Snetchild#include <i386/include/pcb.h>			/* needed for pcb definition in linux_set_thread_area */
73161310Snetchild
74161310Snetchild#include "opt_posix.h"
75161310Snetchild
76161310Snetchildextern struct sysentvec elf32_freebsd_sysvec;	/* defined in i386/i386/elf_machdep.c */
77161310Snetchild
7883221Smarcelstruct l_descriptor {
7983221Smarcel	l_uint		entry_number;
8083221Smarcel	l_ulong		base_addr;
8183221Smarcel	l_uint		limit;
8283221Smarcel	l_uint		seg_32bit:1;
8383221Smarcel	l_uint		contents:2;
8483221Smarcel	l_uint		read_exec_only:1;
8583221Smarcel	l_uint		limit_in_pages:1;
8683221Smarcel	l_uint		seg_not_present:1;
8783221Smarcel	l_uint		useable:1;
8864921Smarcel};
8964921Smarcel
9083221Smarcelstruct l_old_select_argv {
9183221Smarcel	l_int		nfds;
9283221Smarcel	l_fd_set	*readfds;
9383221Smarcel	l_fd_set	*writefds;
9483221Smarcel	l_fd_set	*exceptfds;
9583221Smarcel	struct l_timeval	*timeout;
9664921Smarcel};
9764921Smarcel
98198554Sjhbstatic int	linux_mmap_common(struct thread *td, l_uintptr_t addr,
99198554Sjhb		    l_size_t len, l_int prot, l_int flags, l_int fd,
100198554Sjhb		    l_loff_t pos);
101198554Sjhb
10264921Smarcelint
10367051Sgallatinlinux_to_bsd_sigaltstack(int lsa)
10467051Sgallatin{
10567051Sgallatin	int bsa = 0;
10667051Sgallatin
10767051Sgallatin	if (lsa & LINUX_SS_DISABLE)
10867051Sgallatin		bsa |= SS_DISABLE;
10967051Sgallatin	if (lsa & LINUX_SS_ONSTACK)
11067051Sgallatin		bsa |= SS_ONSTACK;
11167051Sgallatin	return (bsa);
11267051Sgallatin}
11367051Sgallatin
11467051Sgallatinint
11567051Sgallatinbsd_to_linux_sigaltstack(int bsa)
11667051Sgallatin{
11767051Sgallatin	int lsa = 0;
11867051Sgallatin
11967051Sgallatin	if (bsa & SS_DISABLE)
12067051Sgallatin		lsa |= LINUX_SS_DISABLE;
12167051Sgallatin	if (bsa & SS_ONSTACK)
12267051Sgallatin		lsa |= LINUX_SS_ONSTACK;
12367051Sgallatin	return (lsa);
12467051Sgallatin}
12567051Sgallatin
12667051Sgallatinint
12783366Sjulianlinux_execve(struct thread *td, struct linux_execve_args *args)
12864921Smarcel{
129140992Ssobomax	int error;
130140992Ssobomax	char *newpath;
131140992Ssobomax	struct image_args eargs;
13264921Smarcel
133141468Sjhb	LCONVPATHEXIST(td, args->path, &newpath);
13464921Smarcel
13564921Smarcel#ifdef DEBUG
13672543Sjlemon	if (ldebug(execve))
137140992Ssobomax		printf(ARGS(execve, "%s"), newpath);
13864921Smarcel#endif
13964921Smarcel
140140992Ssobomax	error = exec_copyin_args(&eargs, newpath, UIO_SYSSPACE,
141140992Ssobomax	    args->argp, args->envp);
142140992Ssobomax	free(newpath, M_TEMP);
143140992Ssobomax	if (error == 0)
144148623Ssobomax		error = kern_execve(td, &eargs, NULL);
145161310Snetchild	if (error == 0)
146161310Snetchild	   	/* linux process can exec fbsd one, dont attempt
147161310Snetchild		 * to create emuldata for such process using
148161310Snetchild		 * linux_proc_init, this leads to a panic on KASSERT
149161310Snetchild		 * because such process has p->p_emuldata == NULL
150161310Snetchild		 */
151217896Sdchagin		if (SV_PROC_ABI(td->td_proc) == SV_ABI_LINUX)
152217896Sdchagin   			error = linux_proc_init(td, 0, 0);
153140992Ssobomax	return (error);
15464921Smarcel}
15564921Smarcel
15683221Smarcelstruct l_ipc_kludge {
15783221Smarcel	struct l_msgbuf *msgp;
15883221Smarcel	l_long msgtyp;
15983221Smarcel};
16083221Smarcel
16164921Smarcelint
16283366Sjulianlinux_ipc(struct thread *td, struct linux_ipc_args *args)
16364921Smarcel{
16483221Smarcel
16583221Smarcel	switch (args->what & 0xFFFF) {
16683221Smarcel	case LINUX_SEMOP: {
16783221Smarcel		struct linux_semop_args a;
16883221Smarcel
16983221Smarcel		a.semid = args->arg1;
17083221Smarcel		a.tsops = args->ptr;
17183221Smarcel		a.nsops = args->arg2;
17283366Sjulian		return (linux_semop(td, &a));
17364921Smarcel	}
17483221Smarcel	case LINUX_SEMGET: {
17583221Smarcel		struct linux_semget_args a;
17664921Smarcel
17783221Smarcel		a.key = args->arg1;
17883221Smarcel		a.nsems = args->arg2;
17983221Smarcel		a.semflg = args->arg3;
18083366Sjulian		return (linux_semget(td, &a));
18183221Smarcel	}
18283221Smarcel	case LINUX_SEMCTL: {
18383221Smarcel		struct linux_semctl_args a;
18483221Smarcel		int error;
18583221Smarcel
18683221Smarcel		a.semid = args->arg1;
18783221Smarcel		a.semnum = args->arg2;
18883221Smarcel		a.cmd = args->arg3;
189111797Sdes		error = copyin(args->ptr, &a.arg, sizeof(a.arg));
19083221Smarcel		if (error)
19183221Smarcel			return (error);
19283366Sjulian		return (linux_semctl(td, &a));
19383221Smarcel	}
19483221Smarcel	case LINUX_MSGSND: {
19583221Smarcel		struct linux_msgsnd_args a;
19683221Smarcel
19783221Smarcel		a.msqid = args->arg1;
19883221Smarcel		a.msgp = args->ptr;
19983221Smarcel		a.msgsz = args->arg2;
20083221Smarcel		a.msgflg = args->arg3;
20183366Sjulian		return (linux_msgsnd(td, &a));
20283221Smarcel	}
20383221Smarcel	case LINUX_MSGRCV: {
20483221Smarcel		struct linux_msgrcv_args a;
20583221Smarcel
20683221Smarcel		a.msqid = args->arg1;
20783221Smarcel		a.msgsz = args->arg2;
20883221Smarcel		a.msgflg = args->arg3;
20983221Smarcel		if ((args->what >> 16) == 0) {
21083221Smarcel			struct l_ipc_kludge tmp;
21183221Smarcel			int error;
21283221Smarcel
21383221Smarcel			if (args->ptr == NULL)
21483221Smarcel				return (EINVAL);
215111797Sdes			error = copyin(args->ptr, &tmp, sizeof(tmp));
21683221Smarcel			if (error)
21783221Smarcel				return (error);
21883221Smarcel			a.msgp = tmp.msgp;
21983221Smarcel			a.msgtyp = tmp.msgtyp;
22083221Smarcel		} else {
22183221Smarcel			a.msgp = args->ptr;
22283221Smarcel			a.msgtyp = args->arg5;
22383221Smarcel		}
22483366Sjulian		return (linux_msgrcv(td, &a));
22583221Smarcel	}
22683221Smarcel	case LINUX_MSGGET: {
22783221Smarcel		struct linux_msgget_args a;
22883221Smarcel
22983221Smarcel		a.key = args->arg1;
23083221Smarcel		a.msgflg = args->arg2;
23183366Sjulian		return (linux_msgget(td, &a));
23283221Smarcel	}
23383221Smarcel	case LINUX_MSGCTL: {
23483221Smarcel		struct linux_msgctl_args a;
23583221Smarcel
23683221Smarcel		a.msqid = args->arg1;
23783221Smarcel		a.cmd = args->arg2;
23883221Smarcel		a.buf = args->ptr;
23983366Sjulian		return (linux_msgctl(td, &a));
24083221Smarcel	}
24183221Smarcel	case LINUX_SHMAT: {
24283221Smarcel		struct linux_shmat_args a;
24383221Smarcel
24483221Smarcel		a.shmid = args->arg1;
24583221Smarcel		a.shmaddr = args->ptr;
24683221Smarcel		a.shmflg = args->arg2;
24783221Smarcel		a.raddr = (l_ulong *)args->arg3;
24883366Sjulian		return (linux_shmat(td, &a));
24983221Smarcel	}
25083221Smarcel	case LINUX_SHMDT: {
25183221Smarcel		struct linux_shmdt_args a;
25283221Smarcel
25383221Smarcel		a.shmaddr = args->ptr;
25483366Sjulian		return (linux_shmdt(td, &a));
25583221Smarcel	}
25683221Smarcel	case LINUX_SHMGET: {
25783221Smarcel		struct linux_shmget_args a;
25883221Smarcel
25983221Smarcel		a.key = args->arg1;
26083221Smarcel		a.size = args->arg2;
26183221Smarcel		a.shmflg = args->arg3;
26283366Sjulian		return (linux_shmget(td, &a));
26383221Smarcel	}
26483221Smarcel	case LINUX_SHMCTL: {
26583221Smarcel		struct linux_shmctl_args a;
26683221Smarcel
26783221Smarcel		a.shmid = args->arg1;
26883221Smarcel		a.cmd = args->arg2;
26983221Smarcel		a.buf = args->ptr;
27083366Sjulian		return (linux_shmctl(td, &a));
27183221Smarcel	}
27283221Smarcel	default:
27383221Smarcel		break;
27483221Smarcel	}
27583221Smarcel
27683221Smarcel	return (EINVAL);
27764921Smarcel}
27864921Smarcel
27964921Smarcelint
28083366Sjulianlinux_old_select(struct thread *td, struct linux_old_select_args *args)
28164921Smarcel{
28283221Smarcel	struct l_old_select_argv linux_args;
28383221Smarcel	struct linux_select_args newsel;
28464921Smarcel	int error;
28564921Smarcel
28683221Smarcel#ifdef DEBUG
28783221Smarcel	if (ldebug(old_select))
28891437Speter		printf(ARGS(old_select, "%p"), args->ptr);
28964921Smarcel#endif
29064921Smarcel
291111797Sdes	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
29264921Smarcel	if (error)
29364921Smarcel		return (error);
29464921Smarcel
29564921Smarcel	newsel.nfds = linux_args.nfds;
29664921Smarcel	newsel.readfds = linux_args.readfds;
29764921Smarcel	newsel.writefds = linux_args.writefds;
29864921Smarcel	newsel.exceptfds = linux_args.exceptfds;
29964921Smarcel	newsel.timeout = linux_args.timeout;
30083366Sjulian	return (linux_select(td, &newsel));
30164921Smarcel}
30264921Smarcel
30364921Smarcelint
304218612Sdchaginlinux_set_cloned_tls(struct thread *td, void *desc)
305218612Sdchagin{
306218612Sdchagin	struct segment_descriptor sd;
307218612Sdchagin	struct l_user_desc info;
308218612Sdchagin	int idx, error;
309218612Sdchagin	int a[2];
310218612Sdchagin
311218612Sdchagin	error = copyin(desc, &info, sizeof(struct l_user_desc));
312218612Sdchagin	if (error) {
313218612Sdchagin		printf(LMSG("copyin failed!"));
314218612Sdchagin	} else {
315218612Sdchagin		idx = info.entry_number;
316218612Sdchagin
317218612Sdchagin		/*
318218612Sdchagin		 * looks like we're getting the idx we returned
319218612Sdchagin		 * in the set_thread_area() syscall
320218612Sdchagin		 */
321218612Sdchagin		if (idx != 6 && idx != 3) {
322218612Sdchagin			printf(LMSG("resetting idx!"));
323218612Sdchagin			idx = 3;
324218612Sdchagin		}
325218612Sdchagin
326218612Sdchagin		/* this doesnt happen in practice */
327218612Sdchagin		if (idx == 6) {
328218612Sdchagin	   		/* we might copy out the entry_number as 3 */
329218612Sdchagin		   	info.entry_number = 3;
330218612Sdchagin			error = copyout(&info, desc, sizeof(struct l_user_desc));
331218612Sdchagin			if (error)
332218612Sdchagin				printf(LMSG("copyout failed!"));
333218612Sdchagin		}
334218612Sdchagin
335218612Sdchagin		a[0] = LINUX_LDT_entry_a(&info);
336218612Sdchagin		a[1] = LINUX_LDT_entry_b(&info);
337218612Sdchagin
338218612Sdchagin		memcpy(&sd, &a, sizeof(a));
339218612Sdchagin#ifdef DEBUG
340218612Sdchagin		if (ldebug(clone))
341218612Sdchagin			printf("Segment created in clone with "
342218612Sdchagin			"CLONE_SETTLS: lobase: %x, hibase: %x, "
343218612Sdchagin			"lolimit: %x, hilimit: %x, type: %i, "
344218612Sdchagin			"dpl: %i, p: %i, xx: %i, def32: %i, "
345218612Sdchagin			"gran: %i\n", sd.sd_lobase, sd.sd_hibase,
346218612Sdchagin			sd.sd_lolimit, sd.sd_hilimit, sd.sd_type,
347218612Sdchagin			sd.sd_dpl, sd.sd_p, sd.sd_xx,
348218612Sdchagin			sd.sd_def32, sd.sd_gran);
349218612Sdchagin#endif
350218612Sdchagin
351218612Sdchagin		/* set %gs */
352218612Sdchagin		td->td_pcb->pcb_gsd = sd;
353218612Sdchagin		td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL);
354218612Sdchagin	}
355218612Sdchagin
356218612Sdchagin	return (error);
357218612Sdchagin}
358218612Sdchagin
35964921Smarcelint
360218613Sdchaginlinux_set_upcall_kse(struct thread *td, register_t stack)
361218613Sdchagin{
362218613Sdchagin
363218613Sdchagin	td->td_frame->tf_esp = stack;
364218613Sdchagin
365218613Sdchagin	return (0);
366218613Sdchagin}
367218613Sdchagin
36864921Smarcel#define STACK_SIZE  (2 * 1024 * 1024)
36964921Smarcel#define GUARD_SIZE  (4 * PAGE_SIZE)
37064921Smarcel
37164921Smarcelint
372104893Ssobomaxlinux_mmap2(struct thread *td, struct linux_mmap2_args *args)
373104893Ssobomax{
374104893Ssobomax
375104893Ssobomax#ifdef DEBUG
376104893Ssobomax	if (ldebug(mmap2))
377111798Sdes		printf(ARGS(mmap2, "%p, %d, %d, 0x%08x, %d, %d"),
378111798Sdes		    (void *)args->addr, args->len, args->prot,
379111798Sdes		    args->flags, args->fd, args->pgoff);
380104893Ssobomax#endif
381104893Ssobomax
382198554Sjhb	return (linux_mmap_common(td, args->addr, args->len, args->prot,
383198554Sjhb		args->flags, args->fd, (uint64_t)(uint32_t)args->pgoff *
384198554Sjhb		PAGE_SIZE));
385104893Ssobomax}
386104893Ssobomax
387104893Ssobomaxint
38883366Sjulianlinux_mmap(struct thread *td, struct linux_mmap_args *args)
38964921Smarcel{
39064921Smarcel	int error;
39183221Smarcel	struct l_mmap_argv linux_args;
39264921Smarcel
393111797Sdes	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
39464921Smarcel	if (error)
39564921Smarcel		return (error);
39664921Smarcel
39764921Smarcel#ifdef DEBUG
39872543Sjlemon	if (ldebug(mmap))
39972543Sjlemon		printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"),
400104984Sbde		    (void *)linux_args.addr, linux_args.len, linux_args.prot,
401166727Sjkim		    linux_args.flags, linux_args.fd, linux_args.pgoff);
40264921Smarcel#endif
40364921Smarcel
404198554Sjhb	return (linux_mmap_common(td, linux_args.addr, linux_args.len,
405198554Sjhb	    linux_args.prot, linux_args.flags, linux_args.fd,
406198554Sjhb	    (uint32_t)linux_args.pgoff));
407104893Ssobomax}
408104893Ssobomax
409104893Ssobomaxstatic int
410198554Sjhblinux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot,
411198554Sjhb    l_int flags, l_int fd, l_loff_t pos)
412104893Ssobomax{
413104893Ssobomax	struct proc *p = td->td_proc;
414104893Ssobomax	struct mmap_args /* {
415104893Ssobomax		caddr_t addr;
416104893Ssobomax		size_t len;
417104893Ssobomax		int prot;
418104893Ssobomax		int flags;
419104893Ssobomax		int fd;
420104893Ssobomax		long pad;
421104893Ssobomax		off_t pos;
422104893Ssobomax	} */ bsd_args;
423112630Smdodd	int error;
424162472Snetchild	struct file *fp;
425255219Spjd	cap_rights_t rights;
426104893Ssobomax
427112630Smdodd	error = 0;
42864921Smarcel	bsd_args.flags = 0;
429162472Snetchild	fp = NULL;
430162472Snetchild
431162472Snetchild	/*
432162472Snetchild	 * Linux mmap(2):
433162472Snetchild	 * You must specify exactly one of MAP_SHARED and MAP_PRIVATE
434162472Snetchild	 */
435198554Sjhb	if (!((flags & LINUX_MAP_SHARED) ^ (flags & LINUX_MAP_PRIVATE)))
436162479Snetchild		return (EINVAL);
437162472Snetchild
438198554Sjhb	if (flags & LINUX_MAP_SHARED)
43964921Smarcel		bsd_args.flags |= MAP_SHARED;
440198554Sjhb	if (flags & LINUX_MAP_PRIVATE)
44164921Smarcel		bsd_args.flags |= MAP_PRIVATE;
442198554Sjhb	if (flags & LINUX_MAP_FIXED)
44364921Smarcel		bsd_args.flags |= MAP_FIXED;
444208994Skan	if (flags & LINUX_MAP_ANON) {
445208994Skan		/* Enforce pos to be on page boundary, then ignore. */
446208994Skan		if ((pos & PAGE_MASK) != 0)
447208994Skan			return (EINVAL);
448208994Skan		pos = 0;
44964921Smarcel		bsd_args.flags |= MAP_ANON;
450208994Skan	} else
45173213Sdillon		bsd_args.flags |= MAP_NOSYNC;
452198554Sjhb	if (flags & LINUX_MAP_GROWSDOWN)
45364921Smarcel		bsd_args.flags |= MAP_STACK;
45464921Smarcel
455166727Sjkim	/*
456166727Sjkim	 * PROT_READ, PROT_WRITE, or PROT_EXEC implies PROT_READ and PROT_EXEC
457166727Sjkim	 * on Linux/i386. We do this to ensure maximum compatibility.
458166727Sjkim	 * Linux/ia64 does the same in i386 emulation mode.
459166727Sjkim	 */
460198554Sjhb	bsd_args.prot = prot;
461166727Sjkim	if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC))
462166727Sjkim		bsd_args.prot |= PROT_READ | PROT_EXEC;
463166727Sjkim
464167048Sjkim	/* Linux does not check file descriptor when MAP_ANONYMOUS is set. */
465198554Sjhb	bsd_args.fd = (bsd_args.flags & MAP_ANON) ? -1 : fd;
466167048Sjkim	if (bsd_args.fd != -1) {
467166727Sjkim		/*
468166727Sjkim		 * Linux follows Solaris mmap(2) description:
469166727Sjkim		 * The file descriptor fildes is opened with
470166727Sjkim		 * read permission, regardless of the
471166727Sjkim		 * protection options specified.
472224778Srwatson		 *
473224778Srwatson		 * Checking just CAP_MMAP is fine here, since the real work
474224778Srwatson		 * is done in the FreeBSD mmap().
475166727Sjkim		 */
476166727Sjkim
477255219Spjd		error = fget(td, bsd_args.fd,
478255219Spjd		    cap_rights_init(&rights, CAP_MMAP), &fp);
479255219Spjd		if (error != 0)
480166727Sjkim			return (error);
481166727Sjkim		if (fp->f_type != DTYPE_VNODE) {
482166727Sjkim			fdrop(fp, td);
483166727Sjkim			return (EINVAL);
484166727Sjkim		}
485166727Sjkim
486166727Sjkim		/* Linux mmap() just fails for O_WRONLY files */
487166727Sjkim		if (!(fp->f_flag & FREAD)) {
488166727Sjkim			fdrop(fp, td);
489166727Sjkim			return (EACCES);
490166727Sjkim		}
491166727Sjkim
492166727Sjkim		fdrop(fp, td);
493166727Sjkim	}
494166727Sjkim
495198554Sjhb	if (flags & LINUX_MAP_GROWSDOWN) {
496161365Snetchild		/*
497198554Sjhb		 * The Linux MAP_GROWSDOWN option does not limit auto
49864921Smarcel		 * growth of the region.  Linux mmap with this option
49964921Smarcel		 * takes as addr the inital BOS, and as len, the initial
50064921Smarcel		 * region size.  It can then grow down from addr without
50164921Smarcel		 * limit.  However, linux threads has an implicit internal
50264921Smarcel		 * limit to stack size of STACK_SIZE.  Its just not
50364921Smarcel		 * enforced explicitly in linux.  But, here we impose
50464921Smarcel		 * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
50564921Smarcel		 * region, since we can do this with our mmap.
50664921Smarcel		 *
50764921Smarcel		 * Our mmap with MAP_STACK takes addr as the maximum
50864921Smarcel		 * downsize limit on BOS, and as len the max size of
50964921Smarcel		 * the region.  It them maps the top SGROWSIZ bytes,
510166944Snetchild		 * and auto grows the region down, up to the limit
51164921Smarcel		 * in addr.
51264921Smarcel		 *
51364921Smarcel		 * If we don't use the MAP_STACK option, the effect
51464921Smarcel		 * of this code is to allocate a stack region of a
51564921Smarcel		 * fixed size of (STACK_SIZE - GUARD_SIZE).
51664921Smarcel		 */
51764921Smarcel
518198554Sjhb		if ((caddr_t)PTRIN(addr) + len > p->p_vmspace->vm_maxsaddr) {
519161365Snetchild			/*
520161365Snetchild			 * Some linux apps will attempt to mmap
52167238Sgallatin			 * thread stacks near the top of their
52267238Sgallatin			 * address space.  If their TOS is greater
52367238Sgallatin			 * than vm_maxsaddr, vm_map_growstack()
52467238Sgallatin			 * will confuse the thread stack with the
52567238Sgallatin			 * process stack and deliver a SEGV if they
52667238Sgallatin			 * attempt to grow the thread stack past their
52767238Sgallatin			 * current stacksize rlimit.  To avoid this,
52867238Sgallatin			 * adjust vm_maxsaddr upwards to reflect
52967238Sgallatin			 * the current stacksize rlimit rather
53067238Sgallatin			 * than the maximum possible stacksize.
53167238Sgallatin			 * It would be better to adjust the
53267238Sgallatin			 * mmap'ed region, but some apps do not check
53367238Sgallatin			 * mmap's return value.
53467238Sgallatin			 */
535125454Sjhb			PROC_LOCK(p);
53667238Sgallatin			p->p_vmspace->vm_maxsaddr = (char *)USRSTACK -
537125454Sjhb			    lim_cur(p, RLIMIT_STACK);
538125454Sjhb			PROC_UNLOCK(p);
53967238Sgallatin		}
54067238Sgallatin
541176193Sjkim		/*
542176193Sjkim		 * This gives us our maximum stack size and a new BOS.
543176193Sjkim		 * If we're using VM_STACK, then mmap will just map
544176193Sjkim		 * the top SGROWSIZ bytes, and let the stack grow down
545176193Sjkim		 * to the limit at BOS.  If we're not using VM_STACK
546176193Sjkim		 * we map the full stack, since we don't have a way
547176193Sjkim		 * to autogrow it.
548176193Sjkim		 */
549198554Sjhb		if (len > STACK_SIZE - GUARD_SIZE) {
550198554Sjhb			bsd_args.addr = (caddr_t)PTRIN(addr);
551198554Sjhb			bsd_args.len = len;
552176193Sjkim		} else {
553198554Sjhb			bsd_args.addr = (caddr_t)PTRIN(addr) -
554198554Sjhb			    (STACK_SIZE - GUARD_SIZE - len);
555176193Sjkim			bsd_args.len = STACK_SIZE - GUARD_SIZE;
556176193Sjkim		}
55764921Smarcel	} else {
558198554Sjhb		bsd_args.addr = (caddr_t)PTRIN(addr);
559198554Sjhb		bsd_args.len  = len;
56064921Smarcel	}
561198554Sjhb	bsd_args.pos = pos;
56264921Smarcel
56364921Smarcel#ifdef DEBUG
56472543Sjlemon	if (ldebug(mmap))
565112630Smdodd		printf("-> %s(%p, %d, %d, 0x%08x, %d, 0x%x)\n",
566112630Smdodd		    __func__,
56772543Sjlemon		    (void *)bsd_args.addr, bsd_args.len, bsd_args.prot,
56872543Sjlemon		    bsd_args.flags, bsd_args.fd, (int)bsd_args.pos);
56964921Smarcel#endif
570225617Skmacy	error = sys_mmap(td, &bsd_args);
571112630Smdodd#ifdef DEBUG
572112630Smdodd	if (ldebug(mmap))
573112630Smdodd		printf("-> %s() return: 0x%x (0x%08x)\n",
574112630Smdodd			__func__, error, (u_int)td->td_retval[0]);
575112630Smdodd#endif
576112630Smdodd	return (error);
57764921Smarcel}
57864921Smarcel
57964921Smarcelint
580166727Sjkimlinux_mprotect(struct thread *td, struct linux_mprotect_args *uap)
581166727Sjkim{
582166727Sjkim	struct mprotect_args bsd_args;
583166727Sjkim
584166727Sjkim	bsd_args.addr = uap->addr;
585166727Sjkim	bsd_args.len = uap->len;
586166727Sjkim	bsd_args.prot = uap->prot;
587166727Sjkim	if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC))
588166727Sjkim		bsd_args.prot |= PROT_READ | PROT_EXEC;
589225617Skmacy	return (sys_mprotect(td, &bsd_args));
590166727Sjkim}
591166727Sjkim
592166727Sjkimint
59383366Sjulianlinux_ioperm(struct thread *td, struct linux_ioperm_args *args)
59464921Smarcel{
595140862Ssobomax	int error;
596140862Ssobomax	struct i386_ioperm_args iia;
59764921Smarcel
598140862Ssobomax	iia.start = args->start;
599140862Ssobomax	iia.length = args->length;
600140862Ssobomax	iia.enable = args->enable;
601140862Ssobomax	error = i386_set_ioperm(td, &iia);
602140862Ssobomax	return (error);
60364921Smarcel}
60464921Smarcel
60564921Smarcelint
60683366Sjulianlinux_iopl(struct thread *td, struct linux_iopl_args *args)
60764921Smarcel{
60864921Smarcel	int error;
60964921Smarcel
61064921Smarcel	if (args->level < 0 || args->level > 3)
61164921Smarcel		return (EINVAL);
612164033Srwatson	if ((error = priv_check(td, PRIV_IO)) != 0)
61364921Smarcel		return (error);
61491406Sjhb	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
61583981Srwatson		return (error);
61683366Sjulian	td->td_frame->tf_eflags = (td->td_frame->tf_eflags & ~PSL_IOPL) |
61764921Smarcel	    (args->level * (PSL_IOPL / 3));
61864921Smarcel	return (0);
61964921Smarcel}
62064921Smarcel
62164921Smarcelint
622105441Smarkmlinux_modify_ldt(struct thread *td, struct linux_modify_ldt_args *uap)
62364921Smarcel{
62464921Smarcel	int error;
625140862Ssobomax	struct i386_ldt_args ldt;
62683221Smarcel	struct l_descriptor ld;
627140862Ssobomax	union descriptor desc;
628173937Skib	int size, written;
62964921Smarcel
63064921Smarcel	switch (uap->func) {
63164921Smarcel	case 0x00: /* read_ldt */
632140862Ssobomax		ldt.start = 0;
633140862Ssobomax		ldt.descs = uap->ptr;
634140862Ssobomax		ldt.num = uap->bytecount / sizeof(union descriptor);
635140862Ssobomax		error = i386_get_ldt(td, &ldt);
63683366Sjulian		td->td_retval[0] *= sizeof(union descriptor);
63764921Smarcel		break;
638173937Skib	case 0x02: /* read_default_ldt = 0 */
639173937Skib		size = 5*sizeof(struct l_desc_struct);
640173937Skib		if (size > uap->bytecount)
641173937Skib			size = uap->bytecount;
642173937Skib		for (written = error = 0; written < size && error == 0; written++)
643173937Skib			error = subyte((char *)uap->ptr + written, 0);
644173937Skib		td->td_retval[0] = written;
645173937Skib		break;
64664921Smarcel	case 0x01: /* write_ldt */
64764921Smarcel	case 0x11: /* write_ldt */
64864921Smarcel		if (uap->bytecount != sizeof(ld))
64964921Smarcel			return (EINVAL);
65064921Smarcel
65164921Smarcel		error = copyin(uap->ptr, &ld, sizeof(ld));
65264921Smarcel		if (error)
65364921Smarcel			return (error);
65464921Smarcel
655140862Ssobomax		ldt.start = ld.entry_number;
656140862Ssobomax		ldt.descs = &desc;
657140862Ssobomax		ldt.num = 1;
658140862Ssobomax		desc.sd.sd_lolimit = (ld.limit & 0x0000ffff);
659140862Ssobomax		desc.sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16;
660140862Ssobomax		desc.sd.sd_lobase = (ld.base_addr & 0x00ffffff);
661140862Ssobomax		desc.sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24;
662140862Ssobomax		desc.sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) |
66364921Smarcel			(ld.contents << 2);
664140862Ssobomax		desc.sd.sd_dpl = 3;
665140862Ssobomax		desc.sd.sd_p = (ld.seg_not_present ^ 1);
666140862Ssobomax		desc.sd.sd_xx = 0;
667140862Ssobomax		desc.sd.sd_def32 = ld.seg_32bit;
668140862Ssobomax		desc.sd.sd_gran = ld.limit_in_pages;
669140862Ssobomax		error = i386_set_ldt(td, &ldt, &desc);
67064921Smarcel		break;
67164921Smarcel	default:
672195074Sjhb		error = ENOSYS;
67364921Smarcel		break;
67464921Smarcel	}
67564921Smarcel
67664921Smarcel	if (error == EOPNOTSUPP) {
67764921Smarcel		printf("linux: modify_ldt needs kernel option USER_LDT\n");
67864921Smarcel		error = ENOSYS;
67964921Smarcel	}
68064921Smarcel
68164921Smarcel	return (error);
68264921Smarcel}
68364921Smarcel
68464921Smarcelint
68583366Sjulianlinux_sigaction(struct thread *td, struct linux_sigaction_args *args)
68664921Smarcel{
68783221Smarcel	l_osigaction_t osa;
68883221Smarcel	l_sigaction_t act, oact;
68964921Smarcel	int error;
69064921Smarcel
69164921Smarcel#ifdef DEBUG
69272543Sjlemon	if (ldebug(sigaction))
69372543Sjlemon		printf(ARGS(sigaction, "%d, %p, %p"),
69472543Sjlemon		    args->sig, (void *)args->nsa, (void *)args->osa);
69564921Smarcel#endif
69664921Smarcel
69764921Smarcel	if (args->nsa != NULL) {
698111797Sdes		error = copyin(args->nsa, &osa, sizeof(l_osigaction_t));
69964921Smarcel		if (error)
70064921Smarcel			return (error);
70164921Smarcel		act.lsa_handler = osa.lsa_handler;
70264921Smarcel		act.lsa_flags = osa.lsa_flags;
70364921Smarcel		act.lsa_restorer = osa.lsa_restorer;
70464921Smarcel		LINUX_SIGEMPTYSET(act.lsa_mask);
70564921Smarcel		act.lsa_mask.__bits[0] = osa.lsa_mask;
70664921Smarcel	}
70764921Smarcel
70883366Sjulian	error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL,
70964921Smarcel	    args->osa ? &oact : NULL);
71064921Smarcel
71164921Smarcel	if (args->osa != NULL && !error) {
71264921Smarcel		osa.lsa_handler = oact.lsa_handler;
71364921Smarcel		osa.lsa_flags = oact.lsa_flags;
71464921Smarcel		osa.lsa_restorer = oact.lsa_restorer;
71564921Smarcel		osa.lsa_mask = oact.lsa_mask.__bits[0];
716111797Sdes		error = copyout(&osa, args->osa, sizeof(l_osigaction_t));
71764921Smarcel	}
71864921Smarcel
71964921Smarcel	return (error);
72064921Smarcel}
72164921Smarcel
72264921Smarcel/*
72364921Smarcel * Linux has two extra args, restart and oldmask.  We dont use these,
72464921Smarcel * but it seems that "restart" is actually a context pointer that
72564921Smarcel * enables the signal to happen with a different register set.
72664921Smarcel */
72764921Smarcelint
72883366Sjulianlinux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args)
72964921Smarcel{
730102814Siedowse	sigset_t sigmask;
73183221Smarcel	l_sigset_t mask;
73264921Smarcel
73364921Smarcel#ifdef DEBUG
73472543Sjlemon	if (ldebug(sigsuspend))
73572543Sjlemon		printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
73664921Smarcel#endif
73764921Smarcel
73864921Smarcel	LINUX_SIGEMPTYSET(mask);
73964921Smarcel	mask.__bits[0] = args->mask;
740102814Siedowse	linux_to_bsd_sigset(&mask, &sigmask);
741102814Siedowse	return (kern_sigsuspend(td, sigmask));
74264921Smarcel}
74364921Smarcel
74464921Smarcelint
745105441Smarkmlinux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap)
74664921Smarcel{
74783221Smarcel	l_sigset_t lmask;
748102814Siedowse	sigset_t sigmask;
74964921Smarcel	int error;
75064921Smarcel
75164921Smarcel#ifdef DEBUG
75272543Sjlemon	if (ldebug(rt_sigsuspend))
75372543Sjlemon		printf(ARGS(rt_sigsuspend, "%p, %d"),
75472543Sjlemon		    (void *)uap->newset, uap->sigsetsize);
75564921Smarcel#endif
75664921Smarcel
75783221Smarcel	if (uap->sigsetsize != sizeof(l_sigset_t))
75864921Smarcel		return (EINVAL);
75964921Smarcel
76083221Smarcel	error = copyin(uap->newset, &lmask, sizeof(l_sigset_t));
76164921Smarcel	if (error)
76264921Smarcel		return (error);
76364921Smarcel
764102814Siedowse	linux_to_bsd_sigset(&lmask, &sigmask);
765102814Siedowse	return (kern_sigsuspend(td, sigmask));
76664921Smarcel}
76764921Smarcel
76864921Smarcelint
76983366Sjulianlinux_pause(struct thread *td, struct linux_pause_args *args)
77064921Smarcel{
77183366Sjulian	struct proc *p = td->td_proc;
772102814Siedowse	sigset_t sigmask;
77364921Smarcel
77464921Smarcel#ifdef DEBUG
77572543Sjlemon	if (ldebug(pause))
77672543Sjlemon		printf(ARGS(pause, ""));
77764921Smarcel#endif
77864921Smarcel
77971494Sjhb	PROC_LOCK(p);
780112888Sjeff	sigmask = td->td_sigmask;
78171494Sjhb	PROC_UNLOCK(p);
782102814Siedowse	return (kern_sigsuspend(td, sigmask));
78364921Smarcel}
78464921Smarcel
78564921Smarcelint
78683366Sjulianlinux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
78764921Smarcel{
788102814Siedowse	stack_t ss, oss;
78983221Smarcel	l_stack_t lss;
79064921Smarcel	int error;
79164921Smarcel
79264921Smarcel#ifdef DEBUG
79372543Sjlemon	if (ldebug(sigaltstack))
79472543Sjlemon		printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
79564921Smarcel#endif
79664921Smarcel
797102814Siedowse	if (uap->uss != NULL) {
79883221Smarcel		error = copyin(uap->uss, &lss, sizeof(l_stack_t));
79967051Sgallatin		if (error)
80067051Sgallatin			return (error);
80164921Smarcel
802102814Siedowse		ss.ss_sp = lss.ss_sp;
803102814Siedowse		ss.ss_size = lss.ss_size;
804102814Siedowse		ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags);
80567051Sgallatin	}
806134269Sjhb	error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL,
807134269Sjhb	    (uap->uoss != NULL) ? &oss : NULL);
808102814Siedowse	if (!error && uap->uoss != NULL) {
809102814Siedowse		lss.ss_sp = oss.ss_sp;
810102814Siedowse		lss.ss_size = oss.ss_size;
811102814Siedowse		lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags);
81283221Smarcel		error = copyout(&lss, uap->uoss, sizeof(l_stack_t));
81364921Smarcel	}
81464921Smarcel
81564921Smarcel	return (error);
81664921Smarcel}
817104893Ssobomax
818104893Ssobomaxint
819104893Ssobomaxlinux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
820104893Ssobomax{
821104893Ssobomax	struct ftruncate_args sa;
822104893Ssobomax
823104893Ssobomax#ifdef DEBUG
824104893Ssobomax	if (ldebug(ftruncate64))
825104984Sbde		printf(ARGS(ftruncate64, "%u, %jd"), args->fd,
826104984Sbde		    (intmax_t)args->length);
827104893Ssobomax#endif
828104893Ssobomax
829104893Ssobomax	sa.fd = args->fd;
830104893Ssobomax	sa.length = args->length;
831225617Skmacy	return sys_ftruncate(td, &sa);
832104893Ssobomax}
833134838Sdfr
834134838Sdfrint
835134838Sdfrlinux_set_thread_area(struct thread *td, struct linux_set_thread_area_args *args)
836134838Sdfr{
837161310Snetchild	struct l_user_desc info;
838161310Snetchild	int error;
839161310Snetchild	int idx;
840161310Snetchild	int a[2];
841161310Snetchild	struct segment_descriptor sd;
842161310Snetchild
843161310Snetchild	error = copyin(args->desc, &info, sizeof(struct l_user_desc));
844161310Snetchild	if (error)
845161310Snetchild		return (error);
846161310Snetchild
847161310Snetchild#ifdef DEBUG
848161310Snetchild	if (ldebug(set_thread_area))
849161310Snetchild	   	printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, %i, %i, %i\n"),
850161310Snetchild		      info.entry_number,
851161310Snetchild      		      info.base_addr,
852161310Snetchild      		      info.limit,
853161310Snetchild      		      info.seg_32bit,
854161310Snetchild		      info.contents,
855161310Snetchild      		      info.read_exec_only,
856161310Snetchild      		      info.limit_in_pages,
857161310Snetchild      		      info.seg_not_present,
858161310Snetchild      		      info.useable);
859161310Snetchild#endif
860161310Snetchild
861161310Snetchild	idx = info.entry_number;
862161365Snetchild	/*
863166944Snetchild	 * Semantics of linux version: every thread in the system has array of
864166944Snetchild	 * 3 tls descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown. This
865166944Snetchild	 * syscall loads one of the selected tls decriptors with a value and
866166944Snetchild	 * also loads GDT descriptors 6, 7 and 8 with the content of the
867166944Snetchild	 * per-thread descriptors.
868161310Snetchild	 *
869166944Snetchild	 * Semantics of fbsd version: I think we can ignore that linux has 3
870166944Snetchild	 * per-thread descriptors and use just the 1st one. The tls_array[]
871166944Snetchild	 * is used only in set/get-thread_area() syscalls and for loading the
872166944Snetchild	 * GDT descriptors. In fbsd we use just one GDT descriptor for TLS so
873166944Snetchild	 * we will load just one.
874166944Snetchild	 *
875166944Snetchild	 * XXX: this doesn't work when a user space process tries to use more
876166944Snetchild	 * than 1 TLS segment. Comment in the linux sources says wine might do
877166944Snetchild	 * this.
878134838Sdfr	 */
879161310Snetchild
880161365Snetchild	/*
881161365Snetchild	 * we support just GLIBC TLS now
882161310Snetchild	 * we should let 3 proceed as well because we use this segment so
883161310Snetchild	 * if code does two subsequent calls it should succeed
884161310Snetchild	 */
885161310Snetchild	if (idx != 6 && idx != -1 && idx != 3)
886161310Snetchild		return (EINVAL);
887161310Snetchild
888161365Snetchild	/*
889161365Snetchild	 * we have to copy out the GDT entry we use
890166944Snetchild	 * FreeBSD uses GDT entry #3 for storing %gs so load that
891166944Snetchild	 *
892166944Snetchild	 * XXX: what if a user space program doesn't check this value and tries
893161310Snetchild	 * to use 6, 7 or 8?
894161310Snetchild	 */
895161310Snetchild	idx = info.entry_number = 3;
896161310Snetchild	error = copyout(&info, args->desc, sizeof(struct l_user_desc));
897161310Snetchild	if (error)
898161310Snetchild		return (error);
899161310Snetchild
900167157Sjkim	if (LINUX_LDT_empty(&info)) {
901161310Snetchild		a[0] = 0;
902161310Snetchild		a[1] = 0;
903161310Snetchild	} else {
904167157Sjkim		a[0] = LINUX_LDT_entry_a(&info);
905167157Sjkim		a[1] = LINUX_LDT_entry_b(&info);
906161310Snetchild	}
907161310Snetchild
908161310Snetchild	memcpy(&sd, &a, sizeof(a));
909161310Snetchild#ifdef DEBUG
910161310Snetchild	if (ldebug(set_thread_area))
911161310Snetchild	   	printf("Segment created in set_thread_area: lobase: %x, hibase: %x, lolimit: %x, hilimit: %x, type: %i, dpl: %i, p: %i, xx: %i, def32: %i, gran: %i\n", sd.sd_lobase,
912161310Snetchild			sd.sd_hibase,
913161310Snetchild			sd.sd_lolimit,
914161310Snetchild			sd.sd_hilimit,
915161310Snetchild			sd.sd_type,
916161310Snetchild			sd.sd_dpl,
917161310Snetchild			sd.sd_p,
918161310Snetchild			sd.sd_xx,
919161310Snetchild			sd.sd_def32,
920161310Snetchild			sd.sd_gran);
921161310Snetchild#endif
922161310Snetchild
923161310Snetchild	/* this is taken from i386 version of cpu_set_user_tls() */
924161310Snetchild	critical_enter();
925161310Snetchild	/* set %gs */
926161310Snetchild	td->td_pcb->pcb_gsd = sd;
927161310Snetchild	PCPU_GET(fsgs_gdt)[1] = sd;
928161310Snetchild	load_gs(GSEL(GUGS_SEL, SEL_UPL));
929161310Snetchild	critical_exit();
930161310Snetchild
931161310Snetchild	return (0);
932134838Sdfr}
933134838Sdfr
934134838Sdfrint
935161310Snetchildlinux_get_thread_area(struct thread *td, struct linux_get_thread_area_args *args)
936134838Sdfr{
937161310Snetchild
938161310Snetchild	struct l_user_desc info;
939161310Snetchild	int error;
940161310Snetchild	int idx;
941161310Snetchild	struct l_desc_struct desc;
942161310Snetchild	struct segment_descriptor sd;
943134838Sdfr
944161310Snetchild#ifdef DEBUG
945161310Snetchild	if (ldebug(get_thread_area))
946161310Snetchild		printf(ARGS(get_thread_area, "%p"), args->desc);
947161310Snetchild#endif
948161310Snetchild
949161310Snetchild	error = copyin(args->desc, &info, sizeof(struct l_user_desc));
950161310Snetchild	if (error)
951161310Snetchild		return (error);
952161310Snetchild
953161310Snetchild	idx = info.entry_number;
954161310Snetchild	/* XXX: I am not sure if we want 3 to be allowed too. */
955161310Snetchild	if (idx != 6 && idx != 3)
956161310Snetchild		return (EINVAL);
957161310Snetchild
958161310Snetchild	idx = 3;
959161310Snetchild
960161310Snetchild	memset(&info, 0, sizeof(info));
961161310Snetchild
962161310Snetchild	sd = PCPU_GET(fsgs_gdt)[1];
963161310Snetchild
964161310Snetchild	memcpy(&desc, &sd, sizeof(desc));
965161310Snetchild
966161310Snetchild	info.entry_number = idx;
967167157Sjkim	info.base_addr = LINUX_GET_BASE(&desc);
968167157Sjkim	info.limit = LINUX_GET_LIMIT(&desc);
969167157Sjkim	info.seg_32bit = LINUX_GET_32BIT(&desc);
970167157Sjkim	info.contents = LINUX_GET_CONTENTS(&desc);
971167157Sjkim	info.read_exec_only = !LINUX_GET_WRITABLE(&desc);
972167157Sjkim	info.limit_in_pages = LINUX_GET_LIMIT_PAGES(&desc);
973167157Sjkim	info.seg_not_present = !LINUX_GET_PRESENT(&desc);
974167157Sjkim	info.useable = LINUX_GET_USEABLE(&desc);
975161310Snetchild
976161310Snetchild	error = copyout(&info, args->desc, sizeof(struct l_user_desc));
977161310Snetchild	if (error)
978161310Snetchild	   	return (EFAULT);
979161310Snetchild
980134838Sdfr	return (0);
981134838Sdfr}
982134838Sdfr
983161310Snetchild/* copied from kern/kern_time.c */
984134838Sdfrint
985161310Snetchildlinux_timer_create(struct thread *td, struct linux_timer_create_args *args)
986134838Sdfr{
987225617Skmacy   	return sys_ktimer_create(td, (struct ktimer_create_args *) args);
988161310Snetchild}
989134838Sdfr
990161310Snetchildint
991161310Snetchildlinux_timer_settime(struct thread *td, struct linux_timer_settime_args *args)
992161310Snetchild{
993225617Skmacy   	return sys_ktimer_settime(td, (struct ktimer_settime_args *) args);
994134838Sdfr}
995134838Sdfr
996161310Snetchildint
997161310Snetchildlinux_timer_gettime(struct thread *td, struct linux_timer_gettime_args *args)
998161310Snetchild{
999225617Skmacy   	return sys_ktimer_gettime(td, (struct ktimer_gettime_args *) args);
1000161310Snetchild}
1001161310Snetchild
1002161310Snetchildint
1003161310Snetchildlinux_timer_getoverrun(struct thread *td, struct linux_timer_getoverrun_args *args)
1004161310Snetchild{
1005225617Skmacy   	return sys_ktimer_getoverrun(td, (struct ktimer_getoverrun_args *) args);
1006161310Snetchild}
1007161310Snetchild
1008161310Snetchildint
1009161310Snetchildlinux_timer_delete(struct thread *td, struct linux_timer_delete_args *args)
1010161310Snetchild{
1011225617Skmacy   	return sys_ktimer_delete(td, (struct ktimer_delete_args *) args);
1012161310Snetchild}
1013161310Snetchild
1014161310Snetchild/* XXX: this wont work with module - convert it */
1015161310Snetchildint
1016161310Snetchildlinux_mq_open(struct thread *td, struct linux_mq_open_args *args)
1017161310Snetchild{
1018161310Snetchild#ifdef P1003_1B_MQUEUE
1019225617Skmacy   	return sys_kmq_open(td, (struct kmq_open_args *) args);
1020161310Snetchild#else
1021161310Snetchild	return (ENOSYS);
1022161310Snetchild#endif
1023161310Snetchild}
1024161310Snetchild
1025161310Snetchildint
1026161310Snetchildlinux_mq_unlink(struct thread *td, struct linux_mq_unlink_args *args)
1027161310Snetchild{
1028161310Snetchild#ifdef P1003_1B_MQUEUE
1029225617Skmacy   	return sys_kmq_unlink(td, (struct kmq_unlink_args *) args);
1030161310Snetchild#else
1031161310Snetchild	return (ENOSYS);
1032161310Snetchild#endif
1033161310Snetchild}
1034161310Snetchild
1035161310Snetchildint
1036161310Snetchildlinux_mq_timedsend(struct thread *td, struct linux_mq_timedsend_args *args)
1037161310Snetchild{
1038161310Snetchild#ifdef P1003_1B_MQUEUE
1039225617Skmacy   	return sys_kmq_timedsend(td, (struct kmq_timedsend_args *) args);
1040161310Snetchild#else
1041161310Snetchild	return (ENOSYS);
1042161310Snetchild#endif
1043161310Snetchild}
1044161310Snetchild
1045161310Snetchildint
1046161310Snetchildlinux_mq_timedreceive(struct thread *td, struct linux_mq_timedreceive_args *args)
1047161310Snetchild{
1048161310Snetchild#ifdef P1003_1B_MQUEUE
1049225617Skmacy   	return sys_kmq_timedreceive(td, (struct kmq_timedreceive_args *) args);
1050161310Snetchild#else
1051161310Snetchild	return (ENOSYS);
1052161310Snetchild#endif
1053161310Snetchild}
1054161310Snetchild
1055161310Snetchildint
1056161310Snetchildlinux_mq_notify(struct thread *td, struct linux_mq_notify_args *args)
1057161310Snetchild{
1058161310Snetchild#ifdef P1003_1B_MQUEUE
1059225617Skmacy	return sys_kmq_notify(td, (struct kmq_notify_args *) args);
1060161310Snetchild#else
1061161310Snetchild	return (ENOSYS);
1062161310Snetchild#endif
1063161310Snetchild}
1064161310Snetchild
1065161310Snetchildint
1066161310Snetchildlinux_mq_getsetattr(struct thread *td, struct linux_mq_getsetattr_args *args)
1067161310Snetchild{
1068161310Snetchild#ifdef P1003_1B_MQUEUE
1069225617Skmacy   	return sys_kmq_setattr(td, (struct kmq_setattr_args *) args);
1070161310Snetchild#else
1071161310Snetchild	return (ENOSYS);
1072161310Snetchild#endif
1073161310Snetchild}
1074161310Snetchild
1075218030Sdchaginint
1076218030Sdchaginlinux_wait4(struct thread *td, struct linux_wait4_args *args)
1077218030Sdchagin{
1078218030Sdchagin	int error, options;
1079218030Sdchagin	struct rusage ru, *rup;
1080218030Sdchagin
1081218030Sdchagin#ifdef DEBUG
1082218030Sdchagin	if (ldebug(wait4))
1083218030Sdchagin		printf(ARGS(wait4, "%d, %p, %d, %p"),
1084218030Sdchagin		    args->pid, (void *)args->status, args->options,
1085218030Sdchagin		    (void *)args->rusage);
1086218030Sdchagin#endif
1087218030Sdchagin
1088218030Sdchagin	options = (args->options & (WNOHANG | WUNTRACED));
1089218030Sdchagin	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
1090218030Sdchagin	if (args->options & __WCLONE)
1091218030Sdchagin		options |= WLINUXCLONE;
1092218030Sdchagin
1093218030Sdchagin	if (args->rusage != NULL)
1094218030Sdchagin		rup = &ru;
1095218030Sdchagin	else
1096218030Sdchagin		rup = NULL;
1097218030Sdchagin	error = linux_common_wait(td, args->pid, args->status, options, rup);
1098218030Sdchagin	if (error)
1099218030Sdchagin		return (error);
1100218030Sdchagin	if (args->rusage != NULL)
1101218030Sdchagin		error = copyout(&ru, args->rusage, sizeof(ru));
1102218030Sdchagin
1103218030Sdchagin	return (error);
1104218030Sdchagin}
1105