xref: /freebsd-14.2/sys/compat/linux/linux_misc.c (revision abbcaa0a)
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.46 1998/12/04 22:54:50 archie Exp $
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/kernel.h>
35 #include <sys/mman.h>
36 #include <sys/proc.h>
37 #include <sys/fcntl.h>
38 #include <sys/imgact_aout.h>
39 #include <sys/mount.h>
40 #include <sys/namei.h>
41 #include <sys/resourcevar.h>
42 #include <sys/stat.h>
43 #include <sys/sysctl.h>
44 #include <sys/vnode.h>
45 #include <sys/wait.h>
46 #include <sys/time.h>
47 
48 #include <vm/vm.h>
49 #include <vm/pmap.h>
50 #include <vm/vm_kern.h>
51 #include <vm/vm_prot.h>
52 #include <vm/vm_map.h>
53 #include <vm/vm_extern.h>
54 
55 #include <machine/frame.h>
56 #include <machine/psl.h>
57 
58 #include <i386/linux/linux.h>
59 #include <i386/linux/linux_proto.h>
60 #include <i386/linux/linux_util.h>
61 
62 int
63 linux_alarm(struct proc *p, struct linux_alarm_args *args)
64 {
65     struct itimerval it, old_it;
66     struct timeval tv;
67     int s;
68 
69 #ifdef DEBUG
70     printf("Linux-emul(%ld): alarm(%u)\n", (long)p->p_pid, args->secs);
71 #endif
72     if (args->secs > 100000000)
73 	return EINVAL;
74     it.it_value.tv_sec = (long)args->secs;
75     it.it_value.tv_usec = 0;
76     it.it_interval.tv_sec = 0;
77     it.it_interval.tv_usec = 0;
78     s = splsoftclock();
79     old_it = p->p_realtimer;
80     getmicrouptime(&tv);
81     if (timevalisset(&old_it.it_value))
82 	untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
83     if (it.it_value.tv_sec != 0) {
84 	p->p_ithandle = timeout(realitexpire, (caddr_t)p, tvtohz(&it.it_value));
85 	timevaladd(&it.it_value, &tv);
86     }
87     p->p_realtimer = it;
88     splx(s);
89     if (timevalcmp(&old_it.it_value, &tv, >)) {
90 	timevalsub(&old_it.it_value, &tv);
91 	if (old_it.it_value.tv_usec != 0)
92 	    old_it.it_value.tv_sec++;
93 	p->p_retval[0] = old_it.it_value.tv_sec;
94     }
95     return 0;
96 }
97 
98 int
99 linux_brk(struct proc *p, struct linux_brk_args *args)
100 {
101 #if 0
102     struct vmspace *vm = p->p_vmspace;
103     vm_offset_t new, old;
104     int error;
105 
106     if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
107 	return EINVAL;
108     if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
109 	> p->p_rlimit[RLIMIT_DATA].rlim_cur)
110 	return ENOMEM;
111 
112     old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
113     new = round_page((vm_offset_t)args->dsend);
114     p->p_retval[0] = old;
115     if ((new-old) > 0) {
116 	if (swap_pager_full)
117 	    return ENOMEM;
118 	error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE,
119 			VM_PROT_ALL, VM_PROT_ALL, 0);
120 	if (error)
121 	    return error;
122 	vm->vm_dsize += btoc((new-old));
123 	p->p_retval[0] = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
124     }
125     return 0;
126 #else
127     struct vmspace *vm = p->p_vmspace;
128     vm_offset_t new, old;
129     struct obreak_args /* {
130 	char * nsize;
131     } */ tmp;
132 
133 #ifdef DEBUG
134     printf("Linux-emul(%ld): brk(%p)\n", (long)p->p_pid, (void *)args->dsend);
135 #endif
136     old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
137     new = (vm_offset_t)args->dsend;
138     tmp.nsize = (char *) new;
139     if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp))
140 	p->p_retval[0] = (int)new;
141     else
142 	p->p_retval[0] = (int)old;
143 
144     return 0;
145 #endif
146 }
147 
148 int
149 linux_uselib(struct proc *p, struct linux_uselib_args *args)
150 {
151     struct nameidata ni;
152     struct vnode *vp;
153     struct exec *a_out;
154     struct vattr attr;
155     vm_offset_t vmaddr;
156     unsigned long file_offset;
157     vm_offset_t buffer;
158     unsigned long bss_size;
159     int error;
160     caddr_t sg;
161     int locked;
162 
163     sg = stackgap_init();
164     CHECKALTEXIST(p, &sg, args->library);
165 
166 #ifdef DEBUG
167     printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library);
168 #endif
169 
170     a_out = NULL;
171     locked = 0;
172     vp = NULL;
173 
174     NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, args->library, p);
175     if (error = namei(&ni))
176 	goto cleanup;
177 
178     vp = ni.ni_vp;
179     if (vp == NULL) {
180 	error = ENOEXEC;	/* ?? */
181 	goto cleanup;
182     }
183 
184     /*
185      * From here on down, we have a locked vnode that must be unlocked.
186      */
187     locked++;
188 
189     /*
190      * Writable?
191      */
192     if (vp->v_writecount) {
193 	error = ETXTBSY;
194 	goto cleanup;
195     }
196 
197     /*
198      * Executable?
199      */
200     if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p))
201 	goto cleanup;
202 
203     if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
204 	((attr.va_mode & 0111) == 0) ||
205 	(attr.va_type != VREG)) {
206 	    error = ENOEXEC;
207 	    goto cleanup;
208     }
209 
210     /*
211      * Sensible size?
212      */
213     if (attr.va_size == 0) {
214 	error = ENOEXEC;
215 	goto cleanup;
216     }
217 
218     /*
219      * Can we access it?
220      */
221     if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))
222 	goto cleanup;
223 
224     if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p))
225 	goto cleanup;
226 
227     /*
228      * Lock no longer needed
229      */
230     VOP_UNLOCK(vp, 0, p);
231     locked = 0;
232 
233     /*
234      * Pull in executable header into kernel_map
235      */
236     error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
237 	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
238     if (error)
239 	goto cleanup;
240 
241     /*
242      * Is it a Linux binary ?
243      */
244     if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
245 	error = ENOEXEC;
246 	goto cleanup;
247     }
248 
249     /* While we are here, we should REALLY do some more checks */
250 
251     /*
252      * Set file/virtual offset based on a.out variant.
253      */
254     switch ((int)(a_out->a_magic & 0xffff)) {
255     case 0413:	/* ZMAGIC */
256 	file_offset = 1024;
257 	break;
258     case 0314:	/* QMAGIC */
259 	file_offset = 0;
260 	break;
261     default:
262 	error = ENOEXEC;
263 	goto cleanup;
264     }
265 
266     bss_size = round_page(a_out->a_bss);
267 
268     /*
269      * Check various fields in header for validity/bounds.
270      */
271     if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
272 	error = ENOEXEC;
273 	goto cleanup;
274     }
275 
276     /* text + data can't exceed file size */
277     if (a_out->a_data + a_out->a_text > attr.va_size) {
278 	error = EFAULT;
279 	goto cleanup;
280     }
281 
282     /*
283      * text/data/bss must not exceed limits
284      * XXX: this is not complete. it should check current usage PLUS
285      * the resources needed by this library.
286      */
287     if (a_out->a_text > MAXTSIZ ||
288 	a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
289 	error = ENOMEM;
290 	goto cleanup;
291     }
292 
293     /*
294      * prevent more writers
295      */
296     vp->v_flag |= VTEXT;
297 
298     /*
299      * Check if file_offset page aligned,.
300      * Currently we cannot handle misalinged file offsets,
301      * and so we read in the entire image (what a waste).
302      */
303     if (file_offset & PAGE_MASK) {
304 #ifdef DEBUG
305 printf("uselib: Non page aligned binary %lu\n", file_offset);
306 #endif
307 	/*
308 	 * Map text+data read/write/execute
309 	 */
310 
311 	/* a_entry is the load address and is page aligned */
312 	vmaddr = trunc_page(a_out->a_entry);
313 
314 	/* get anon user mapping, read+write+execute */
315 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
316 		    	    a_out->a_text + a_out->a_data, FALSE,
317 			    VM_PROT_ALL, VM_PROT_ALL, 0);
318 	if (error)
319 	    goto cleanup;
320 
321 	/* map file into kernel_map */
322 	error = vm_mmap(kernel_map, &buffer,
323 			round_page(a_out->a_text + a_out->a_data + file_offset),
324 		   	VM_PROT_READ, VM_PROT_READ, 0,
325 			(caddr_t)vp, trunc_page(file_offset));
326 	if (error)
327 	    goto cleanup;
328 
329 	/* copy from kernel VM space to user space */
330 	error = copyout((caddr_t)(void *)(uintptr_t)(buffer + file_offset),
331 			(caddr_t)vmaddr, a_out->a_text + a_out->a_data);
332 
333 	/* release temporary kernel space */
334 	vm_map_remove(kernel_map, buffer,
335 		      buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
336 
337 	if (error)
338 	    goto cleanup;
339     }
340     else {
341 #ifdef DEBUG
342 printf("uselib: Page aligned binary %lu\n", file_offset);
343 #endif
344 	/*
345 	 * for QMAGIC, a_entry is 20 bytes beyond the load address
346 	 * to skip the executable header
347 	 */
348 	vmaddr = trunc_page(a_out->a_entry);
349 
350 	/*
351 	 * Map it all into the process's space as a single copy-on-write
352 	 * "data" segment.
353 	 */
354 	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
355 		   	a_out->a_text + a_out->a_data,
356 			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
357 			(caddr_t)vp, file_offset);
358 	if (error)
359 	    goto cleanup;
360     }
361 #ifdef DEBUG
362 printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
363 #endif
364     if (bss_size != 0) {
365         /*
366 	 * Calculate BSS start address
367 	 */
368 	vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data;
369 
370 	/*
371 	 * allocate some 'anon' space
372 	 */
373 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
374 			    bss_size, FALSE,
375 			    VM_PROT_ALL, VM_PROT_ALL, 0);
376 	if (error)
377 	    goto cleanup;
378     }
379 
380 cleanup:
381     /*
382      * Unlock vnode if needed
383      */
384     if (locked)
385 	VOP_UNLOCK(vp, 0, p);
386 
387     /*
388      * Release the kernel mapping.
389      */
390     if (a_out)
391 	vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE);
392 
393     return error;
394 }
395 
396 /* XXX move */
397 struct linux_select_argv {
398 	int nfds;
399 	fd_set *readfds;
400 	fd_set *writefds;
401 	fd_set *exceptfds;
402 	struct timeval *timeout;
403 };
404 
405 int
406 linux_select(struct proc *p, struct linux_select_args *args)
407 {
408     struct linux_select_argv linux_args;
409     struct linux_newselect_args newsel;
410     int error;
411 
412 #ifdef SELECT_DEBUG
413     printf("Linux-emul(%d): select(%x)\n",
414 	   p->p_pid, args->ptr);
415 #endif
416     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
417 			sizeof(linux_args))))
418 	return error;
419 
420     newsel.nfds = linux_args.nfds;
421     newsel.readfds = linux_args.readfds;
422     newsel.writefds = linux_args.writefds;
423     newsel.exceptfds = linux_args.exceptfds;
424     newsel.timeout = linux_args.timeout;
425 
426     return linux_newselect(p, &newsel);
427 }
428 
429 int
430 linux_newselect(struct proc *p, struct linux_newselect_args *args)
431 {
432     struct select_args bsa;
433     struct timeval tv0, tv1, utv, *tvp;
434     caddr_t sg;
435     int error;
436 
437 #ifdef DEBUG
438     printf("Linux-emul(%ld): newselect(%d, %p, %p, %p, %p)\n",
439   	(long)p->p_pid, args->nfds, (void *)args->readfds,
440 	(void *)args->writefds, (void *)args->exceptfds,
441 	(void *)args->timeout);
442 #endif
443     error = 0;
444     bsa.nd = args->nfds;
445     bsa.in = args->readfds;
446     bsa.ou = args->writefds;
447     bsa.ex = args->exceptfds;
448     bsa.tv = args->timeout;
449 
450     /*
451      * Store current time for computation of the amount of
452      * time left.
453      */
454     if (args->timeout) {
455 	if ((error = copyin(args->timeout, &utv, sizeof(utv))))
456 	    goto select_out;
457 #ifdef DEBUG
458 	printf("Linux-emul(%ld): incoming timeout (%ld/%ld)\n",
459 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
460 #endif
461 	if (itimerfix(&utv)) {
462 	    /*
463 	     * The timeval was invalid.  Convert it to something
464 	     * valid that will act as it does under Linux.
465 	     */
466 	    sg = stackgap_init();
467 	    tvp = stackgap_alloc(&sg, sizeof(utv));
468 	    utv.tv_sec += utv.tv_usec / 1000000;
469 	    utv.tv_usec %= 1000000;
470 	    if (utv.tv_usec < 0) {
471 		utv.tv_sec -= 1;
472 		utv.tv_usec += 1000000;
473 	    }
474 	    if (utv.tv_sec < 0)
475 		timevalclear(&utv);
476 	    if ((error = copyout(&utv, tvp, sizeof(utv))))
477 		goto select_out;
478 	    bsa.tv = tvp;
479 	}
480 	microtime(&tv0);
481     }
482 
483     error = select(p, &bsa);
484 #ifdef DEBUG
485     printf("Linux-emul(%d): real select returns %d\n",
486 	       p->p_pid, error);
487 #endif
488 
489     if (error) {
490 	/*
491 	 * See fs/select.c in the Linux kernel.  Without this,
492 	 * Maelstrom doesn't work.
493 	 */
494 	if (error == ERESTART)
495 	    error = EINTR;
496 	goto select_out;
497     }
498 
499     if (args->timeout) {
500 	if (p->p_retval[0]) {
501 	    /*
502 	     * Compute how much time was left of the timeout,
503 	     * by subtracting the current time and the time
504 	     * before we started the call, and subtracting
505 	     * that result from the user-supplied value.
506 	     */
507 	    microtime(&tv1);
508 	    timevalsub(&tv1, &tv0);
509 	    timevalsub(&utv, &tv1);
510 	    if (utv.tv_sec < 0)
511 		timevalclear(&utv);
512 	} else
513 	    timevalclear(&utv);
514 #ifdef DEBUG
515 	printf("Linux-emul(%ld): outgoing timeout (%ld/%ld)\n",
516 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
517 #endif
518 	if ((error = copyout(&utv, args->timeout, sizeof(utv))))
519 	    goto select_out;
520     }
521 
522 select_out:
523 #ifdef DEBUG
524     printf("Linux-emul(%d): newselect_out -> %d\n",
525 	       p->p_pid, error);
526 #endif
527     return error;
528 }
529 
530 int
531 linux_getpgid(struct proc *p, struct linux_getpgid_args *args)
532 {
533     struct proc *curproc;
534 
535 #ifdef DEBUG
536     printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid);
537 #endif
538     if (args->pid != p->p_pid) {
539 	if (!(curproc = pfind(args->pid)))
540 	    return ESRCH;
541     }
542     else
543 	curproc = p;
544     p->p_retval[0] = curproc->p_pgid;
545     return 0;
546 }
547 
548 int
549 linux_fork(struct proc *p, struct linux_fork_args *args)
550 {
551     int error;
552 
553 #ifdef DEBUG
554     printf("Linux-emul(%d): fork()\n", p->p_pid);
555 #endif
556     if (error = fork(p, (struct fork_args *)args))
557 	return error;
558     if (p->p_retval[1] == 1)
559 	p->p_retval[0] = 0;
560     return 0;
561 }
562 
563 /* XXX move */
564 struct linux_mmap_argv {
565 	linux_caddr_t addr;
566 	int len;
567 	int prot;
568 	int flags;
569 	int fd;
570 	int pos;
571 };
572 
573 int
574 linux_mmap(struct proc *p, struct linux_mmap_args *args)
575 {
576     struct mmap_args /* {
577 	caddr_t addr;
578 	size_t len;
579 	int prot;
580 	int flags;
581 	int fd;
582 	long pad;
583 	off_t pos;
584     } */ bsd_args;
585     int error;
586     struct linux_mmap_argv linux_args;
587 
588     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
589 			sizeof(linux_args))))
590 	return error;
591 #ifdef DEBUG
592     printf("Linux-emul(%ld): mmap(%p, %d, %d, %08x, %d, %d)\n",
593 	(long)p->p_pid, (void *)linux_args.addr, linux_args.len,
594 	linux_args.prot, linux_args.flags, linux_args.fd, linux_args.pos);
595 #endif
596     bsd_args.flags = 0;
597     if (linux_args.flags & LINUX_MAP_SHARED)
598 	bsd_args.flags |= MAP_SHARED;
599     if (linux_args.flags & LINUX_MAP_PRIVATE)
600 	bsd_args.flags |= MAP_PRIVATE;
601     if (linux_args.flags & LINUX_MAP_FIXED)
602 	bsd_args.flags |= MAP_FIXED;
603     if (linux_args.flags & LINUX_MAP_ANON)
604 	bsd_args.flags |= MAP_ANON;
605     bsd_args.addr = linux_args.addr;
606     bsd_args.len = linux_args.len;
607     bsd_args.prot = linux_args.prot | PROT_READ;	/* always required */
608     bsd_args.fd = linux_args.fd;
609     bsd_args.pos = linux_args.pos;
610     bsd_args.pad = 0;
611     return mmap(p, &bsd_args);
612 }
613 
614 int
615 linux_mremap(struct proc *p, struct linux_mremap_args *args)
616 {
617 	struct munmap_args /* {
618 		void *addr;
619 		size_t len;
620 	} */ bsd_args;
621 	int error = 0;
622 
623 #ifdef DEBUG
624 	printf("Linux-emul(%ld): mremap(%p, %08x, %08x, %08x)\n",
625 	    (long)p->p_pid, (void *)args->addr, args->old_len, args->new_len,
626 	    args->flags);
627 #endif
628 	args->new_len = round_page(args->new_len);
629 	args->old_len = round_page(args->old_len);
630 
631 	if (args->new_len > args->old_len) {
632 		p->p_retval[0] = 0;
633 		return ENOMEM;
634 	}
635 
636 	if (args->new_len < args->old_len) {
637 		bsd_args.addr = args->addr + args->new_len;
638 		bsd_args.len = args->old_len - args->new_len;
639 		error = munmap(p, &bsd_args);
640 	}
641 
642 	p->p_retval[0] = error ? 0 : (int)args->addr;
643 	return error;
644 }
645 
646 int
647 linux_msync(struct proc *p, struct linux_msync_args *args)
648 {
649 	struct msync_args bsd_args;
650 
651 	bsd_args.addr = args->addr;
652 	bsd_args.len = args->len;
653 	bsd_args.flags = 0;	/* XXX ignore */
654 
655 	return msync(p, &bsd_args);
656 }
657 
658 int
659 linux_pipe(struct proc *p, struct linux_pipe_args *args)
660 {
661     int error;
662     int reg_edx;
663 
664 #ifdef DEBUG
665     printf("Linux-emul(%d): pipe(*)\n", p->p_pid);
666 #endif
667     reg_edx = p->p_retval[1];
668     if (error = pipe(p, 0)) {
669 	p->p_retval[1] = reg_edx;
670 	return error;
671     }
672 
673     if (error = copyout(p->p_retval, args->pipefds, 2*sizeof(int))) {
674 	p->p_retval[1] = reg_edx;
675 	return error;
676     }
677 
678     p->p_retval[1] = reg_edx;
679     p->p_retval[0] = 0;
680     return 0;
681 }
682 
683 int
684 linux_time(struct proc *p, struct linux_time_args *args)
685 {
686     struct timeval tv;
687     linux_time_t tm;
688     int error;
689 
690 #ifdef DEBUG
691     printf("Linux-emul(%d): time(*)\n", p->p_pid);
692 #endif
693     microtime(&tv);
694     tm = tv.tv_sec;
695     if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t))))
696 	return error;
697     p->p_retval[0] = tm;
698     return 0;
699 }
700 
701 struct linux_times_argv {
702     long    tms_utime;
703     long    tms_stime;
704     long    tms_cutime;
705     long    tms_cstime;
706 };
707 
708 #define CLK_TCK 100	/* Linux uses 100 */
709 #define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
710 
711 int
712 linux_times(struct proc *p, struct linux_times_args *args)
713 {
714     struct timeval tv;
715     struct linux_times_argv tms;
716     struct rusage ru;
717     int error;
718 
719 #ifdef DEBUG
720     printf("Linux-emul(%d): times(*)\n", p->p_pid);
721 #endif
722     calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
723 
724     tms.tms_utime = CONVTCK(ru.ru_utime);
725     tms.tms_stime = CONVTCK(ru.ru_stime);
726 
727     tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
728     tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
729 
730     if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf,
731 	    	    sizeof(struct linux_times_argv))))
732 	return error;
733 
734     microuptime(&tv);
735     p->p_retval[0] = (int)CONVTCK(tv);
736     return 0;
737 }
738 
739 /* XXX move */
740 struct linux_newuname_t {
741     char sysname[65];
742     char nodename[65];
743     char release[65];
744     char version[65];
745     char machine[65];
746     char domainname[65];
747 };
748 
749 int
750 linux_newuname(struct proc *p, struct linux_newuname_args *args)
751 {
752     struct linux_newuname_t linux_newuname;
753 
754 #ifdef DEBUG
755     printf("Linux-emul(%d): newuname(*)\n", p->p_pid);
756 #endif
757     bzero(&linux_newuname, sizeof(struct linux_newuname_t));
758     strncpy(linux_newuname.sysname, ostype,
759 	sizeof(linux_newuname.sysname) - 1);
760     strncpy(linux_newuname.nodename, hostname,
761 	sizeof(linux_newuname.nodename) - 1);
762     strncpy(linux_newuname.release, osrelease,
763 	sizeof(linux_newuname.release) - 1);
764     strncpy(linux_newuname.version, version,
765 	sizeof(linux_newuname.version) - 1);
766     strncpy(linux_newuname.machine, machine,
767 	sizeof(linux_newuname.machine) - 1);
768     strncpy(linux_newuname.domainname, domainname,
769 	sizeof(linux_newuname.domainname) - 1);
770     return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf,
771 	    	    sizeof(struct linux_newuname_t)));
772 }
773 
774 struct linux_utimbuf {
775 	linux_time_t l_actime;
776 	linux_time_t l_modtime;
777 };
778 
779 int
780 linux_utime(struct proc *p, struct linux_utime_args *args)
781 {
782     struct utimes_args /* {
783 	char	*path;
784 	struct	timeval *tptr;
785     } */ bsdutimes;
786     struct timeval tv[2], *tvp;
787     struct linux_utimbuf lut;
788     int error;
789     caddr_t sg;
790 
791     sg = stackgap_init();
792     CHECKALTEXIST(p, &sg, args->fname);
793 
794 #ifdef DEBUG
795     printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname);
796 #endif
797     if (args->times) {
798 	if ((error = copyin(args->times, &lut, sizeof lut)))
799 	    return error;
800 	tv[0].tv_sec = lut.l_actime;
801 	tv[0].tv_usec = 0;
802 	tv[1].tv_sec = lut.l_modtime;
803 	tv[1].tv_usec = 0;
804 	/* so that utimes can copyin */
805 	tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv));
806 	if ((error = copyout(tv, tvp, sizeof(tv))))
807 	    return error;
808 	bsdutimes.tptr = tvp;
809     } else
810 	bsdutimes.tptr = NULL;
811 
812     bsdutimes.path = args->fname;
813     return utimes(p, &bsdutimes);
814 }
815 
816 int
817 linux_waitpid(struct proc *p, struct linux_waitpid_args *args)
818 {
819     struct wait_args /* {
820 	int pid;
821 	int *status;
822 	int options;
823 	struct	rusage *rusage;
824     } */ tmp;
825     int error, tmpstat;
826 
827 #ifdef DEBUG
828     printf("Linux-emul(%ld): waitpid(%d, %p, %d)\n",
829 	(long)p->p_pid, args->pid, (void *)args->status, args->options);
830 #endif
831     tmp.pid = args->pid;
832     tmp.status = args->status;
833     tmp.options = args->options;
834     tmp.rusage = NULL;
835 
836     if (error = wait4(p, &tmp))
837 	return error;
838     if (args->status) {
839 	if (error = copyin(args->status, &tmpstat, sizeof(int)))
840 	    return error;
841 	if (WIFSIGNALED(tmpstat))
842 	    tmpstat = (tmpstat & 0xffffff80) |
843 		      bsd_to_linux_signal[WTERMSIG(tmpstat)];
844 	else if (WIFSTOPPED(tmpstat))
845 	    tmpstat = (tmpstat & 0xffff00ff) |
846 		      (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
847 	return copyout(&tmpstat, args->status, sizeof(int));
848     } else
849 	return 0;
850 }
851 
852 int
853 linux_wait4(struct proc *p, struct linux_wait4_args *args)
854 {
855     struct wait_args /* {
856 	int pid;
857 	int *status;
858 	int options;
859 	struct	rusage *rusage;
860     } */ tmp;
861     int error, tmpstat;
862 
863 #ifdef DEBUG
864     printf("Linux-emul(%ld): wait4(%d, %p, %d, %p)\n",
865 	(long)p->p_pid, args->pid, (void *)args->status, args->options,
866 	(void *)args->rusage);
867 #endif
868     tmp.pid = args->pid;
869     tmp.status = args->status;
870     tmp.options = args->options;
871     tmp.rusage = args->rusage;
872 
873     if (error = wait4(p, &tmp))
874 	return error;
875 
876     p->p_siglist &= ~sigmask(SIGCHLD);
877 
878     if (args->status) {
879 	if (error = copyin(args->status, &tmpstat, sizeof(int)))
880 	    return error;
881 	if (WIFSIGNALED(tmpstat))
882 	    tmpstat = (tmpstat & 0xffffff80) |
883 		  bsd_to_linux_signal[WTERMSIG(tmpstat)];
884 	else if (WIFSTOPPED(tmpstat))
885 	    tmpstat = (tmpstat & 0xffff00ff) |
886 		  (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
887 	return copyout(&tmpstat, args->status, sizeof(int));
888     } else
889 	return 0;
890 }
891 
892 int
893 linux_mknod(struct proc *p, struct linux_mknod_args *args)
894 {
895 	caddr_t sg;
896 	struct mknod_args bsd_mknod;
897 	struct mkfifo_args bsd_mkfifo;
898 
899 	sg = stackgap_init();
900 
901 	CHECKALTCREAT(p, &sg, args->path);
902 
903 #ifdef DEBUG
904 	printf("Linux-emul(%d): mknod(%s, %d, %d)\n",
905 	   p->p_pid, args->path, args->mode, args->dev);
906 #endif
907 
908 	if (args->mode & S_IFIFO) {
909 		bsd_mkfifo.path = args->path;
910 		bsd_mkfifo.mode = args->mode;
911 		return mkfifo(p, &bsd_mkfifo);
912 	} else {
913 		bsd_mknod.path = args->path;
914 		bsd_mknod.mode = args->mode;
915 		bsd_mknod.dev = args->dev;
916 		return mknod(p, &bsd_mknod);
917 	}
918 }
919 
920 /*
921  * UGH! This is just about the dumbest idea I've ever heard!!
922  */
923 int
924 linux_personality(struct proc *p, struct linux_personality_args *args)
925 {
926 #ifdef DEBUG
927 	printf("Linux-emul(%d): personality(%d)\n",
928 	   p->p_pid, args->per);
929 #endif
930 	if (args->per != 0)
931 		return EINVAL;
932 
933 	/* Yes Jim, it's still a Linux... */
934 	p->p_retval[0] = 0;
935 	return 0;
936 }
937 
938 /*
939  * Wrappers for get/setitimer for debugging..
940  */
941 int
942 linux_setitimer(struct proc *p, struct linux_setitimer_args *args)
943 {
944 	struct setitimer_args bsa;
945 	struct itimerval foo;
946 	int error;
947 
948 #ifdef DEBUG
949 	printf("Linux-emul(%ld): setitimer(%p, %p)\n",
950 	    (long)p->p_pid, (void *)args->itv, (void *)args->oitv);
951 #endif
952 	bsa.which = args->which;
953 	bsa.itv = args->itv;
954 	bsa.oitv = args->oitv;
955 	if (args->itv) {
956 	    if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo,
957 			sizeof(foo))))
958 		return error;
959 #ifdef DEBUG
960 	    printf("setitimer: value: sec: %ld, usec: %ld\n",
961 		foo.it_value.tv_sec, foo.it_value.tv_usec);
962 	    printf("setitimer: interval: sec: %ld, usec: %ld\n",
963 		foo.it_interval.tv_sec, foo.it_interval.tv_usec);
964 #endif
965 	}
966 	return setitimer(p, &bsa);
967 }
968 
969 int
970 linux_getitimer(struct proc *p, struct linux_getitimer_args *args)
971 {
972 	struct getitimer_args bsa;
973 #ifdef DEBUG
974 	printf("Linux-emul(%ld): getitimer(%p)\n",
975 	    (long)p->p_pid, (void *)args->itv);
976 #endif
977 	bsa.which = args->which;
978 	bsa.itv = args->itv;
979 	return getitimer(p, &bsa);
980 }
981 
982 int
983 linux_iopl(struct proc *p, struct linux_iopl_args *args)
984 {
985 	int error;
986 
987 	error = suser(p->p_ucred, &p->p_acflag);
988 	if (error != 0)
989 		return error;
990 	if (securelevel > 0)
991 		return EPERM;
992 	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
993 	return 0;
994 }
995 
996 int
997 linux_nice(struct proc *p, struct linux_nice_args *args)
998 {
999 	struct setpriority_args	bsd_args;
1000 
1001 	bsd_args.which = PRIO_PROCESS;
1002 	bsd_args.who = 0;	/* current process */
1003 	bsd_args.prio = args->inc;
1004 	return setpriority(p, &bsd_args);
1005 }
1006 
1007