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;
425104893Ssobomax
426112630Smdodd	error = 0;
42764921Smarcel	bsd_args.flags = 0;
428162472Snetchild	fp = NULL;
429162472Snetchild
430162472Snetchild	/*
431162472Snetchild	 * Linux mmap(2):
432162472Snetchild	 * You must specify exactly one of MAP_SHARED and MAP_PRIVATE
433162472Snetchild	 */
434198554Sjhb	if (!((flags & LINUX_MAP_SHARED) ^ (flags & LINUX_MAP_PRIVATE)))
435162479Snetchild		return (EINVAL);
436162472Snetchild
437198554Sjhb	if (flags & LINUX_MAP_SHARED)
43864921Smarcel		bsd_args.flags |= MAP_SHARED;
439198554Sjhb	if (flags & LINUX_MAP_PRIVATE)
44064921Smarcel		bsd_args.flags |= MAP_PRIVATE;
441198554Sjhb	if (flags & LINUX_MAP_FIXED)
44264921Smarcel		bsd_args.flags |= MAP_FIXED;
443208994Skan	if (flags & LINUX_MAP_ANON) {
444208994Skan		/* Enforce pos to be on page boundary, then ignore. */
445208994Skan		if ((pos & PAGE_MASK) != 0)
446208994Skan			return (EINVAL);
447208994Skan		pos = 0;
44864921Smarcel		bsd_args.flags |= MAP_ANON;
449208994Skan	} else
45073213Sdillon		bsd_args.flags |= MAP_NOSYNC;
451198554Sjhb	if (flags & LINUX_MAP_GROWSDOWN)
45264921Smarcel		bsd_args.flags |= MAP_STACK;
45364921Smarcel
454166727Sjkim	/*
455166727Sjkim	 * PROT_READ, PROT_WRITE, or PROT_EXEC implies PROT_READ and PROT_EXEC
456166727Sjkim	 * on Linux/i386. We do this to ensure maximum compatibility.
457166727Sjkim	 * Linux/ia64 does the same in i386 emulation mode.
458166727Sjkim	 */
459198554Sjhb	bsd_args.prot = prot;
460166727Sjkim	if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC))
461166727Sjkim		bsd_args.prot |= PROT_READ | PROT_EXEC;
462166727Sjkim
463167048Sjkim	/* Linux does not check file descriptor when MAP_ANONYMOUS is set. */
464198554Sjhb	bsd_args.fd = (bsd_args.flags & MAP_ANON) ? -1 : fd;
465167048Sjkim	if (bsd_args.fd != -1) {
466166727Sjkim		/*
467166727Sjkim		 * Linux follows Solaris mmap(2) description:
468166727Sjkim		 * The file descriptor fildes is opened with
469166727Sjkim		 * read permission, regardless of the
470166727Sjkim		 * protection options specified.
471224778Srwatson		 *
472224778Srwatson		 * Checking just CAP_MMAP is fine here, since the real work
473224778Srwatson		 * is done in the FreeBSD mmap().
474166727Sjkim		 */
475166727Sjkim
476224778Srwatson		if ((error = fget(td, bsd_args.fd, CAP_MMAP, &fp)) != 0)
477166727Sjkim			return (error);
478166727Sjkim		if (fp->f_type != DTYPE_VNODE) {
479166727Sjkim			fdrop(fp, td);
480166727Sjkim			return (EINVAL);
481166727Sjkim		}
482166727Sjkim
483166727Sjkim		/* Linux mmap() just fails for O_WRONLY files */
484166727Sjkim		if (!(fp->f_flag & FREAD)) {
485166727Sjkim			fdrop(fp, td);
486166727Sjkim			return (EACCES);
487166727Sjkim		}
488166727Sjkim
489166727Sjkim		fdrop(fp, td);
490166727Sjkim	}
491166727Sjkim
492198554Sjhb	if (flags & LINUX_MAP_GROWSDOWN) {
493161365Snetchild		/*
494198554Sjhb		 * The Linux MAP_GROWSDOWN option does not limit auto
49564921Smarcel		 * growth of the region.  Linux mmap with this option
49664921Smarcel		 * takes as addr the inital BOS, and as len, the initial
49764921Smarcel		 * region size.  It can then grow down from addr without
49864921Smarcel		 * limit.  However, linux threads has an implicit internal
49964921Smarcel		 * limit to stack size of STACK_SIZE.  Its just not
50064921Smarcel		 * enforced explicitly in linux.  But, here we impose
50164921Smarcel		 * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
50264921Smarcel		 * region, since we can do this with our mmap.
50364921Smarcel		 *
50464921Smarcel		 * Our mmap with MAP_STACK takes addr as the maximum
50564921Smarcel		 * downsize limit on BOS, and as len the max size of
50664921Smarcel		 * the region.  It them maps the top SGROWSIZ bytes,
507166944Snetchild		 * and auto grows the region down, up to the limit
50864921Smarcel		 * in addr.
50964921Smarcel		 *
51064921Smarcel		 * If we don't use the MAP_STACK option, the effect
51164921Smarcel		 * of this code is to allocate a stack region of a
51264921Smarcel		 * fixed size of (STACK_SIZE - GUARD_SIZE).
51364921Smarcel		 */
51464921Smarcel
515198554Sjhb		if ((caddr_t)PTRIN(addr) + len > p->p_vmspace->vm_maxsaddr) {
516161365Snetchild			/*
517161365Snetchild			 * Some linux apps will attempt to mmap
51867238Sgallatin			 * thread stacks near the top of their
51967238Sgallatin			 * address space.  If their TOS is greater
52067238Sgallatin			 * than vm_maxsaddr, vm_map_growstack()
52167238Sgallatin			 * will confuse the thread stack with the
52267238Sgallatin			 * process stack and deliver a SEGV if they
52367238Sgallatin			 * attempt to grow the thread stack past their
52467238Sgallatin			 * current stacksize rlimit.  To avoid this,
52567238Sgallatin			 * adjust vm_maxsaddr upwards to reflect
52667238Sgallatin			 * the current stacksize rlimit rather
52767238Sgallatin			 * than the maximum possible stacksize.
52867238Sgallatin			 * It would be better to adjust the
52967238Sgallatin			 * mmap'ed region, but some apps do not check
53067238Sgallatin			 * mmap's return value.
53167238Sgallatin			 */
532125454Sjhb			PROC_LOCK(p);
53367238Sgallatin			p->p_vmspace->vm_maxsaddr = (char *)USRSTACK -
534125454Sjhb			    lim_cur(p, RLIMIT_STACK);
535125454Sjhb			PROC_UNLOCK(p);
53667238Sgallatin		}
53767238Sgallatin
538176193Sjkim		/*
539176193Sjkim		 * This gives us our maximum stack size and a new BOS.
540176193Sjkim		 * If we're using VM_STACK, then mmap will just map
541176193Sjkim		 * the top SGROWSIZ bytes, and let the stack grow down
542176193Sjkim		 * to the limit at BOS.  If we're not using VM_STACK
543176193Sjkim		 * we map the full stack, since we don't have a way
544176193Sjkim		 * to autogrow it.
545176193Sjkim		 */
546198554Sjhb		if (len > STACK_SIZE - GUARD_SIZE) {
547198554Sjhb			bsd_args.addr = (caddr_t)PTRIN(addr);
548198554Sjhb			bsd_args.len = len;
549176193Sjkim		} else {
550198554Sjhb			bsd_args.addr = (caddr_t)PTRIN(addr) -
551198554Sjhb			    (STACK_SIZE - GUARD_SIZE - len);
552176193Sjkim			bsd_args.len = STACK_SIZE - GUARD_SIZE;
553176193Sjkim		}
55464921Smarcel	} else {
555198554Sjhb		bsd_args.addr = (caddr_t)PTRIN(addr);
556198554Sjhb		bsd_args.len  = len;
55764921Smarcel	}
558198554Sjhb	bsd_args.pos = pos;
55964921Smarcel
56064921Smarcel#ifdef DEBUG
56172543Sjlemon	if (ldebug(mmap))
562112630Smdodd		printf("-> %s(%p, %d, %d, 0x%08x, %d, 0x%x)\n",
563112630Smdodd		    __func__,
56472543Sjlemon		    (void *)bsd_args.addr, bsd_args.len, bsd_args.prot,
56572543Sjlemon		    bsd_args.flags, bsd_args.fd, (int)bsd_args.pos);
56664921Smarcel#endif
567225617Skmacy	error = sys_mmap(td, &bsd_args);
568112630Smdodd#ifdef DEBUG
569112630Smdodd	if (ldebug(mmap))
570112630Smdodd		printf("-> %s() return: 0x%x (0x%08x)\n",
571112630Smdodd			__func__, error, (u_int)td->td_retval[0]);
572112630Smdodd#endif
573112630Smdodd	return (error);
57464921Smarcel}
57564921Smarcel
57664921Smarcelint
577166727Sjkimlinux_mprotect(struct thread *td, struct linux_mprotect_args *uap)
578166727Sjkim{
579166727Sjkim	struct mprotect_args bsd_args;
580166727Sjkim
581166727Sjkim	bsd_args.addr = uap->addr;
582166727Sjkim	bsd_args.len = uap->len;
583166727Sjkim	bsd_args.prot = uap->prot;
584166727Sjkim	if (bsd_args.prot & (PROT_READ | PROT_WRITE | PROT_EXEC))
585166727Sjkim		bsd_args.prot |= PROT_READ | PROT_EXEC;
586225617Skmacy	return (sys_mprotect(td, &bsd_args));
587166727Sjkim}
588166727Sjkim
589166727Sjkimint
59083366Sjulianlinux_ioperm(struct thread *td, struct linux_ioperm_args *args)
59164921Smarcel{
592140862Ssobomax	int error;
593140862Ssobomax	struct i386_ioperm_args iia;
59464921Smarcel
595140862Ssobomax	iia.start = args->start;
596140862Ssobomax	iia.length = args->length;
597140862Ssobomax	iia.enable = args->enable;
598140862Ssobomax	error = i386_set_ioperm(td, &iia);
599140862Ssobomax	return (error);
60064921Smarcel}
60164921Smarcel
60264921Smarcelint
60383366Sjulianlinux_iopl(struct thread *td, struct linux_iopl_args *args)
60464921Smarcel{
60564921Smarcel	int error;
60664921Smarcel
60764921Smarcel	if (args->level < 0 || args->level > 3)
60864921Smarcel		return (EINVAL);
609164033Srwatson	if ((error = priv_check(td, PRIV_IO)) != 0)
61064921Smarcel		return (error);
61191406Sjhb	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
61283981Srwatson		return (error);
61383366Sjulian	td->td_frame->tf_eflags = (td->td_frame->tf_eflags & ~PSL_IOPL) |
61464921Smarcel	    (args->level * (PSL_IOPL / 3));
61564921Smarcel	return (0);
61664921Smarcel}
61764921Smarcel
61864921Smarcelint
619105441Smarkmlinux_modify_ldt(struct thread *td, struct linux_modify_ldt_args *uap)
62064921Smarcel{
62164921Smarcel	int error;
622140862Ssobomax	struct i386_ldt_args ldt;
62383221Smarcel	struct l_descriptor ld;
624140862Ssobomax	union descriptor desc;
625173937Skib	int size, written;
62664921Smarcel
62764921Smarcel	switch (uap->func) {
62864921Smarcel	case 0x00: /* read_ldt */
629140862Ssobomax		ldt.start = 0;
630140862Ssobomax		ldt.descs = uap->ptr;
631140862Ssobomax		ldt.num = uap->bytecount / sizeof(union descriptor);
632140862Ssobomax		error = i386_get_ldt(td, &ldt);
63383366Sjulian		td->td_retval[0] *= sizeof(union descriptor);
63464921Smarcel		break;
635173937Skib	case 0x02: /* read_default_ldt = 0 */
636173937Skib		size = 5*sizeof(struct l_desc_struct);
637173937Skib		if (size > uap->bytecount)
638173937Skib			size = uap->bytecount;
639173937Skib		for (written = error = 0; written < size && error == 0; written++)
640173937Skib			error = subyte((char *)uap->ptr + written, 0);
641173937Skib		td->td_retval[0] = written;
642173937Skib		break;
64364921Smarcel	case 0x01: /* write_ldt */
64464921Smarcel	case 0x11: /* write_ldt */
64564921Smarcel		if (uap->bytecount != sizeof(ld))
64664921Smarcel			return (EINVAL);
64764921Smarcel
64864921Smarcel		error = copyin(uap->ptr, &ld, sizeof(ld));
64964921Smarcel		if (error)
65064921Smarcel			return (error);
65164921Smarcel
652140862Ssobomax		ldt.start = ld.entry_number;
653140862Ssobomax		ldt.descs = &desc;
654140862Ssobomax		ldt.num = 1;
655140862Ssobomax		desc.sd.sd_lolimit = (ld.limit & 0x0000ffff);
656140862Ssobomax		desc.sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16;
657140862Ssobomax		desc.sd.sd_lobase = (ld.base_addr & 0x00ffffff);
658140862Ssobomax		desc.sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24;
659140862Ssobomax		desc.sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) |
66064921Smarcel			(ld.contents << 2);
661140862Ssobomax		desc.sd.sd_dpl = 3;
662140862Ssobomax		desc.sd.sd_p = (ld.seg_not_present ^ 1);
663140862Ssobomax		desc.sd.sd_xx = 0;
664140862Ssobomax		desc.sd.sd_def32 = ld.seg_32bit;
665140862Ssobomax		desc.sd.sd_gran = ld.limit_in_pages;
666140862Ssobomax		error = i386_set_ldt(td, &ldt, &desc);
66764921Smarcel		break;
66864921Smarcel	default:
669195074Sjhb		error = ENOSYS;
67064921Smarcel		break;
67164921Smarcel	}
67264921Smarcel
67364921Smarcel	if (error == EOPNOTSUPP) {
67464921Smarcel		printf("linux: modify_ldt needs kernel option USER_LDT\n");
67564921Smarcel		error = ENOSYS;
67664921Smarcel	}
67764921Smarcel
67864921Smarcel	return (error);
67964921Smarcel}
68064921Smarcel
68164921Smarcelint
68283366Sjulianlinux_sigaction(struct thread *td, struct linux_sigaction_args *args)
68364921Smarcel{
68483221Smarcel	l_osigaction_t osa;
68583221Smarcel	l_sigaction_t act, oact;
68664921Smarcel	int error;
68764921Smarcel
68864921Smarcel#ifdef DEBUG
68972543Sjlemon	if (ldebug(sigaction))
69072543Sjlemon		printf(ARGS(sigaction, "%d, %p, %p"),
69172543Sjlemon		    args->sig, (void *)args->nsa, (void *)args->osa);
69264921Smarcel#endif
69364921Smarcel
69464921Smarcel	if (args->nsa != NULL) {
695111797Sdes		error = copyin(args->nsa, &osa, sizeof(l_osigaction_t));
69664921Smarcel		if (error)
69764921Smarcel			return (error);
69864921Smarcel		act.lsa_handler = osa.lsa_handler;
69964921Smarcel		act.lsa_flags = osa.lsa_flags;
70064921Smarcel		act.lsa_restorer = osa.lsa_restorer;
70164921Smarcel		LINUX_SIGEMPTYSET(act.lsa_mask);
70264921Smarcel		act.lsa_mask.__bits[0] = osa.lsa_mask;
70364921Smarcel	}
70464921Smarcel
70583366Sjulian	error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL,
70664921Smarcel	    args->osa ? &oact : NULL);
70764921Smarcel
70864921Smarcel	if (args->osa != NULL && !error) {
70964921Smarcel		osa.lsa_handler = oact.lsa_handler;
71064921Smarcel		osa.lsa_flags = oact.lsa_flags;
71164921Smarcel		osa.lsa_restorer = oact.lsa_restorer;
71264921Smarcel		osa.lsa_mask = oact.lsa_mask.__bits[0];
713111797Sdes		error = copyout(&osa, args->osa, sizeof(l_osigaction_t));
71464921Smarcel	}
71564921Smarcel
71664921Smarcel	return (error);
71764921Smarcel}
71864921Smarcel
71964921Smarcel/*
72064921Smarcel * Linux has two extra args, restart and oldmask.  We dont use these,
72164921Smarcel * but it seems that "restart" is actually a context pointer that
72264921Smarcel * enables the signal to happen with a different register set.
72364921Smarcel */
72464921Smarcelint
72583366Sjulianlinux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args)
72664921Smarcel{
727102814Siedowse	sigset_t sigmask;
72883221Smarcel	l_sigset_t mask;
72964921Smarcel
73064921Smarcel#ifdef DEBUG
73172543Sjlemon	if (ldebug(sigsuspend))
73272543Sjlemon		printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
73364921Smarcel#endif
73464921Smarcel
73564921Smarcel	LINUX_SIGEMPTYSET(mask);
73664921Smarcel	mask.__bits[0] = args->mask;
737102814Siedowse	linux_to_bsd_sigset(&mask, &sigmask);
738102814Siedowse	return (kern_sigsuspend(td, sigmask));
73964921Smarcel}
74064921Smarcel
74164921Smarcelint
742105441Smarkmlinux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap)
74364921Smarcel{
74483221Smarcel	l_sigset_t lmask;
745102814Siedowse	sigset_t sigmask;
74664921Smarcel	int error;
74764921Smarcel
74864921Smarcel#ifdef DEBUG
74972543Sjlemon	if (ldebug(rt_sigsuspend))
75072543Sjlemon		printf(ARGS(rt_sigsuspend, "%p, %d"),
75172543Sjlemon		    (void *)uap->newset, uap->sigsetsize);
75264921Smarcel#endif
75364921Smarcel
75483221Smarcel	if (uap->sigsetsize != sizeof(l_sigset_t))
75564921Smarcel		return (EINVAL);
75664921Smarcel
75783221Smarcel	error = copyin(uap->newset, &lmask, sizeof(l_sigset_t));
75864921Smarcel	if (error)
75964921Smarcel		return (error);
76064921Smarcel
761102814Siedowse	linux_to_bsd_sigset(&lmask, &sigmask);
762102814Siedowse	return (kern_sigsuspend(td, sigmask));
76364921Smarcel}
76464921Smarcel
76564921Smarcelint
76683366Sjulianlinux_pause(struct thread *td, struct linux_pause_args *args)
76764921Smarcel{
76883366Sjulian	struct proc *p = td->td_proc;
769102814Siedowse	sigset_t sigmask;
77064921Smarcel
77164921Smarcel#ifdef DEBUG
77272543Sjlemon	if (ldebug(pause))
77372543Sjlemon		printf(ARGS(pause, ""));
77464921Smarcel#endif
77564921Smarcel
77671494Sjhb	PROC_LOCK(p);
777112888Sjeff	sigmask = td->td_sigmask;
77871494Sjhb	PROC_UNLOCK(p);
779102814Siedowse	return (kern_sigsuspend(td, sigmask));
78064921Smarcel}
78164921Smarcel
78264921Smarcelint
78383366Sjulianlinux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
78464921Smarcel{
785102814Siedowse	stack_t ss, oss;
78683221Smarcel	l_stack_t lss;
78764921Smarcel	int error;
78864921Smarcel
78964921Smarcel#ifdef DEBUG
79072543Sjlemon	if (ldebug(sigaltstack))
79172543Sjlemon		printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
79264921Smarcel#endif
79364921Smarcel
794102814Siedowse	if (uap->uss != NULL) {
79583221Smarcel		error = copyin(uap->uss, &lss, sizeof(l_stack_t));
79667051Sgallatin		if (error)
79767051Sgallatin			return (error);
79864921Smarcel
799102814Siedowse		ss.ss_sp = lss.ss_sp;
800102814Siedowse		ss.ss_size = lss.ss_size;
801102814Siedowse		ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags);
80267051Sgallatin	}
803134269Sjhb	error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL,
804134269Sjhb	    (uap->uoss != NULL) ? &oss : NULL);
805102814Siedowse	if (!error && uap->uoss != NULL) {
806102814Siedowse		lss.ss_sp = oss.ss_sp;
807102814Siedowse		lss.ss_size = oss.ss_size;
808102814Siedowse		lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags);
80983221Smarcel		error = copyout(&lss, uap->uoss, sizeof(l_stack_t));
81064921Smarcel	}
81164921Smarcel
81264921Smarcel	return (error);
81364921Smarcel}
814104893Ssobomax
815104893Ssobomaxint
816104893Ssobomaxlinux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
817104893Ssobomax{
818104893Ssobomax	struct ftruncate_args sa;
819104893Ssobomax
820104893Ssobomax#ifdef DEBUG
821104893Ssobomax	if (ldebug(ftruncate64))
822104984Sbde		printf(ARGS(ftruncate64, "%u, %jd"), args->fd,
823104984Sbde		    (intmax_t)args->length);
824104893Ssobomax#endif
825104893Ssobomax
826104893Ssobomax	sa.fd = args->fd;
827104893Ssobomax	sa.length = args->length;
828225617Skmacy	return sys_ftruncate(td, &sa);
829104893Ssobomax}
830134838Sdfr
831134838Sdfrint
832134838Sdfrlinux_set_thread_area(struct thread *td, struct linux_set_thread_area_args *args)
833134838Sdfr{
834161310Snetchild	struct l_user_desc info;
835161310Snetchild	int error;
836161310Snetchild	int idx;
837161310Snetchild	int a[2];
838161310Snetchild	struct segment_descriptor sd;
839161310Snetchild
840161310Snetchild	error = copyin(args->desc, &info, sizeof(struct l_user_desc));
841161310Snetchild	if (error)
842161310Snetchild		return (error);
843161310Snetchild
844161310Snetchild#ifdef DEBUG
845161310Snetchild	if (ldebug(set_thread_area))
846161310Snetchild	   	printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, %i, %i, %i\n"),
847161310Snetchild		      info.entry_number,
848161310Snetchild      		      info.base_addr,
849161310Snetchild      		      info.limit,
850161310Snetchild      		      info.seg_32bit,
851161310Snetchild		      info.contents,
852161310Snetchild      		      info.read_exec_only,
853161310Snetchild      		      info.limit_in_pages,
854161310Snetchild      		      info.seg_not_present,
855161310Snetchild      		      info.useable);
856161310Snetchild#endif
857161310Snetchild
858161310Snetchild	idx = info.entry_number;
859161365Snetchild	/*
860166944Snetchild	 * Semantics of linux version: every thread in the system has array of
861166944Snetchild	 * 3 tls descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown. This
862166944Snetchild	 * syscall loads one of the selected tls decriptors with a value and
863166944Snetchild	 * also loads GDT descriptors 6, 7 and 8 with the content of the
864166944Snetchild	 * per-thread descriptors.
865161310Snetchild	 *
866166944Snetchild	 * Semantics of fbsd version: I think we can ignore that linux has 3
867166944Snetchild	 * per-thread descriptors and use just the 1st one. The tls_array[]
868166944Snetchild	 * is used only in set/get-thread_area() syscalls and for loading the
869166944Snetchild	 * GDT descriptors. In fbsd we use just one GDT descriptor for TLS so
870166944Snetchild	 * we will load just one.
871166944Snetchild	 *
872166944Snetchild	 * XXX: this doesn't work when a user space process tries to use more
873166944Snetchild	 * than 1 TLS segment. Comment in the linux sources says wine might do
874166944Snetchild	 * this.
875134838Sdfr	 */
876161310Snetchild
877161365Snetchild	/*
878161365Snetchild	 * we support just GLIBC TLS now
879161310Snetchild	 * we should let 3 proceed as well because we use this segment so
880161310Snetchild	 * if code does two subsequent calls it should succeed
881161310Snetchild	 */
882161310Snetchild	if (idx != 6 && idx != -1 && idx != 3)
883161310Snetchild		return (EINVAL);
884161310Snetchild
885161365Snetchild	/*
886161365Snetchild	 * we have to copy out the GDT entry we use
887166944Snetchild	 * FreeBSD uses GDT entry #3 for storing %gs so load that
888166944Snetchild	 *
889166944Snetchild	 * XXX: what if a user space program doesn't check this value and tries
890161310Snetchild	 * to use 6, 7 or 8?
891161310Snetchild	 */
892161310Snetchild	idx = info.entry_number = 3;
893161310Snetchild	error = copyout(&info, args->desc, sizeof(struct l_user_desc));
894161310Snetchild	if (error)
895161310Snetchild		return (error);
896161310Snetchild
897167157Sjkim	if (LINUX_LDT_empty(&info)) {
898161310Snetchild		a[0] = 0;
899161310Snetchild		a[1] = 0;
900161310Snetchild	} else {
901167157Sjkim		a[0] = LINUX_LDT_entry_a(&info);
902167157Sjkim		a[1] = LINUX_LDT_entry_b(&info);
903161310Snetchild	}
904161310Snetchild
905161310Snetchild	memcpy(&sd, &a, sizeof(a));
906161310Snetchild#ifdef DEBUG
907161310Snetchild	if (ldebug(set_thread_area))
908161310Snetchild	   	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,
909161310Snetchild			sd.sd_hibase,
910161310Snetchild			sd.sd_lolimit,
911161310Snetchild			sd.sd_hilimit,
912161310Snetchild			sd.sd_type,
913161310Snetchild			sd.sd_dpl,
914161310Snetchild			sd.sd_p,
915161310Snetchild			sd.sd_xx,
916161310Snetchild			sd.sd_def32,
917161310Snetchild			sd.sd_gran);
918161310Snetchild#endif
919161310Snetchild
920161310Snetchild	/* this is taken from i386 version of cpu_set_user_tls() */
921161310Snetchild	critical_enter();
922161310Snetchild	/* set %gs */
923161310Snetchild	td->td_pcb->pcb_gsd = sd;
924161310Snetchild	PCPU_GET(fsgs_gdt)[1] = sd;
925161310Snetchild	load_gs(GSEL(GUGS_SEL, SEL_UPL));
926161310Snetchild	critical_exit();
927161310Snetchild
928161310Snetchild	return (0);
929134838Sdfr}
930134838Sdfr
931134838Sdfrint
932161310Snetchildlinux_get_thread_area(struct thread *td, struct linux_get_thread_area_args *args)
933134838Sdfr{
934161310Snetchild
935161310Snetchild	struct l_user_desc info;
936161310Snetchild	int error;
937161310Snetchild	int idx;
938161310Snetchild	struct l_desc_struct desc;
939161310Snetchild	struct segment_descriptor sd;
940134838Sdfr
941161310Snetchild#ifdef DEBUG
942161310Snetchild	if (ldebug(get_thread_area))
943161310Snetchild		printf(ARGS(get_thread_area, "%p"), args->desc);
944161310Snetchild#endif
945161310Snetchild
946161310Snetchild	error = copyin(args->desc, &info, sizeof(struct l_user_desc));
947161310Snetchild	if (error)
948161310Snetchild		return (error);
949161310Snetchild
950161310Snetchild	idx = info.entry_number;
951161310Snetchild	/* XXX: I am not sure if we want 3 to be allowed too. */
952161310Snetchild	if (idx != 6 && idx != 3)
953161310Snetchild		return (EINVAL);
954161310Snetchild
955161310Snetchild	idx = 3;
956161310Snetchild
957161310Snetchild	memset(&info, 0, sizeof(info));
958161310Snetchild
959161310Snetchild	sd = PCPU_GET(fsgs_gdt)[1];
960161310Snetchild
961161310Snetchild	memcpy(&desc, &sd, sizeof(desc));
962161310Snetchild
963161310Snetchild	info.entry_number = idx;
964167157Sjkim	info.base_addr = LINUX_GET_BASE(&desc);
965167157Sjkim	info.limit = LINUX_GET_LIMIT(&desc);
966167157Sjkim	info.seg_32bit = LINUX_GET_32BIT(&desc);
967167157Sjkim	info.contents = LINUX_GET_CONTENTS(&desc);
968167157Sjkim	info.read_exec_only = !LINUX_GET_WRITABLE(&desc);
969167157Sjkim	info.limit_in_pages = LINUX_GET_LIMIT_PAGES(&desc);
970167157Sjkim	info.seg_not_present = !LINUX_GET_PRESENT(&desc);
971167157Sjkim	info.useable = LINUX_GET_USEABLE(&desc);
972161310Snetchild
973161310Snetchild	error = copyout(&info, args->desc, sizeof(struct l_user_desc));
974161310Snetchild	if (error)
975161310Snetchild	   	return (EFAULT);
976161310Snetchild
977134838Sdfr	return (0);
978134838Sdfr}
979134838Sdfr
980161310Snetchild/* copied from kern/kern_time.c */
981134838Sdfrint
982161310Snetchildlinux_timer_create(struct thread *td, struct linux_timer_create_args *args)
983134838Sdfr{
984225617Skmacy   	return sys_ktimer_create(td, (struct ktimer_create_args *) args);
985161310Snetchild}
986134838Sdfr
987161310Snetchildint
988161310Snetchildlinux_timer_settime(struct thread *td, struct linux_timer_settime_args *args)
989161310Snetchild{
990225617Skmacy   	return sys_ktimer_settime(td, (struct ktimer_settime_args *) args);
991134838Sdfr}
992134838Sdfr
993161310Snetchildint
994161310Snetchildlinux_timer_gettime(struct thread *td, struct linux_timer_gettime_args *args)
995161310Snetchild{
996225617Skmacy   	return sys_ktimer_gettime(td, (struct ktimer_gettime_args *) args);
997161310Snetchild}
998161310Snetchild
999161310Snetchildint
1000161310Snetchildlinux_timer_getoverrun(struct thread *td, struct linux_timer_getoverrun_args *args)
1001161310Snetchild{
1002225617Skmacy   	return sys_ktimer_getoverrun(td, (struct ktimer_getoverrun_args *) args);
1003161310Snetchild}
1004161310Snetchild
1005161310Snetchildint
1006161310Snetchildlinux_timer_delete(struct thread *td, struct linux_timer_delete_args *args)
1007161310Snetchild{
1008225617Skmacy   	return sys_ktimer_delete(td, (struct ktimer_delete_args *) args);
1009161310Snetchild}
1010161310Snetchild
1011161310Snetchild/* XXX: this wont work with module - convert it */
1012161310Snetchildint
1013161310Snetchildlinux_mq_open(struct thread *td, struct linux_mq_open_args *args)
1014161310Snetchild{
1015161310Snetchild#ifdef P1003_1B_MQUEUE
1016225617Skmacy   	return sys_kmq_open(td, (struct kmq_open_args *) args);
1017161310Snetchild#else
1018161310Snetchild	return (ENOSYS);
1019161310Snetchild#endif
1020161310Snetchild}
1021161310Snetchild
1022161310Snetchildint
1023161310Snetchildlinux_mq_unlink(struct thread *td, struct linux_mq_unlink_args *args)
1024161310Snetchild{
1025161310Snetchild#ifdef P1003_1B_MQUEUE
1026225617Skmacy   	return sys_kmq_unlink(td, (struct kmq_unlink_args *) args);
1027161310Snetchild#else
1028161310Snetchild	return (ENOSYS);
1029161310Snetchild#endif
1030161310Snetchild}
1031161310Snetchild
1032161310Snetchildint
1033161310Snetchildlinux_mq_timedsend(struct thread *td, struct linux_mq_timedsend_args *args)
1034161310Snetchild{
1035161310Snetchild#ifdef P1003_1B_MQUEUE
1036225617Skmacy   	return sys_kmq_timedsend(td, (struct kmq_timedsend_args *) args);
1037161310Snetchild#else
1038161310Snetchild	return (ENOSYS);
1039161310Snetchild#endif
1040161310Snetchild}
1041161310Snetchild
1042161310Snetchildint
1043161310Snetchildlinux_mq_timedreceive(struct thread *td, struct linux_mq_timedreceive_args *args)
1044161310Snetchild{
1045161310Snetchild#ifdef P1003_1B_MQUEUE
1046225617Skmacy   	return sys_kmq_timedreceive(td, (struct kmq_timedreceive_args *) args);
1047161310Snetchild#else
1048161310Snetchild	return (ENOSYS);
1049161310Snetchild#endif
1050161310Snetchild}
1051161310Snetchild
1052161310Snetchildint
1053161310Snetchildlinux_mq_notify(struct thread *td, struct linux_mq_notify_args *args)
1054161310Snetchild{
1055161310Snetchild#ifdef P1003_1B_MQUEUE
1056225617Skmacy	return sys_kmq_notify(td, (struct kmq_notify_args *) args);
1057161310Snetchild#else
1058161310Snetchild	return (ENOSYS);
1059161310Snetchild#endif
1060161310Snetchild}
1061161310Snetchild
1062161310Snetchildint
1063161310Snetchildlinux_mq_getsetattr(struct thread *td, struct linux_mq_getsetattr_args *args)
1064161310Snetchild{
1065161310Snetchild#ifdef P1003_1B_MQUEUE
1066225617Skmacy   	return sys_kmq_setattr(td, (struct kmq_setattr_args *) args);
1067161310Snetchild#else
1068161310Snetchild	return (ENOSYS);
1069161310Snetchild#endif
1070161310Snetchild}
1071161310Snetchild
1072218030Sdchaginint
1073218030Sdchaginlinux_wait4(struct thread *td, struct linux_wait4_args *args)
1074218030Sdchagin{
1075218030Sdchagin	int error, options;
1076218030Sdchagin	struct rusage ru, *rup;
1077218030Sdchagin
1078218030Sdchagin#ifdef DEBUG
1079218030Sdchagin	if (ldebug(wait4))
1080218030Sdchagin		printf(ARGS(wait4, "%d, %p, %d, %p"),
1081218030Sdchagin		    args->pid, (void *)args->status, args->options,
1082218030Sdchagin		    (void *)args->rusage);
1083218030Sdchagin#endif
1084218030Sdchagin
1085218030Sdchagin	options = (args->options & (WNOHANG | WUNTRACED));
1086218030Sdchagin	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
1087218030Sdchagin	if (args->options & __WCLONE)
1088218030Sdchagin		options |= WLINUXCLONE;
1089218030Sdchagin
1090218030Sdchagin	if (args->rusage != NULL)
1091218030Sdchagin		rup = &ru;
1092218030Sdchagin	else
1093218030Sdchagin		rup = NULL;
1094218030Sdchagin	error = linux_common_wait(td, args->pid, args->status, options, rup);
1095218030Sdchagin	if (error)
1096218030Sdchagin		return (error);
1097218030Sdchagin	if (args->rusage != NULL)
1098218030Sdchagin		error = copyout(&ru, args->rusage, sizeof(ru));
1099218030Sdchagin
1100218030Sdchagin	return (error);
1101218030Sdchagin}
1102