xref: /freebsd-12.1/sys/compat/linux/linux_misc.c (revision f437b38c)
1 /*-
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *  $Id: linux_misc.c,v 1.64 1999/08/16 11:49:30 marcel Exp $
29  */
30 
31 #include "opt_compat.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/sysproto.h>
36 #include <sys/kernel.h>
37 #include <sys/mman.h>
38 #include <sys/proc.h>
39 #include <sys/fcntl.h>
40 #include <sys/imgact_aout.h>
41 #include <sys/mount.h>
42 #include <sys/namei.h>
43 #include <sys/resourcevar.h>
44 #include <sys/stat.h>
45 #include <sys/sysctl.h>
46 #include <sys/unistd.h>
47 #include <sys/vnode.h>
48 #include <sys/wait.h>
49 #include <sys/time.h>
50 
51 #include <vm/vm.h>
52 #include <vm/pmap.h>
53 #include <vm/vm_kern.h>
54 #include <vm/vm_prot.h>
55 #include <vm/vm_map.h>
56 #include <vm/vm_extern.h>
57 
58 #include <machine/frame.h>
59 #include <machine/psl.h>
60 
61 #include <i386/linux/linux.h>
62 #include <i386/linux/linux_proto.h>
63 #include <i386/linux/linux_util.h>
64 
65 #include <posix4/sched.h>
66 
67 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] =
68 { RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
69   RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
70   RLIMIT_MEMLOCK, -1
71 };
72 
73 int
74 linux_alarm(struct proc *p, struct linux_alarm_args *args)
75 {
76     struct itimerval it, old_it;
77     struct timeval tv;
78     int s;
79 
80 #ifdef DEBUG
81     printf("Linux-emul(%ld): alarm(%u)\n", (long)p->p_pid, args->secs);
82 #endif
83     if (args->secs > 100000000)
84 	return EINVAL;
85     it.it_value.tv_sec = (long)args->secs;
86     it.it_value.tv_usec = 0;
87     it.it_interval.tv_sec = 0;
88     it.it_interval.tv_usec = 0;
89     s = splsoftclock();
90     old_it = p->p_realtimer;
91     getmicrouptime(&tv);
92     if (timevalisset(&old_it.it_value))
93 	untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
94     if (it.it_value.tv_sec != 0) {
95 	p->p_ithandle = timeout(realitexpire, (caddr_t)p, tvtohz(&it.it_value));
96 	timevaladd(&it.it_value, &tv);
97     }
98     p->p_realtimer = it;
99     splx(s);
100     if (timevalcmp(&old_it.it_value, &tv, >)) {
101 	timevalsub(&old_it.it_value, &tv);
102 	if (old_it.it_value.tv_usec != 0)
103 	    old_it.it_value.tv_sec++;
104 	p->p_retval[0] = old_it.it_value.tv_sec;
105     }
106     return 0;
107 }
108 
109 int
110 linux_brk(struct proc *p, struct linux_brk_args *args)
111 {
112 #if 0
113     struct vmspace *vm = p->p_vmspace;
114     vm_offset_t new, old;
115     int error;
116 
117     if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
118 	return EINVAL;
119     if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
120 	> p->p_rlimit[RLIMIT_DATA].rlim_cur)
121 	return ENOMEM;
122 
123     old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
124     new = round_page((vm_offset_t)args->dsend);
125     p->p_retval[0] = old;
126     if ((new-old) > 0) {
127 	if (swap_pager_full)
128 	    return ENOMEM;
129 	error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE,
130 			VM_PROT_ALL, VM_PROT_ALL, 0);
131 	if (error)
132 	    return error;
133 	vm->vm_dsize += btoc((new-old));
134 	p->p_retval[0] = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
135     }
136     return 0;
137 #else
138     struct vmspace *vm = p->p_vmspace;
139     vm_offset_t new, old;
140     struct obreak_args /* {
141 	char * nsize;
142     } */ tmp;
143 
144 #ifdef DEBUG
145     printf("Linux-emul(%ld): brk(%p)\n", (long)p->p_pid, (void *)args->dsend);
146 #endif
147     old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
148     new = (vm_offset_t)args->dsend;
149     tmp.nsize = (char *) new;
150     if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp))
151 	p->p_retval[0] = (int)new;
152     else
153 	p->p_retval[0] = (int)old;
154 
155     return 0;
156 #endif
157 }
158 
159 int
160 linux_uselib(struct proc *p, struct linux_uselib_args *args)
161 {
162     struct nameidata ni;
163     struct vnode *vp;
164     struct exec *a_out;
165     struct vattr attr;
166     vm_offset_t vmaddr;
167     unsigned long file_offset;
168     vm_offset_t buffer;
169     unsigned long bss_size;
170     int error;
171     caddr_t sg;
172     int locked;
173 
174     sg = stackgap_init();
175     CHECKALTEXIST(p, &sg, args->library);
176 
177 #ifdef DEBUG
178     printf("Linux-emul(%ld): uselib(%s)\n", (long)p->p_pid, args->library);
179 #endif
180 
181     a_out = NULL;
182     locked = 0;
183     vp = NULL;
184 
185     NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, args->library, p);
186     error = namei(&ni);
187     if (error)
188 	goto cleanup;
189 
190     vp = ni.ni_vp;
191     if (vp == NULL) {
192 	error = ENOEXEC;	/* ?? */
193 	goto cleanup;
194     }
195 
196     /*
197      * From here on down, we have a locked vnode that must be unlocked.
198      */
199     locked++;
200 
201     /*
202      * Writable?
203      */
204     if (vp->v_writecount) {
205 	error = ETXTBSY;
206 	goto cleanup;
207     }
208 
209     /*
210      * Executable?
211      */
212     error = VOP_GETATTR(vp, &attr, p->p_ucred, p);
213     if (error)
214 	goto cleanup;
215 
216     if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
217 	((attr.va_mode & 0111) == 0) ||
218 	(attr.va_type != VREG)) {
219 	    error = ENOEXEC;
220 	    goto cleanup;
221     }
222 
223     /*
224      * Sensible size?
225      */
226     if (attr.va_size == 0) {
227 	error = ENOEXEC;
228 	goto cleanup;
229     }
230 
231     /*
232      * Can we access it?
233      */
234     error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
235     if (error)
236 	goto cleanup;
237 
238     error = VOP_OPEN(vp, FREAD, p->p_ucred, p);
239     if (error)
240 	goto cleanup;
241 
242     /*
243      * Lock no longer needed
244      */
245     VOP_UNLOCK(vp, 0, p);
246     locked = 0;
247 
248     /*
249      * Pull in executable header into kernel_map
250      */
251     error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
252 	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
253     if (error)
254 	goto cleanup;
255 
256     /*
257      * Is it a Linux binary ?
258      */
259     if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
260 	error = ENOEXEC;
261 	goto cleanup;
262     }
263 
264     /* While we are here, we should REALLY do some more checks */
265 
266     /*
267      * Set file/virtual offset based on a.out variant.
268      */
269     switch ((int)(a_out->a_magic & 0xffff)) {
270     case 0413:	/* ZMAGIC */
271 	file_offset = 1024;
272 	break;
273     case 0314:	/* QMAGIC */
274 	file_offset = 0;
275 	break;
276     default:
277 	error = ENOEXEC;
278 	goto cleanup;
279     }
280 
281     bss_size = round_page(a_out->a_bss);
282 
283     /*
284      * Check various fields in header for validity/bounds.
285      */
286     if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
287 	error = ENOEXEC;
288 	goto cleanup;
289     }
290 
291     /* text + data can't exceed file size */
292     if (a_out->a_data + a_out->a_text > attr.va_size) {
293 	error = EFAULT;
294 	goto cleanup;
295     }
296 
297     /*
298      * text/data/bss must not exceed limits
299      * XXX: this is not complete. it should check current usage PLUS
300      * the resources needed by this library.
301      */
302     if (a_out->a_text > MAXTSIZ ||
303 	a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
304 	error = ENOMEM;
305 	goto cleanup;
306     }
307 
308     /*
309      * prevent more writers
310      */
311     vp->v_flag |= VTEXT;
312 
313     /*
314      * Check if file_offset page aligned,.
315      * Currently we cannot handle misalinged file offsets,
316      * and so we read in the entire image (what a waste).
317      */
318     if (file_offset & PAGE_MASK) {
319 #ifdef DEBUG
320 printf("uselib: Non page aligned binary %lu\n", file_offset);
321 #endif
322 	/*
323 	 * Map text+data read/write/execute
324 	 */
325 
326 	/* a_entry is the load address and is page aligned */
327 	vmaddr = trunc_page(a_out->a_entry);
328 
329 	/* get anon user mapping, read+write+execute */
330 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
331 		    	    a_out->a_text + a_out->a_data, FALSE,
332 			    VM_PROT_ALL, VM_PROT_ALL, 0);
333 	if (error)
334 	    goto cleanup;
335 
336 	/* map file into kernel_map */
337 	error = vm_mmap(kernel_map, &buffer,
338 			round_page(a_out->a_text + a_out->a_data + file_offset),
339 		   	VM_PROT_READ, VM_PROT_READ, 0,
340 			(caddr_t)vp, trunc_page(file_offset));
341 	if (error)
342 	    goto cleanup;
343 
344 	/* copy from kernel VM space to user space */
345 	error = copyout((caddr_t)(void *)(uintptr_t)(buffer + file_offset),
346 			(caddr_t)vmaddr, a_out->a_text + a_out->a_data);
347 
348 	/* release temporary kernel space */
349 	vm_map_remove(kernel_map, buffer,
350 		      buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
351 
352 	if (error)
353 	    goto cleanup;
354     }
355     else {
356 #ifdef DEBUG
357 printf("uselib: Page aligned binary %lu\n", file_offset);
358 #endif
359 	/*
360 	 * for QMAGIC, a_entry is 20 bytes beyond the load address
361 	 * to skip the executable header
362 	 */
363 	vmaddr = trunc_page(a_out->a_entry);
364 
365 	/*
366 	 * Map it all into the process's space as a single copy-on-write
367 	 * "data" segment.
368 	 */
369 	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
370 		   	a_out->a_text + a_out->a_data,
371 			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
372 			(caddr_t)vp, file_offset);
373 	if (error)
374 	    goto cleanup;
375     }
376 #ifdef DEBUG
377 printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
378 #endif
379     if (bss_size != 0) {
380         /*
381 	 * Calculate BSS start address
382 	 */
383 	vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data;
384 
385 	/*
386 	 * allocate some 'anon' space
387 	 */
388 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
389 			    bss_size, FALSE,
390 			    VM_PROT_ALL, VM_PROT_ALL, 0);
391 	if (error)
392 	    goto cleanup;
393     }
394 
395 cleanup:
396     /*
397      * Unlock vnode if needed
398      */
399     if (locked)
400 	VOP_UNLOCK(vp, 0, p);
401 
402     /*
403      * Release the kernel mapping.
404      */
405     if (a_out)
406 	vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE);
407 
408     return error;
409 }
410 
411 /* XXX move */
412 struct linux_select_argv {
413 	int nfds;
414 	fd_set *readfds;
415 	fd_set *writefds;
416 	fd_set *exceptfds;
417 	struct timeval *timeout;
418 };
419 
420 int
421 linux_select(struct proc *p, struct linux_select_args *args)
422 {
423     struct linux_select_argv linux_args;
424     struct linux_newselect_args newsel;
425     int error;
426 
427 #ifdef SELECT_DEBUG
428     printf("Linux-emul(%ld): select(%x)\n", (long)p->p_pid, args->ptr);
429 #endif
430     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
431 			sizeof(linux_args))))
432 	return error;
433 
434     newsel.nfds = linux_args.nfds;
435     newsel.readfds = linux_args.readfds;
436     newsel.writefds = linux_args.writefds;
437     newsel.exceptfds = linux_args.exceptfds;
438     newsel.timeout = linux_args.timeout;
439 
440     return linux_newselect(p, &newsel);
441 }
442 
443 int
444 linux_newselect(struct proc *p, struct linux_newselect_args *args)
445 {
446     struct select_args bsa;
447     struct timeval tv0, tv1, utv, *tvp;
448     caddr_t sg;
449     int error;
450 
451 #ifdef DEBUG
452     printf("Linux-emul(%ld): newselect(%d, %p, %p, %p, %p)\n",
453   	(long)p->p_pid, args->nfds, (void *)args->readfds,
454 	(void *)args->writefds, (void *)args->exceptfds,
455 	(void *)args->timeout);
456 #endif
457     error = 0;
458     bsa.nd = args->nfds;
459     bsa.in = args->readfds;
460     bsa.ou = args->writefds;
461     bsa.ex = args->exceptfds;
462     bsa.tv = args->timeout;
463 
464     /*
465      * Store current time for computation of the amount of
466      * time left.
467      */
468     if (args->timeout) {
469 	if ((error = copyin(args->timeout, &utv, sizeof(utv))))
470 	    goto select_out;
471 #ifdef DEBUG
472 	printf("Linux-emul(%ld): incoming timeout (%ld/%ld)\n",
473 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
474 #endif
475 	if (itimerfix(&utv)) {
476 	    /*
477 	     * The timeval was invalid.  Convert it to something
478 	     * valid that will act as it does under Linux.
479 	     */
480 	    sg = stackgap_init();
481 	    tvp = stackgap_alloc(&sg, sizeof(utv));
482 	    utv.tv_sec += utv.tv_usec / 1000000;
483 	    utv.tv_usec %= 1000000;
484 	    if (utv.tv_usec < 0) {
485 		utv.tv_sec -= 1;
486 		utv.tv_usec += 1000000;
487 	    }
488 	    if (utv.tv_sec < 0)
489 		timevalclear(&utv);
490 	    if ((error = copyout(&utv, tvp, sizeof(utv))))
491 		goto select_out;
492 	    bsa.tv = tvp;
493 	}
494 	microtime(&tv0);
495     }
496 
497     error = select(p, &bsa);
498 #ifdef DEBUG
499     printf("Linux-emul(%ld): real select returns %d\n", (long)p->p_pid, error);
500 #endif
501 
502     if (error) {
503 	/*
504 	 * See fs/select.c in the Linux kernel.  Without this,
505 	 * Maelstrom doesn't work.
506 	 */
507 	if (error == ERESTART)
508 	    error = EINTR;
509 	goto select_out;
510     }
511 
512     if (args->timeout) {
513 	if (p->p_retval[0]) {
514 	    /*
515 	     * Compute how much time was left of the timeout,
516 	     * by subtracting the current time and the time
517 	     * before we started the call, and subtracting
518 	     * that result from the user-supplied value.
519 	     */
520 	    microtime(&tv1);
521 	    timevalsub(&tv1, &tv0);
522 	    timevalsub(&utv, &tv1);
523 	    if (utv.tv_sec < 0)
524 		timevalclear(&utv);
525 	} else
526 	    timevalclear(&utv);
527 #ifdef DEBUG
528 	printf("Linux-emul(%ld): outgoing timeout (%ld/%ld)\n",
529 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
530 #endif
531 	if ((error = copyout(&utv, args->timeout, sizeof(utv))))
532 	    goto select_out;
533     }
534 
535 select_out:
536 #ifdef DEBUG
537     printf("Linux-emul(%ld): newselect_out -> %d\n", (long)p->p_pid, error);
538 #endif
539     return error;
540 }
541 
542 int
543 linux_getpgid(struct proc *p, struct linux_getpgid_args *args)
544 {
545     struct proc *curp;
546 
547 #ifdef DEBUG
548     printf("Linux-emul(%ld): getpgid(%d)\n", (long)p->p_pid, args->pid);
549 #endif
550     if (args->pid != p->p_pid) {
551 	if (!(curp = pfind(args->pid)))
552 	    return ESRCH;
553     }
554     else
555 	curp = p;
556     p->p_retval[0] = curp->p_pgid;
557     return 0;
558 }
559 
560 int
561 linux_fork(struct proc *p, struct linux_fork_args *args)
562 {
563     int error;
564 
565 #ifdef DEBUG
566     printf("Linux-emul(%ld): fork()\n", (long)p->p_pid);
567 #endif
568     if ((error = fork(p, (struct fork_args *)args)) != 0)
569 	return error;
570     if (p->p_retval[1] == 1)
571 	p->p_retval[0] = 0;
572     return 0;
573 }
574 
575 int
576 linux_vfork(struct proc *p, struct linux_vfork_args *args)
577 {
578 	int error;
579 
580 #ifdef DEBUG
581 	printf("Linux-emul(%ld): vfork()\n", (long)p->p_pid);
582 #endif
583 
584 	if ((error = vfork(p, (struct vfork_args *)args)) != 0)
585 		return error;
586 	/* Are we the child? */
587 	if (p->p_retval[1] == 1)
588 		p->p_retval[0] = 0;
589 	return 0;
590 }
591 
592 #define CLONE_VM	0x100
593 #define CLONE_FS	0x200
594 #define CLONE_FILES	0x400
595 #define CLONE_SIGHAND	0x800
596 #define CLONE_PID	0x1000
597 
598 int
599 linux_clone(struct proc *p, struct linux_clone_args *args)
600 {
601     int error, ff = RFPROC;
602     struct proc *p2;
603     int            exit_signal;
604     vm_offset_t    start;
605     struct rfork_args rf_args;
606 
607 #ifdef DEBUG
608     if (args->flags & CLONE_PID)
609 	printf("linux_clone(%ld): CLONE_PID not yet supported\n",
610 	       (long)p->p_pid);
611     printf("linux_clone(%ld): invoked with flags %x and stack %x\n",
612 	   (long)p->p_pid, (unsigned int)args->flags,
613 	   (unsigned int)args->stack);
614 #endif
615 
616     if (!args->stack)
617         return (EINVAL);
618 
619     exit_signal = args->flags & 0x000000ff;
620     if (exit_signal >= LINUX_NSIG)
621 	return EINVAL;
622     exit_signal = linux_to_bsd_signal[exit_signal];
623 
624     /* RFTHREAD probably not necessary here, but it shouldn't hurt either */
625     ff |= RFTHREAD;
626 
627     if (args->flags & CLONE_VM)
628 	ff |= RFMEM;
629     if (args->flags & CLONE_SIGHAND)
630 	ff |= RFSIGSHARE;
631     if (!(args->flags & CLONE_FILES))
632 	ff |= RFFDG;
633 
634     error = 0;
635     start = 0;
636 
637     rf_args.flags = ff;
638     if ((error = rfork(p, &rf_args)) != 0)
639 	return error;
640 
641     p2 = pfind(p->p_retval[0]);
642     if (p2 == 0)
643  	return ESRCH;
644 
645     p2->p_sigparent = exit_signal;
646     p2->p_md.md_regs->tf_esp = (unsigned int)args->stack;
647 
648 #ifdef DEBUG
649     printf ("linux_clone(%ld): successful rfork to %ld\n",
650 	    (long)p->p_pid, (long)p2->p_pid);
651 #endif
652     return 0;
653 }
654 
655 /* XXX move */
656 struct linux_mmap_argv {
657 	linux_caddr_t addr;
658 	int len;
659 	int prot;
660 	int flags;
661 	int fd;
662 	int pos;
663 };
664 
665 #define STACK_SIZE  (2 * 1024 * 1024)
666 #define GUARD_SIZE  (4 * PAGE_SIZE)
667 int
668 linux_mmap(struct proc *p, struct linux_mmap_args *args)
669 {
670     struct mmap_args /* {
671 	caddr_t addr;
672 	size_t len;
673 	int prot;
674 	int flags;
675 	int fd;
676 	long pad;
677 	off_t pos;
678     } */ bsd_args;
679     int error;
680     struct linux_mmap_argv linux_args;
681 
682     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
683 			sizeof(linux_args))))
684 	return error;
685 #ifdef DEBUG
686     printf("Linux-emul(%ld): mmap(%p, %d, %d, %08x, %d, %d)\n",
687 	(long)p->p_pid, (void *)linux_args.addr, linux_args.len,
688 	linux_args.prot, linux_args.flags, linux_args.fd, linux_args.pos);
689 #endif
690     bsd_args.flags = 0;
691     if (linux_args.flags & LINUX_MAP_SHARED)
692 	bsd_args.flags |= MAP_SHARED;
693     if (linux_args.flags & LINUX_MAP_PRIVATE)
694 	bsd_args.flags |= MAP_PRIVATE;
695     if (linux_args.flags & LINUX_MAP_FIXED)
696 	bsd_args.flags |= MAP_FIXED;
697     if (linux_args.flags & LINUX_MAP_ANON)
698 	bsd_args.flags |= MAP_ANON;
699     if (linux_args.flags & LINUX_MAP_GROWSDOWN) {
700 	bsd_args.flags |= MAP_STACK;
701 
702 	/* The linux MAP_GROWSDOWN option does not limit auto
703 	 * growth of the region.  Linux mmap with this option
704 	 * takes as addr the inital BOS, and as len, the initial
705 	 * region size.  It can then grow down from addr without
706 	 * limit.  However, linux threads has an implicit internal
707 	 * limit to stack size of STACK_SIZE.  Its just not
708 	 * enforced explicitly in linux.  But, here we impose
709 	 * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
710 	 * region, since we can do this with our mmap.
711 	 *
712 	 * Our mmap with MAP_STACK takes addr as the maximum
713 	 * downsize limit on BOS, and as len the max size of
714 	 * the region.  It them maps the top SGROWSIZ bytes,
715 	 * and autgrows the region down, up to the limit
716 	 * in addr.
717 	 *
718 	 * If we don't use the MAP_STACK option, the effect
719 	 * of this code is to allocate a stack region of a
720 	 * fixed size of (STACK_SIZE - GUARD_SIZE).
721 	 */
722 
723 	/* This gives us TOS */
724 	bsd_args.addr = linux_args.addr + linux_args.len;
725 
726 	/* This gives us our maximum stack size */
727 	if (linux_args.len > STACK_SIZE - GUARD_SIZE)
728 	    bsd_args.len = linux_args.len;
729 	else
730 	    bsd_args.len  = STACK_SIZE - GUARD_SIZE;
731 
732 	/* This gives us a new BOS.  If we're using VM_STACK, then
733 	 * mmap will just map the top SGROWSIZ bytes, and let
734 	 * the stack grow down to the limit at BOS.  If we're
735 	 * not using VM_STACK we map the full stack, since we
736 	 * don't have a way to autogrow it.
737 	 */
738 	bsd_args.addr -= bsd_args.len;
739 
740     } else {
741 	bsd_args.addr = linux_args.addr;
742 	bsd_args.len  = linux_args.len;
743     }
744 
745     bsd_args.prot = linux_args.prot | PROT_READ;	/* always required */
746     bsd_args.fd = linux_args.fd;
747     bsd_args.pos = linux_args.pos;
748     bsd_args.pad = 0;
749     return mmap(p, &bsd_args);
750 }
751 
752 int
753 linux_mremap(struct proc *p, struct linux_mremap_args *args)
754 {
755 	struct munmap_args /* {
756 		void *addr;
757 		size_t len;
758 	} */ bsd_args;
759 	int error = 0;
760 
761 #ifdef DEBUG
762 	printf("Linux-emul(%ld): mremap(%p, %08x, %08x, %08x)\n",
763 	    (long)p->p_pid, (void *)args->addr, args->old_len, args->new_len,
764 	    args->flags);
765 #endif
766 	args->new_len = round_page(args->new_len);
767 	args->old_len = round_page(args->old_len);
768 
769 	if (args->new_len > args->old_len) {
770 		p->p_retval[0] = 0;
771 		return ENOMEM;
772 	}
773 
774 	if (args->new_len < args->old_len) {
775 		bsd_args.addr = args->addr + args->new_len;
776 		bsd_args.len = args->old_len - args->new_len;
777 		error = munmap(p, &bsd_args);
778 	}
779 
780 	p->p_retval[0] = error ? 0 : (int)args->addr;
781 	return error;
782 }
783 
784 int
785 linux_msync(struct proc *p, struct linux_msync_args *args)
786 {
787 	struct msync_args bsd_args;
788 
789 	bsd_args.addr = args->addr;
790 	bsd_args.len = args->len;
791 	bsd_args.flags = 0;	/* XXX ignore */
792 
793 	return msync(p, &bsd_args);
794 }
795 
796 int
797 linux_pipe(struct proc *p, struct linux_pipe_args *args)
798 {
799     int error;
800     int reg_edx;
801 
802 #ifdef DEBUG
803     printf("Linux-emul(%ld): pipe(*)\n", (long)p->p_pid);
804 #endif
805     reg_edx = p->p_retval[1];
806     error = pipe(p, 0);
807     if (error) {
808 	p->p_retval[1] = reg_edx;
809 	return error;
810     }
811 
812     error = copyout(p->p_retval, args->pipefds, 2*sizeof(int));
813     if (error) {
814 	p->p_retval[1] = reg_edx;
815 	return error;
816     }
817 
818     p->p_retval[1] = reg_edx;
819     p->p_retval[0] = 0;
820     return 0;
821 }
822 
823 int
824 linux_time(struct proc *p, struct linux_time_args *args)
825 {
826     struct timeval tv;
827     linux_time_t tm;
828     int error;
829 
830 #ifdef DEBUG
831     printf("Linux-emul(%ld): time(*)\n", (long)p->p_pid);
832 #endif
833     microtime(&tv);
834     tm = tv.tv_sec;
835     if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t))))
836 	return error;
837     p->p_retval[0] = tm;
838     return 0;
839 }
840 
841 struct linux_times_argv {
842     long    tms_utime;
843     long    tms_stime;
844     long    tms_cutime;
845     long    tms_cstime;
846 };
847 
848 #define CLK_TCK 100	/* Linux uses 100 */
849 #define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
850 
851 int
852 linux_times(struct proc *p, struct linux_times_args *args)
853 {
854     struct timeval tv;
855     struct linux_times_argv tms;
856     struct rusage ru;
857     int error;
858 
859 #ifdef DEBUG
860     printf("Linux-emul(%ld): times(*)\n", (long)p->p_pid);
861 #endif
862     calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
863 
864     tms.tms_utime = CONVTCK(ru.ru_utime);
865     tms.tms_stime = CONVTCK(ru.ru_stime);
866 
867     tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
868     tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
869 
870     if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf,
871 	    	    sizeof(struct linux_times_argv))))
872 	return error;
873 
874     microuptime(&tv);
875     p->p_retval[0] = (int)CONVTCK(tv);
876     return 0;
877 }
878 
879 /* XXX move */
880 struct linux_newuname_t {
881     char sysname[65];
882     char nodename[65];
883     char release[65];
884     char version[65];
885     char machine[65];
886     char domainname[65];
887 };
888 
889 int
890 linux_newuname(struct proc *p, struct linux_newuname_args *args)
891 {
892     struct linux_newuname_t linux_newuname;
893 
894 #ifdef DEBUG
895     printf("Linux-emul(%ld): newuname(*)\n", (long)p->p_pid);
896 #endif
897     bzero(&linux_newuname, sizeof(struct linux_newuname_t));
898     strncpy(linux_newuname.sysname, "Linux",
899 	sizeof(linux_newuname.sysname) - 1);
900     strncpy(linux_newuname.nodename, hostname,
901 	sizeof(linux_newuname.nodename) - 1);
902     strncpy(linux_newuname.release, "2.0.36",
903 	sizeof(linux_newuname.release) - 1);
904     strncpy(linux_newuname.version, version,
905 	sizeof(linux_newuname.version) - 1);
906     strncpy(linux_newuname.machine, machine,
907 	sizeof(linux_newuname.machine) - 1);
908     strncpy(linux_newuname.domainname, domainname,
909 	sizeof(linux_newuname.domainname) - 1);
910     return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf,
911 	    	    sizeof(struct linux_newuname_t)));
912 }
913 
914 struct linux_utimbuf {
915 	linux_time_t l_actime;
916 	linux_time_t l_modtime;
917 };
918 
919 int
920 linux_utime(struct proc *p, struct linux_utime_args *args)
921 {
922     struct utimes_args /* {
923 	char	*path;
924 	struct	timeval *tptr;
925     } */ bsdutimes;
926     struct timeval tv[2], *tvp;
927     struct linux_utimbuf lut;
928     int error;
929     caddr_t sg;
930 
931     sg = stackgap_init();
932     CHECKALTEXIST(p, &sg, args->fname);
933 
934 #ifdef DEBUG
935     printf("Linux-emul(%ld): utime(%s, *)\n", (long)p->p_pid, args->fname);
936 #endif
937     if (args->times) {
938 	if ((error = copyin(args->times, &lut, sizeof lut)))
939 	    return error;
940 	tv[0].tv_sec = lut.l_actime;
941 	tv[0].tv_usec = 0;
942 	tv[1].tv_sec = lut.l_modtime;
943 	tv[1].tv_usec = 0;
944 	/* so that utimes can copyin */
945 	tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv));
946 	if ((error = copyout(tv, tvp, sizeof(tv))))
947 	    return error;
948 	bsdutimes.tptr = tvp;
949     } else
950 	bsdutimes.tptr = NULL;
951 
952     bsdutimes.path = args->fname;
953     return utimes(p, &bsdutimes);
954 }
955 
956 #define __WCLONE 0x80000000
957 
958 int
959 linux_waitpid(struct proc *p, struct linux_waitpid_args *args)
960 {
961     struct wait_args /* {
962 	int pid;
963 	int *status;
964 	int options;
965 	struct	rusage *rusage;
966     } */ tmp;
967     int error, tmpstat;
968 
969 #ifdef DEBUG
970     printf("Linux-emul(%ld): waitpid(%d, %p, %d)\n",
971 	(long)p->p_pid, args->pid, (void *)args->status, args->options);
972 #endif
973     tmp.pid = args->pid;
974     tmp.status = args->status;
975     tmp.options = (args->options & (WNOHANG | WUNTRACED));
976     /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
977     if (args->options & __WCLONE)
978 	tmp.options |= WLINUXCLONE;
979     tmp.rusage = NULL;
980 
981     if ((error = wait4(p, &tmp)) != 0)
982 	return error;
983 
984     if (args->status) {
985 	if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
986 	    return error;
987 	if (WIFSIGNALED(tmpstat))
988 	    tmpstat = (tmpstat & 0xffffff80) |
989 		      bsd_to_linux_signal[WTERMSIG(tmpstat)];
990 	else if (WIFSTOPPED(tmpstat))
991 	    tmpstat = (tmpstat & 0xffff00ff) |
992 		      (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
993 	return copyout(&tmpstat, args->status, sizeof(int));
994     } else
995 	return 0;
996 }
997 
998 int
999 linux_wait4(struct proc *p, struct linux_wait4_args *args)
1000 {
1001     struct wait_args /* {
1002 	int pid;
1003 	int *status;
1004 	int options;
1005 	struct	rusage *rusage;
1006     } */ tmp;
1007     int error, tmpstat;
1008 
1009 #ifdef DEBUG
1010     printf("Linux-emul(%ld): wait4(%d, %p, %d, %p)\n",
1011 	(long)p->p_pid, args->pid, (void *)args->status, args->options,
1012 	(void *)args->rusage);
1013 #endif
1014     tmp.pid = args->pid;
1015     tmp.status = args->status;
1016     tmp.options = (args->options & (WNOHANG | WUNTRACED));
1017     /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
1018     if (args->options & __WCLONE)
1019 	tmp.options |= WLINUXCLONE;
1020     tmp.rusage = args->rusage;
1021 
1022     if ((error = wait4(p, &tmp)) != 0)
1023 	return error;
1024 
1025     p->p_siglist &= ~sigmask(SIGCHLD);
1026 
1027     if (args->status) {
1028 	if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
1029 	    return error;
1030 	if (WIFSIGNALED(tmpstat))
1031 	    tmpstat = (tmpstat & 0xffffff80) |
1032 		  bsd_to_linux_signal[WTERMSIG(tmpstat)];
1033 	else if (WIFSTOPPED(tmpstat))
1034 	    tmpstat = (tmpstat & 0xffff00ff) |
1035 		  (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
1036 	return copyout(&tmpstat, args->status, sizeof(int));
1037     } else
1038 	return 0;
1039 }
1040 
1041 int
1042 linux_mknod(struct proc *p, struct linux_mknod_args *args)
1043 {
1044 	caddr_t sg;
1045 	struct mknod_args bsd_mknod;
1046 	struct mkfifo_args bsd_mkfifo;
1047 
1048 	sg = stackgap_init();
1049 
1050 	CHECKALTCREAT(p, &sg, args->path);
1051 
1052 #ifdef DEBUG
1053 	printf("Linux-emul(%ld): mknod(%s, %d, %d)\n",
1054 	   (long)p->p_pid, args->path, args->mode, args->dev);
1055 #endif
1056 
1057 	if (args->mode & S_IFIFO) {
1058 		bsd_mkfifo.path = args->path;
1059 		bsd_mkfifo.mode = args->mode;
1060 		return mkfifo(p, &bsd_mkfifo);
1061 	} else {
1062 		bsd_mknod.path = args->path;
1063 		bsd_mknod.mode = args->mode;
1064 		bsd_mknod.dev = args->dev;
1065 		return mknod(p, &bsd_mknod);
1066 	}
1067 }
1068 
1069 /*
1070  * UGH! This is just about the dumbest idea I've ever heard!!
1071  */
1072 int
1073 linux_personality(struct proc *p, struct linux_personality_args *args)
1074 {
1075 #ifdef DEBUG
1076 	printf("Linux-emul(%ld): personality(%d)\n",
1077 	   (long)p->p_pid, args->per);
1078 #endif
1079 	if (args->per != 0)
1080 		return EINVAL;
1081 
1082 	/* Yes Jim, it's still a Linux... */
1083 	p->p_retval[0] = 0;
1084 	return 0;
1085 }
1086 
1087 /*
1088  * Wrappers for get/setitimer for debugging..
1089  */
1090 int
1091 linux_setitimer(struct proc *p, struct linux_setitimer_args *args)
1092 {
1093 	struct setitimer_args bsa;
1094 	struct itimerval foo;
1095 	int error;
1096 
1097 #ifdef DEBUG
1098 	printf("Linux-emul(%ld): setitimer(%p, %p)\n",
1099 	    (long)p->p_pid, (void *)args->itv, (void *)args->oitv);
1100 #endif
1101 	bsa.which = args->which;
1102 	bsa.itv = args->itv;
1103 	bsa.oitv = args->oitv;
1104 	if (args->itv) {
1105 	    if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo,
1106 			sizeof(foo))))
1107 		return error;
1108 #ifdef DEBUG
1109 	    printf("setitimer: value: sec: %ld, usec: %ld\n",
1110 		foo.it_value.tv_sec, foo.it_value.tv_usec);
1111 	    printf("setitimer: interval: sec: %ld, usec: %ld\n",
1112 		foo.it_interval.tv_sec, foo.it_interval.tv_usec);
1113 #endif
1114 	}
1115 	return setitimer(p, &bsa);
1116 }
1117 
1118 int
1119 linux_getitimer(struct proc *p, struct linux_getitimer_args *args)
1120 {
1121 	struct getitimer_args bsa;
1122 #ifdef DEBUG
1123 	printf("Linux-emul(%ld): getitimer(%p)\n",
1124 	    (long)p->p_pid, (void *)args->itv);
1125 #endif
1126 	bsa.which = args->which;
1127 	bsa.itv = args->itv;
1128 	return getitimer(p, &bsa);
1129 }
1130 
1131 int
1132 linux_iopl(struct proc *p, struct linux_iopl_args *args)
1133 {
1134 	int error;
1135 
1136 	error = suser(p);
1137 	if (error != 0)
1138 		return error;
1139 	if (securelevel > 0)
1140 		return EPERM;
1141 	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1142 	return 0;
1143 }
1144 
1145 int
1146 linux_nice(struct proc *p, struct linux_nice_args *args)
1147 {
1148 	struct setpriority_args	bsd_args;
1149 
1150 	bsd_args.which = PRIO_PROCESS;
1151 	bsd_args.who = 0;	/* current process */
1152 	bsd_args.prio = args->inc;
1153 	return setpriority(p, &bsd_args);
1154 }
1155 
1156 int
1157 linux_setgroups(p, uap)
1158      struct proc *p;
1159      struct linux_setgroups_args *uap;
1160 {
1161   struct pcred *pc = p->p_cred;
1162   linux_gid_t linux_gidset[NGROUPS];
1163   gid_t *bsd_gidset;
1164   int ngrp, error;
1165 
1166   if ((error = suser(p)))
1167     return error;
1168 
1169   if (uap->gidsetsize > NGROUPS)
1170     return EINVAL;
1171 
1172   ngrp = uap->gidsetsize;
1173   pc->pc_ucred = crcopy(pc->pc_ucred);
1174   if (ngrp >= 1) {
1175     if ((error = copyin((caddr_t)uap->gidset,
1176                       (caddr_t)linux_gidset,
1177                         ngrp * sizeof(linux_gid_t))))
1178       return error;
1179 
1180     pc->pc_ucred->cr_ngroups = ngrp;
1181 
1182     bsd_gidset = pc->pc_ucred->cr_groups;
1183     ngrp--;
1184     while (ngrp >= 0) {
1185       bsd_gidset[ngrp] = linux_gidset[ngrp];
1186       ngrp--;
1187     }
1188   }
1189   else
1190     pc->pc_ucred->cr_ngroups = 1;
1191 
1192   setsugid(p);
1193   return 0;
1194 }
1195 
1196 int
1197 linux_getgroups(p, uap)
1198      struct proc *p;
1199      struct linux_getgroups_args *uap;
1200 {
1201   struct pcred *pc = p->p_cred;
1202   linux_gid_t linux_gidset[NGROUPS];
1203   gid_t *bsd_gidset;
1204   int ngrp, error;
1205 
1206   if ((ngrp = uap->gidsetsize) == 0) {
1207     p->p_retval[0] = pc->pc_ucred->cr_ngroups;
1208     return 0;
1209   }
1210 
1211   if (ngrp < pc->pc_ucred->cr_ngroups)
1212     return EINVAL;
1213 
1214   ngrp = 0;
1215   bsd_gidset = pc->pc_ucred->cr_groups;
1216   while (ngrp < pc->pc_ucred->cr_ngroups) {
1217     linux_gidset[ngrp] = bsd_gidset[ngrp];
1218     ngrp++;
1219   }
1220 
1221   if ((error = copyout((caddr_t)linux_gidset, (caddr_t)uap->gidset,
1222                        ngrp * sizeof(linux_gid_t))))
1223     return error;
1224 
1225   p->p_retval[0] = ngrp;
1226   return (0);
1227 }
1228 
1229 int
1230 linux_setrlimit(p, uap)
1231      struct proc *p;
1232      struct linux_setrlimit_args *uap;
1233 {
1234     struct osetrlimit_args bsd;
1235 
1236 #ifdef DEBUG
1237     printf("Linux-emul(%ld): setrlimit(%d, %p)\n",
1238 	   (long)p->p_pid, uap->resource, (void *)uap->rlim);
1239 #endif
1240 
1241     if (uap->resource >= LINUX_RLIM_NLIMITS)
1242 	return EINVAL;
1243 
1244     bsd.which = linux_to_bsd_resource[uap->resource];
1245 
1246     if (bsd.which == -1)
1247 	return EINVAL;
1248 
1249     bsd.rlp = uap->rlim;
1250     return osetrlimit(p, &bsd);
1251 }
1252 
1253 int
1254 linux_getrlimit(p, uap)
1255      struct proc *p;
1256      struct linux_getrlimit_args *uap;
1257 {
1258     struct ogetrlimit_args bsd;
1259 
1260 #ifdef DEBUG
1261     printf("Linux-emul(%ld): getrlimit(%d, %p)\n",
1262 	   (long)p->p_pid, uap->resource, (void *)uap->rlim);
1263 #endif
1264 
1265     if (uap->resource >= LINUX_RLIM_NLIMITS)
1266 	return EINVAL;
1267 
1268     bsd.which = linux_to_bsd_resource[uap->resource];
1269 
1270     if (bsd.which == -1)
1271 	return EINVAL;
1272 
1273     bsd.rlp = uap->rlim;
1274     return ogetrlimit(p, &bsd);
1275 }
1276 
1277 int
1278 linux_sched_setscheduler(p, uap)
1279 	struct proc *p;
1280 	struct linux_sched_setscheduler_args *uap;
1281 {
1282 	struct sched_setscheduler_args bsd;
1283 
1284 #ifdef DEBUG
1285 	printf("Linux-emul(%ld): sched_setscheduler(%d, %d, %p)\n",
1286 	       (long)p->p_pid, uap->pid, uap->policy, (void *)uap->param);
1287 #endif
1288 
1289 	switch (uap->policy) {
1290 	case LINUX_SCHED_OTHER:
1291 		bsd.policy = SCHED_OTHER;
1292 		break;
1293 	case LINUX_SCHED_FIFO:
1294 		bsd.policy = SCHED_FIFO;
1295 		break;
1296 	case LINUX_SCHED_RR:
1297 		bsd.policy = SCHED_RR;
1298 		break;
1299 	default:
1300 		return EINVAL;
1301 	}
1302 
1303 	bsd.pid = uap->pid;
1304 	bsd.param = uap->param;
1305 	return sched_setscheduler(p, &bsd);
1306 }
1307 
1308 int
1309 linux_sched_getscheduler(p, uap)
1310 	struct proc *p;
1311 	struct linux_sched_getscheduler_args *uap;
1312 {
1313 	struct sched_getscheduler_args bsd;
1314 	int error;
1315 
1316 #ifdef DEBUG
1317 	printf("Linux-emul(%ld): sched_getscheduler(%d)\n",
1318 	       (long)p->p_pid, uap->pid);
1319 #endif
1320 
1321 	bsd.pid = uap->pid;
1322 	error = sched_getscheduler(p, &bsd);
1323 
1324 	switch (p->p_retval[0]) {
1325 	case SCHED_OTHER:
1326 		p->p_retval[0] = LINUX_SCHED_OTHER;
1327 		break;
1328 	case SCHED_FIFO:
1329 		p->p_retval[0] = LINUX_SCHED_FIFO;
1330 		break;
1331 	case SCHED_RR:
1332 		p->p_retval[0] = LINUX_SCHED_RR;
1333 		break;
1334 	}
1335 
1336 	return error;
1337 }
1338