linux32_machdep.c revision 302964
1/*-
2 * Copyright (c) 2004 Tim J. Robbins
3 * Copyright (c) 2002 Doug Rabson
4 * Copyright (c) 2000 Marcel Moolenaar
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer
12 *    in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/10/sys/amd64/linux32/linux32_machdep.c 302964 2016-07-17 15:23:32Z dchagin $");
33
34#include "opt_compat.h"
35
36#include <sys/param.h>
37#include <sys/kernel.h>
38#include <sys/systm.h>
39#include <sys/capsicum.h>
40#include <sys/file.h>
41#include <sys/fcntl.h>
42#include <sys/clock.h>
43#include <sys/imgact.h>
44#include <sys/limits.h>
45#include <sys/lock.h>
46#include <sys/malloc.h>
47#include <sys/mman.h>
48#include <sys/mutex.h>
49#include <sys/priv.h>
50#include <sys/proc.h>
51#include <sys/resource.h>
52#include <sys/resourcevar.h>
53#include <sys/syscallsubr.h>
54#include <sys/sysproto.h>
55#include <sys/unistd.h>
56#include <sys/wait.h>
57
58#include <machine/frame.h>
59#include <machine/pcb.h>
60#include <machine/psl.h>
61#include <machine/segments.h>
62#include <machine/specialreg.h>
63
64#include <vm/vm.h>
65#include <vm/pmap.h>
66#include <vm/vm_map.h>
67
68#include <compat/freebsd32/freebsd32_util.h>
69#include <amd64/linux32/linux.h>
70#include <amd64/linux32/linux32_proto.h>
71#include <compat/linux/linux_ipc.h>
72#include <compat/linux/linux_misc.h>
73#include <compat/linux/linux_mmap.h>
74#include <compat/linux/linux_signal.h>
75#include <compat/linux/linux_util.h>
76#include <compat/linux/linux_emul.h>
77
78static void	bsd_to_linux_rusage(struct rusage *ru, struct l_rusage *lru);
79
80struct l_old_select_argv {
81	l_int		nfds;
82	l_uintptr_t	readfds;
83	l_uintptr_t	writefds;
84	l_uintptr_t	exceptfds;
85	l_uintptr_t	timeout;
86} __packed;
87
88
89static void
90bsd_to_linux_rusage(struct rusage *ru, struct l_rusage *lru)
91{
92
93	lru->ru_utime.tv_sec = ru->ru_utime.tv_sec;
94	lru->ru_utime.tv_usec = ru->ru_utime.tv_usec;
95	lru->ru_stime.tv_sec = ru->ru_stime.tv_sec;
96	lru->ru_stime.tv_usec = ru->ru_stime.tv_usec;
97	lru->ru_maxrss = ru->ru_maxrss;
98	lru->ru_ixrss = ru->ru_ixrss;
99	lru->ru_idrss = ru->ru_idrss;
100	lru->ru_isrss = ru->ru_isrss;
101	lru->ru_minflt = ru->ru_minflt;
102	lru->ru_majflt = ru->ru_majflt;
103	lru->ru_nswap = ru->ru_nswap;
104	lru->ru_inblock = ru->ru_inblock;
105	lru->ru_oublock = ru->ru_oublock;
106	lru->ru_msgsnd = ru->ru_msgsnd;
107	lru->ru_msgrcv = ru->ru_msgrcv;
108	lru->ru_nsignals = ru->ru_nsignals;
109	lru->ru_nvcsw = ru->ru_nvcsw;
110	lru->ru_nivcsw = ru->ru_nivcsw;
111}
112
113int
114linux_copyout_rusage(struct rusage *ru, void *uaddr)
115{
116	struct l_rusage lru;
117
118	bsd_to_linux_rusage(ru, &lru);
119
120	return (copyout(&lru, uaddr, sizeof(struct l_rusage)));
121}
122
123int
124linux_execve(struct thread *td, struct linux_execve_args *args)
125{
126	struct image_args eargs;
127	char *path;
128	int error;
129
130	LCONVPATHEXIST(td, args->path, &path);
131
132#ifdef DEBUG
133	if (ldebug(execve))
134		printf(ARGS(execve, "%s"), path);
135#endif
136
137	error = freebsd32_exec_copyin_args(&eargs, path, UIO_SYSSPACE,
138	    args->argp, args->envp);
139	free(path, M_TEMP);
140	if (error == 0)
141		error = linux_common_execve(td, &eargs);
142	return (error);
143}
144
145CTASSERT(sizeof(struct l_iovec32) == 8);
146
147static int
148linux32_copyinuio(struct l_iovec32 *iovp, l_ulong iovcnt, struct uio **uiop)
149{
150	struct l_iovec32 iov32;
151	struct iovec *iov;
152	struct uio *uio;
153	uint32_t iovlen;
154	int error, i;
155
156	*uiop = NULL;
157	if (iovcnt > UIO_MAXIOV)
158		return (EINVAL);
159	iovlen = iovcnt * sizeof(struct iovec);
160	uio = malloc(iovlen + sizeof(*uio), M_IOV, M_WAITOK);
161	iov = (struct iovec *)(uio + 1);
162	for (i = 0; i < iovcnt; i++) {
163		error = copyin(&iovp[i], &iov32, sizeof(struct l_iovec32));
164		if (error) {
165			free(uio, M_IOV);
166			return (error);
167		}
168		iov[i].iov_base = PTRIN(iov32.iov_base);
169		iov[i].iov_len = iov32.iov_len;
170	}
171	uio->uio_iov = iov;
172	uio->uio_iovcnt = iovcnt;
173	uio->uio_segflg = UIO_USERSPACE;
174	uio->uio_offset = -1;
175	uio->uio_resid = 0;
176	for (i = 0; i < iovcnt; i++) {
177		if (iov->iov_len > INT_MAX - uio->uio_resid) {
178			free(uio, M_IOV);
179			return (EINVAL);
180		}
181		uio->uio_resid += iov->iov_len;
182		iov++;
183	}
184	*uiop = uio;
185	return (0);
186}
187
188int
189linux32_copyiniov(struct l_iovec32 *iovp32, l_ulong iovcnt, struct iovec **iovp,
190    int error)
191{
192	struct l_iovec32 iov32;
193	struct iovec *iov;
194	uint32_t iovlen;
195	int i;
196
197	*iovp = NULL;
198	if (iovcnt > UIO_MAXIOV)
199		return (error);
200	iovlen = iovcnt * sizeof(struct iovec);
201	iov = malloc(iovlen, M_IOV, M_WAITOK);
202	for (i = 0; i < iovcnt; i++) {
203		error = copyin(&iovp32[i], &iov32, sizeof(struct l_iovec32));
204		if (error) {
205			free(iov, M_IOV);
206			return (error);
207		}
208		iov[i].iov_base = PTRIN(iov32.iov_base);
209		iov[i].iov_len = iov32.iov_len;
210	}
211	*iovp = iov;
212	return(0);
213
214}
215
216int
217linux_readv(struct thread *td, struct linux_readv_args *uap)
218{
219	struct uio *auio;
220	int error;
221
222	error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio);
223	if (error)
224		return (error);
225	error = kern_readv(td, uap->fd, auio);
226	free(auio, M_IOV);
227	return (error);
228}
229
230int
231linux_writev(struct thread *td, struct linux_writev_args *uap)
232{
233	struct uio *auio;
234	int error;
235
236	error = linux32_copyinuio(uap->iovp, uap->iovcnt, &auio);
237	if (error)
238		return (error);
239	error = kern_writev(td, uap->fd, auio);
240	free(auio, M_IOV);
241	return (error);
242}
243
244struct l_ipc_kludge {
245	l_uintptr_t msgp;
246	l_long msgtyp;
247} __packed;
248
249int
250linux_ipc(struct thread *td, struct linux_ipc_args *args)
251{
252
253	switch (args->what & 0xFFFF) {
254	case LINUX_SEMOP: {
255		struct linux_semop_args a;
256
257		a.semid = args->arg1;
258		a.tsops = args->ptr;
259		a.nsops = args->arg2;
260		return (linux_semop(td, &a));
261	}
262	case LINUX_SEMGET: {
263		struct linux_semget_args a;
264
265		a.key = args->arg1;
266		a.nsems = args->arg2;
267		a.semflg = args->arg3;
268		return (linux_semget(td, &a));
269	}
270	case LINUX_SEMCTL: {
271		struct linux_semctl_args a;
272		int error;
273
274		a.semid = args->arg1;
275		a.semnum = args->arg2;
276		a.cmd = args->arg3;
277		error = copyin(args->ptr, &a.arg, sizeof(a.arg));
278		if (error)
279			return (error);
280		return (linux_semctl(td, &a));
281	}
282	case LINUX_MSGSND: {
283		struct linux_msgsnd_args a;
284
285		a.msqid = args->arg1;
286		a.msgp = args->ptr;
287		a.msgsz = args->arg2;
288		a.msgflg = args->arg3;
289		return (linux_msgsnd(td, &a));
290	}
291	case LINUX_MSGRCV: {
292		struct linux_msgrcv_args a;
293
294		a.msqid = args->arg1;
295		a.msgsz = args->arg2;
296		a.msgflg = args->arg3;
297		if ((args->what >> 16) == 0) {
298			struct l_ipc_kludge tmp;
299			int error;
300
301			if (args->ptr == 0)
302				return (EINVAL);
303			error = copyin(args->ptr, &tmp, sizeof(tmp));
304			if (error)
305				return (error);
306			a.msgp = PTRIN(tmp.msgp);
307			a.msgtyp = tmp.msgtyp;
308		} else {
309			a.msgp = args->ptr;
310			a.msgtyp = args->arg5;
311		}
312		return (linux_msgrcv(td, &a));
313	}
314	case LINUX_MSGGET: {
315		struct linux_msgget_args a;
316
317		a.key = args->arg1;
318		a.msgflg = args->arg2;
319		return (linux_msgget(td, &a));
320	}
321	case LINUX_MSGCTL: {
322		struct linux_msgctl_args a;
323
324		a.msqid = args->arg1;
325		a.cmd = args->arg2;
326		a.buf = args->ptr;
327		return (linux_msgctl(td, &a));
328	}
329	case LINUX_SHMAT: {
330		struct linux_shmat_args a;
331
332		a.shmid = args->arg1;
333		a.shmaddr = args->ptr;
334		a.shmflg = args->arg2;
335		a.raddr = PTRIN((l_uint)args->arg3);
336		return (linux_shmat(td, &a));
337	}
338	case LINUX_SHMDT: {
339		struct linux_shmdt_args a;
340
341		a.shmaddr = args->ptr;
342		return (linux_shmdt(td, &a));
343	}
344	case LINUX_SHMGET: {
345		struct linux_shmget_args a;
346
347		a.key = args->arg1;
348		a.size = args->arg2;
349		a.shmflg = args->arg3;
350		return (linux_shmget(td, &a));
351	}
352	case LINUX_SHMCTL: {
353		struct linux_shmctl_args a;
354
355		a.shmid = args->arg1;
356		a.cmd = args->arg2;
357		a.buf = args->ptr;
358		return (linux_shmctl(td, &a));
359	}
360	default:
361		break;
362	}
363
364	return (EINVAL);
365}
366
367int
368linux_old_select(struct thread *td, struct linux_old_select_args *args)
369{
370	struct l_old_select_argv linux_args;
371	struct linux_select_args newsel;
372	int error;
373
374#ifdef DEBUG
375	if (ldebug(old_select))
376		printf(ARGS(old_select, "%p"), args->ptr);
377#endif
378
379	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
380	if (error)
381		return (error);
382
383	newsel.nfds = linux_args.nfds;
384	newsel.readfds = PTRIN(linux_args.readfds);
385	newsel.writefds = PTRIN(linux_args.writefds);
386	newsel.exceptfds = PTRIN(linux_args.exceptfds);
387	newsel.timeout = PTRIN(linux_args.timeout);
388	return (linux_select(td, &newsel));
389}
390
391int
392linux_set_cloned_tls(struct thread *td, void *desc)
393{
394	struct user_segment_descriptor sd;
395	struct l_user_desc info;
396	struct pcb *pcb;
397	int error;
398	int a[2];
399
400	error = copyin(desc, &info, sizeof(struct l_user_desc));
401	if (error) {
402		printf(LMSG("copyin failed!"));
403	} else {
404		/* We might copy out the entry_number as GUGS32_SEL. */
405		info.entry_number = GUGS32_SEL;
406		error = copyout(&info, desc, sizeof(struct l_user_desc));
407		if (error)
408			printf(LMSG("copyout failed!"));
409
410		a[0] = LINUX_LDT_entry_a(&info);
411		a[1] = LINUX_LDT_entry_b(&info);
412
413		memcpy(&sd, &a, sizeof(a));
414#ifdef DEBUG
415		if (ldebug(clone))
416			printf("Segment created in clone with "
417			    "CLONE_SETTLS: lobase: %x, hibase: %x, "
418			    "lolimit: %x, hilimit: %x, type: %i, "
419			    "dpl: %i, p: %i, xx: %i, long: %i, "
420			    "def32: %i, gran: %i\n", sd.sd_lobase,
421			    sd.sd_hibase, sd.sd_lolimit, sd.sd_hilimit,
422			    sd.sd_type, sd.sd_dpl, sd.sd_p, sd.sd_xx,
423			    sd.sd_long, sd.sd_def32, sd.sd_gran);
424#endif
425		pcb = td->td_pcb;
426		pcb->pcb_gsbase = (register_t)info.base_addr;
427		td->td_frame->tf_gs = GSEL(GUGS32_SEL, SEL_UPL);
428		set_pcb_flags(pcb, PCB_32BIT);
429	}
430
431	return (error);
432}
433
434int
435linux_set_upcall_kse(struct thread *td, register_t stack)
436{
437
438	if (stack)
439		td->td_frame->tf_rsp = stack;
440
441	/*
442	 * The newly created Linux thread returns
443	 * to the user space by the same path that a parent do.
444	 */
445	td->td_frame->tf_rax = 0;
446	return (0);
447}
448
449int
450linux_mmap2(struct thread *td, struct linux_mmap2_args *args)
451{
452
453#ifdef DEBUG
454	if (ldebug(mmap2))
455		printf(ARGS(mmap2, "0x%08x, %d, %d, 0x%08x, %d, %d"),
456		    args->addr, args->len, args->prot,
457		    args->flags, args->fd, args->pgoff);
458#endif
459
460	return (linux_mmap_common(td, PTROUT(args->addr), args->len, args->prot,
461		args->flags, args->fd, (uint64_t)(uint32_t)args->pgoff *
462		PAGE_SIZE));
463}
464
465int
466linux_mmap(struct thread *td, struct linux_mmap_args *args)
467{
468	int error;
469	struct l_mmap_argv linux_args;
470
471	error = copyin(args->ptr, &linux_args, sizeof(linux_args));
472	if (error)
473		return (error);
474
475#ifdef DEBUG
476	if (ldebug(mmap))
477		printf(ARGS(mmap, "0x%08x, %d, %d, 0x%08x, %d, %d"),
478		    linux_args.addr, linux_args.len, linux_args.prot,
479		    linux_args.flags, linux_args.fd, linux_args.pgoff);
480#endif
481
482	return (linux_mmap_common(td, linux_args.addr, linux_args.len,
483	    linux_args.prot, linux_args.flags, linux_args.fd,
484	    (uint32_t)linux_args.pgoff));
485}
486
487int
488linux_mprotect(struct thread *td, struct linux_mprotect_args *uap)
489{
490
491	return (linux_mprotect_common(td, PTROUT(uap->addr), uap->len, uap->prot));
492}
493
494int
495linux_iopl(struct thread *td, struct linux_iopl_args *args)
496{
497	int error;
498
499	if (args->level < 0 || args->level > 3)
500		return (EINVAL);
501	if ((error = priv_check(td, PRIV_IO)) != 0)
502		return (error);
503	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
504		return (error);
505	td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) |
506	    (args->level * (PSL_IOPL / 3));
507
508	return (0);
509}
510
511int
512linux_sigaction(struct thread *td, struct linux_sigaction_args *args)
513{
514	l_osigaction_t osa;
515	l_sigaction_t act, oact;
516	int error;
517
518#ifdef DEBUG
519	if (ldebug(sigaction))
520		printf(ARGS(sigaction, "%d, %p, %p"),
521		    args->sig, (void *)args->nsa, (void *)args->osa);
522#endif
523
524	if (args->nsa != NULL) {
525		error = copyin(args->nsa, &osa, sizeof(l_osigaction_t));
526		if (error)
527			return (error);
528		act.lsa_handler = osa.lsa_handler;
529		act.lsa_flags = osa.lsa_flags;
530		act.lsa_restorer = osa.lsa_restorer;
531		LINUX_SIGEMPTYSET(act.lsa_mask);
532		act.lsa_mask.__mask = osa.lsa_mask;
533	}
534
535	error = linux_do_sigaction(td, args->sig, args->nsa ? &act : NULL,
536	    args->osa ? &oact : NULL);
537
538	if (args->osa != NULL && !error) {
539		osa.lsa_handler = oact.lsa_handler;
540		osa.lsa_flags = oact.lsa_flags;
541		osa.lsa_restorer = oact.lsa_restorer;
542		osa.lsa_mask = oact.lsa_mask.__mask;
543		error = copyout(&osa, args->osa, sizeof(l_osigaction_t));
544	}
545
546	return (error);
547}
548
549/*
550 * Linux has two extra args, restart and oldmask.  We don't use these,
551 * but it seems that "restart" is actually a context pointer that
552 * enables the signal to happen with a different register set.
553 */
554int
555linux_sigsuspend(struct thread *td, struct linux_sigsuspend_args *args)
556{
557	sigset_t sigmask;
558	l_sigset_t mask;
559
560#ifdef DEBUG
561	if (ldebug(sigsuspend))
562		printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
563#endif
564
565	LINUX_SIGEMPTYSET(mask);
566	mask.__mask = args->mask;
567	linux_to_bsd_sigset(&mask, &sigmask);
568	return (kern_sigsuspend(td, sigmask));
569}
570
571int
572linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap)
573{
574	l_sigset_t lmask;
575	sigset_t sigmask;
576	int error;
577
578#ifdef DEBUG
579	if (ldebug(rt_sigsuspend))
580		printf(ARGS(rt_sigsuspend, "%p, %d"),
581		    (void *)uap->newset, uap->sigsetsize);
582#endif
583
584	if (uap->sigsetsize != sizeof(l_sigset_t))
585		return (EINVAL);
586
587	error = copyin(uap->newset, &lmask, sizeof(l_sigset_t));
588	if (error)
589		return (error);
590
591	linux_to_bsd_sigset(&lmask, &sigmask);
592	return (kern_sigsuspend(td, sigmask));
593}
594
595int
596linux_pause(struct thread *td, struct linux_pause_args *args)
597{
598	struct proc *p = td->td_proc;
599	sigset_t sigmask;
600
601#ifdef DEBUG
602	if (ldebug(pause))
603		printf(ARGS(pause, ""));
604#endif
605
606	PROC_LOCK(p);
607	sigmask = td->td_sigmask;
608	PROC_UNLOCK(p);
609	return (kern_sigsuspend(td, sigmask));
610}
611
612int
613linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap)
614{
615	stack_t ss, oss;
616	l_stack_t lss;
617	int error;
618
619#ifdef DEBUG
620	if (ldebug(sigaltstack))
621		printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
622#endif
623
624	if (uap->uss != NULL) {
625		error = copyin(uap->uss, &lss, sizeof(l_stack_t));
626		if (error)
627			return (error);
628
629		ss.ss_sp = PTRIN(lss.ss_sp);
630		ss.ss_size = lss.ss_size;
631		ss.ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags);
632	}
633	error = kern_sigaltstack(td, (uap->uss != NULL) ? &ss : NULL,
634	    (uap->uoss != NULL) ? &oss : NULL);
635	if (!error && uap->uoss != NULL) {
636		lss.ss_sp = PTROUT(oss.ss_sp);
637		lss.ss_size = oss.ss_size;
638		lss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags);
639		error = copyout(&lss, uap->uoss, sizeof(l_stack_t));
640	}
641
642	return (error);
643}
644
645int
646linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
647{
648	struct ftruncate_args sa;
649
650#ifdef DEBUG
651	if (ldebug(ftruncate64))
652		printf(ARGS(ftruncate64, "%u, %jd"), args->fd,
653		    (intmax_t)args->length);
654#endif
655
656	sa.fd = args->fd;
657	sa.length = args->length;
658	return sys_ftruncate(td, &sa);
659}
660
661int
662linux_gettimeofday(struct thread *td, struct linux_gettimeofday_args *uap)
663{
664	struct timeval atv;
665	l_timeval atv32;
666	struct timezone rtz;
667	int error = 0;
668
669	if (uap->tp) {
670		microtime(&atv);
671		atv32.tv_sec = atv.tv_sec;
672		atv32.tv_usec = atv.tv_usec;
673		error = copyout(&atv32, uap->tp, sizeof(atv32));
674	}
675	if (error == 0 && uap->tzp != NULL) {
676		rtz.tz_minuteswest = tz_minuteswest;
677		rtz.tz_dsttime = tz_dsttime;
678		error = copyout(&rtz, uap->tzp, sizeof(rtz));
679	}
680	return (error);
681}
682
683int
684linux_settimeofday(struct thread *td, struct linux_settimeofday_args *uap)
685{
686	l_timeval atv32;
687	struct timeval atv, *tvp;
688	struct timezone atz, *tzp;
689	int error;
690
691	if (uap->tp) {
692		error = copyin(uap->tp, &atv32, sizeof(atv32));
693		if (error)
694			return (error);
695		atv.tv_sec = atv32.tv_sec;
696		atv.tv_usec = atv32.tv_usec;
697		tvp = &atv;
698	} else
699		tvp = NULL;
700	if (uap->tzp) {
701		error = copyin(uap->tzp, &atz, sizeof(atz));
702		if (error)
703			return (error);
704		tzp = &atz;
705	} else
706		tzp = NULL;
707	return (kern_settimeofday(td, tvp, tzp));
708}
709
710int
711linux_getrusage(struct thread *td, struct linux_getrusage_args *uap)
712{
713	struct rusage s;
714	int error;
715
716	error = kern_getrusage(td, uap->who, &s);
717	if (error != 0)
718		return (error);
719	if (uap->rusage != NULL)
720		error = linux_copyout_rusage(&s, uap->rusage);
721	return (error);
722}
723
724int
725linux_set_thread_area(struct thread *td,
726    struct linux_set_thread_area_args *args)
727{
728	struct l_user_desc info;
729	struct user_segment_descriptor sd;
730	struct pcb *pcb;
731	int a[2];
732	int error;
733
734	error = copyin(args->desc, &info, sizeof(struct l_user_desc));
735	if (error)
736		return (error);
737
738#ifdef DEBUG
739	if (ldebug(set_thread_area))
740		printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, "
741		    "%i, %i, %i"), info.entry_number, info.base_addr,
742		    info.limit, info.seg_32bit, info.contents,
743		    info.read_exec_only, info.limit_in_pages,
744		    info.seg_not_present, info.useable);
745#endif
746
747	/*
748	 * Semantics of Linux version: every thread in the system has array
749	 * of three TLS descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown.
750	 * This syscall loads one of the selected TLS decriptors with a value
751	 * and also loads GDT descriptors 6, 7 and 8 with the content of
752	 * the per-thread descriptors.
753	 *
754	 * Semantics of FreeBSD version: I think we can ignore that Linux has
755	 * three per-thread descriptors and use just the first one.
756	 * The tls_array[] is used only in [gs]et_thread_area() syscalls and
757	 * for loading the GDT descriptors. We use just one GDT descriptor
758	 * for TLS, so we will load just one.
759	 *
760	 * XXX: This doesn't work when a user space process tries to use more
761	 * than one TLS segment. Comment in the Linux source says wine might
762	 * do this.
763	 */
764
765	/*
766	 * GLIBC reads current %gs and call set_thread_area() with it.
767	 * We should let GUDATA_SEL and GUGS32_SEL proceed as well because
768	 * we use these segments.
769	 */
770	switch (info.entry_number) {
771	case GUGS32_SEL:
772	case GUDATA_SEL:
773	case 6:
774	case -1:
775		info.entry_number = GUGS32_SEL;
776		break;
777	default:
778		return (EINVAL);
779	}
780
781	/*
782	 * We have to copy out the GDT entry we use.
783	 *
784	 * XXX: What if a user space program does not check the return value
785	 * and tries to use 6, 7 or 8?
786	 */
787	error = copyout(&info, args->desc, sizeof(struct l_user_desc));
788	if (error)
789		return (error);
790
791	if (LINUX_LDT_empty(&info)) {
792		a[0] = 0;
793		a[1] = 0;
794	} else {
795		a[0] = LINUX_LDT_entry_a(&info);
796		a[1] = LINUX_LDT_entry_b(&info);
797	}
798
799	memcpy(&sd, &a, sizeof(a));
800#ifdef DEBUG
801	if (ldebug(set_thread_area))
802		printf("Segment created in set_thread_area: "
803		    "lobase: %x, hibase: %x, lolimit: %x, hilimit: %x, "
804		    "type: %i, dpl: %i, p: %i, xx: %i, long: %i, "
805		    "def32: %i, gran: %i\n",
806		    sd.sd_lobase,
807		    sd.sd_hibase,
808		    sd.sd_lolimit,
809		    sd.sd_hilimit,
810		    sd.sd_type,
811		    sd.sd_dpl,
812		    sd.sd_p,
813		    sd.sd_xx,
814		    sd.sd_long,
815		    sd.sd_def32,
816		    sd.sd_gran);
817#endif
818
819	pcb = td->td_pcb;
820	pcb->pcb_gsbase = (register_t)info.base_addr;
821	set_pcb_flags(pcb, PCB_32BIT);
822	update_gdt_gsbase(td, info.base_addr);
823
824	return (0);
825}
826