linux_misc.c revision 37950
157416Smarkm/*-
257416Smarkm * Copyright (c) 1994-1995 S�ren Schmidt
357416Smarkm * All rights reserved.
457416Smarkm *
557416Smarkm * Redistribution and use in source and binary forms, with or without
657416Smarkm * modification, are permitted provided that the following conditions
757416Smarkm * are met:
857416Smarkm * 1. Redistributions of source code must retain the above copyright
957416Smarkm *    notice, this list of conditions and the following disclaimer
1057416Smarkm *    in this position and unchanged.
1157416Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1257416Smarkm *    notice, this list of conditions and the following disclaimer in the
1357416Smarkm *    documentation and/or other materials provided with the distribution.
1457416Smarkm * 3. The name of the author may not be used to endorse or promote products
1557416Smarkm *    derived from this software withough specific prior written permission
1657416Smarkm *
1757416Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1857416Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1957416Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2057416Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2157416Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2257416Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2357416Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2457416Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2557416Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2657416Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2757416Smarkm *
2857416Smarkm *  $Id: linux_misc.c,v 1.39 1998/07/10 22:30:01 jkh Exp $
2957416Smarkm */
3057416Smarkm
3157416Smarkm#include <sys/param.h>
3257416Smarkm#include <sys/systm.h>
3357416Smarkm#include <sys/sysproto.h>
3457416Smarkm#include <sys/kernel.h>
3557416Smarkm#include <sys/mman.h>
36233294Sstas#include <sys/proc.h>
3757416Smarkm#include <sys/fcntl.h>
3857416Smarkm#include <sys/imgact_aout.h>
3957416Smarkm#include <sys/mount.h>
4057416Smarkm#include <sys/namei.h>
4157416Smarkm#include <sys/resourcevar.h>
4257416Smarkm#include <sys/stat.h>
4357416Smarkm#include <sys/sysctl.h>
4457416Smarkm#include <sys/vnode.h>
4557416Smarkm#include <sys/wait.h>
4657416Smarkm#include <sys/time.h>
4757416Smarkm
4857416Smarkm#include <vm/vm.h>
4957416Smarkm#include <vm/pmap.h>
5057416Smarkm#include <vm/vm_kern.h>
5157416Smarkm#include <vm/vm_prot.h>
5257416Smarkm#include <vm/vm_map.h>
5357416Smarkm#include <vm/vm_extern.h>
5457416Smarkm
5557416Smarkm#include <machine/frame.h>
5657416Smarkm#include <machine/psl.h>
5757416Smarkm
5857416Smarkm#include <i386/linux/linux.h>
5957416Smarkm#include <i386/linux/linux_proto.h>
60178825Sdfr#include <i386/linux/linux_util.h>
6157416Smarkm
6257416Smarkmint
6357416Smarkmlinux_alarm(struct proc *p, struct linux_alarm_args *args)
6457416Smarkm{
6557416Smarkm    struct itimerval it, old_it;
6657416Smarkm    struct timeval tv;
6757416Smarkm    int s;
6857416Smarkm
6957416Smarkm#ifdef DEBUG
7057416Smarkm    printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs);
7157416Smarkm#endif
7257416Smarkm    it.it_value.tv_sec = (long)args->secs;
7357416Smarkm    it.it_value.tv_usec = 0;
7457416Smarkm    it.it_interval.tv_sec = 0;
7557416Smarkm    it.it_interval.tv_usec = 0;
7657416Smarkm    s = splclock(); /* XXX Still needed ? */
7757416Smarkm    old_it = p->p_realtimer;
7857416Smarkm    getmicrotime(&tv);
7957416Smarkm    if (timevalisset(&old_it.it_value))
8057416Smarkm	if (timevalcmp(&old_it.it_value, &tv, <))
8172445Sassar	    timevalclear(&old_it.it_value);
8257416Smarkm	else
8357416Smarkm	    timevalsub(&old_it.it_value, &tv);
8457416Smarkm    splx(s);
8557416Smarkm    if (itimerfix(&it.it_value) || itimerfix(&it.it_interval))
8657416Smarkm	return EINVAL;
8757416Smarkm    s = splclock(); /* XXX Still needed ? */
8857416Smarkm    if (timevalisset(&p->p_realtimer.it_value))
8957416Smarkm	    untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
9057416Smarkm    getmicrotime(&tv);
9157416Smarkm    if (timevalisset(&it.it_value)) {
9257416Smarkm	timevaladd(&it.it_value, &tv);
9357416Smarkm	p->p_ithandle = timeout(realitexpire, (caddr_t)p, hzto(&it.it_value));
9457416Smarkm    }
9557416Smarkm    p->p_realtimer = it;
9657416Smarkm    splx(s);
9757416Smarkm    if (old_it.it_value.tv_usec)
9857416Smarkm	old_it.it_value.tv_sec++;
9957416Smarkm    p->p_retval[0] = old_it.it_value.tv_sec;
10057416Smarkm    return 0;
10157416Smarkm}
10257416Smarkm
10357416Smarkmint
10457416Smarkmlinux_brk(struct proc *p, struct linux_brk_args *args)
10557416Smarkm{
10657416Smarkm#if 0
10757416Smarkm    struct vmspace *vm = p->p_vmspace;
10857416Smarkm    vm_offset_t new, old;
10957416Smarkm    int error;
11057416Smarkm
11157416Smarkm    if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
11257416Smarkm	return EINVAL;
11357416Smarkm    if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
11457416Smarkm	> p->p_rlimit[RLIMIT_DATA].rlim_cur)
11557416Smarkm	return ENOMEM;
11657416Smarkm
11757416Smarkm    old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
118178825Sdfr    new = round_page((vm_offset_t)args->dsend);
11978527Sassar    p->p_retval[0] = old;
12057416Smarkm    if ((new-old) > 0) {
12178527Sassar	if (swap_pager_full)
12257416Smarkm	    return ENOMEM;
12357416Smarkm	error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE,
12457416Smarkm			VM_PROT_ALL, VM_PROT_ALL, 0);
12557416Smarkm	if (error)
12657416Smarkm	    return error;
12778527Sassar	vm->vm_dsize += btoc((new-old));
12857416Smarkm	p->p_retval[0] = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
12957416Smarkm    }
13057416Smarkm    return 0;
13157416Smarkm#else
13257416Smarkm    struct vmspace *vm = p->p_vmspace;
13357416Smarkm    vm_offset_t new, old;
13457416Smarkm    struct obreak_args /* {
13557416Smarkm	char * nsize;
13657416Smarkm    } */ tmp;
13757416Smarkm
13857416Smarkm#ifdef DEBUG
13957416Smarkm    printf("Linux-emul(%ld): brk(%p)\n", (long)p->p_pid, (void *)args->dsend);
14057416Smarkm#endif
141178825Sdfr    old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
14257416Smarkm    new = (vm_offset_t)args->dsend;
14357416Smarkm    tmp.nsize = (char *) new;
14478527Sassar    if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp))
14557416Smarkm	p->p_retval[0] = (int)new;
14657416Smarkm    else
14757416Smarkm	p->p_retval[0] = (int)old;
14857416Smarkm
14957416Smarkm    return 0;
150233294Sstas#endif
151233294Sstas}
15257416Smarkm
15357416Smarkmint
15457416Smarkmlinux_uselib(struct proc *p, struct linux_uselib_args *args)
15557416Smarkm{
15657416Smarkm    struct nameidata ni;
15757416Smarkm    struct vnode *vp;
15857416Smarkm    struct exec *a_out;
15957416Smarkm    struct vattr attr;
16057416Smarkm    vm_offset_t vmaddr;
16157416Smarkm    unsigned long file_offset;
16257416Smarkm    vm_offset_t buffer;
16357416Smarkm    unsigned long bss_size;
16457416Smarkm    int error;
16557416Smarkm    caddr_t sg;
16657416Smarkm    int locked;
16757416Smarkm
16857416Smarkm    sg = stackgap_init();
16957416Smarkm    CHECKALTEXIST(p, &sg, args->library);
17057416Smarkm
17157416Smarkm#ifdef DEBUG
17257416Smarkm    printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library);
17357416Smarkm#endif
17457416Smarkm
17557416Smarkm    a_out = NULL;
17657416Smarkm    locked = 0;
17757416Smarkm    vp = NULL;
17857416Smarkm
17957416Smarkm    NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, args->library, p);
18057416Smarkm    if (error = namei(&ni))
18157416Smarkm	goto cleanup;
18257416Smarkm
18357416Smarkm    vp = ni.ni_vp;
18457416Smarkm    if (vp == NULL) {
18590926Snectar	error = ENOEXEC;	/* ?? */
18690926Snectar	goto cleanup;
18790926Snectar    }
18890926Snectar
18990926Snectar    /*
19057416Smarkm     * From here on down, we have a locked vnode that must be unlocked.
19157416Smarkm     */
19257416Smarkm    locked++;
19357416Smarkm
19457416Smarkm    /*
19557416Smarkm     * Writable?
19657416Smarkm     */
19757416Smarkm    if (vp->v_writecount) {
19857416Smarkm	error = ETXTBSY;
19957416Smarkm	goto cleanup;
20057416Smarkm    }
20157416Smarkm
20257416Smarkm    /*
20357416Smarkm     * Executable?
20457416Smarkm     */
20557416Smarkm    if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p))
20657416Smarkm	goto cleanup;
20757416Smarkm
20857416Smarkm    if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
209	((attr.va_mode & 0111) == 0) ||
210	(attr.va_type != VREG)) {
211	    error = ENOEXEC;
212	    goto cleanup;
213    }
214
215    /*
216     * Sensible size?
217     */
218    if (attr.va_size == 0) {
219	error = ENOEXEC;
220	goto cleanup;
221    }
222
223    /*
224     * Can we access it?
225     */
226    if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))
227	goto cleanup;
228
229    if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p))
230	goto cleanup;
231
232    /*
233     * Lock no longer needed
234     */
235    VOP_UNLOCK(vp, 0, p);
236    locked = 0;
237
238    /*
239     * Pull in executable header into kernel_map
240     */
241    error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
242	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
243    if (error)
244	goto cleanup;
245
246    /*
247     * Is it a Linux binary ?
248     */
249    if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
250	error = ENOEXEC;
251	goto cleanup;
252    }
253
254    /* While we are here, we should REALLY do some more checks */
255
256    /*
257     * Set file/virtual offset based on a.out variant.
258     */
259    switch ((int)(a_out->a_magic & 0xffff)) {
260    case 0413:	/* ZMAGIC */
261	file_offset = 1024;
262	break;
263    case 0314:	/* QMAGIC */
264	file_offset = 0;
265	break;
266    default:
267	error = ENOEXEC;
268	goto cleanup;
269    }
270
271    bss_size = round_page(a_out->a_bss);
272
273    /*
274     * Check various fields in header for validity/bounds.
275     */
276    if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
277	error = ENOEXEC;
278	goto cleanup;
279    }
280
281    /* text + data can't exceed file size */
282    if (a_out->a_data + a_out->a_text > attr.va_size) {
283	error = EFAULT;
284	goto cleanup;
285    }
286
287    /*
288     * text/data/bss must not exceed limits
289     * XXX: this is not complete. it should check current usage PLUS
290     * the resources needed by this library.
291     */
292    if (a_out->a_text > MAXTSIZ ||
293	a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
294	error = ENOMEM;
295	goto cleanup;
296    }
297
298    /*
299     * prevent more writers
300     */
301    vp->v_flag |= VTEXT;
302
303    /*
304     * Check if file_offset page aligned,.
305     * Currently we cannot handle misalinged file offsets,
306     * and so we read in the entire image (what a waste).
307     */
308    if (file_offset & PAGE_MASK) {
309#ifdef DEBUG
310printf("uselib: Non page aligned binary %lu\n", file_offset);
311#endif
312	/*
313	 * Map text+data read/write/execute
314	 */
315
316	/* a_entry is the load address and is page aligned */
317	vmaddr = trunc_page(a_out->a_entry);
318
319	/* get anon user mapping, read+write+execute */
320	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
321		    	    a_out->a_text + a_out->a_data, FALSE,
322			    VM_PROT_ALL, VM_PROT_ALL, 0);
323	if (error)
324	    goto cleanup;
325
326	/* map file into kernel_map */
327	error = vm_mmap(kernel_map, &buffer,
328			round_page(a_out->a_text + a_out->a_data + file_offset),
329		   	VM_PROT_READ, VM_PROT_READ, 0,
330			(caddr_t)vp, trunc_page(file_offset));
331	if (error)
332	    goto cleanup;
333
334	/* copy from kernel VM space to user space */
335	error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr,
336			a_out->a_text + a_out->a_data);
337
338	/* release temporary kernel space */
339	vm_map_remove(kernel_map, buffer,
340		      buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
341
342	if (error)
343	    goto cleanup;
344    }
345    else {
346#ifdef DEBUG
347printf("uselib: Page aligned binary %lu\n", file_offset);
348#endif
349	/*
350	 * for QMAGIC, a_entry is 20 bytes beyond the load address
351	 * to skip the executable header
352	 */
353	vmaddr = trunc_page(a_out->a_entry);
354
355	/*
356	 * Map it all into the process's space as a single copy-on-write
357	 * "data" segment.
358	 */
359	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
360		   	a_out->a_text + a_out->a_data,
361			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
362			(caddr_t)vp, file_offset);
363	if (error)
364	    goto cleanup;
365    }
366#ifdef DEBUG
367printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
368#endif
369    if (bss_size != 0) {
370        /*
371	 * Calculate BSS start address
372	 */
373	vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data;
374
375	/*
376	 * allocate some 'anon' space
377	 */
378	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
379			    bss_size, FALSE,
380			    VM_PROT_ALL, VM_PROT_ALL, 0);
381	if (error)
382	    goto cleanup;
383    }
384
385cleanup:
386    /*
387     * Unlock vnode if needed
388     */
389    if (locked)
390	VOP_UNLOCK(vp, 0, p);
391
392    /*
393     * Release the kernel mapping.
394     */
395    if (a_out)
396	vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE);
397
398    return error;
399}
400
401/* XXX move */
402struct linux_select_argv {
403	int nfds;
404	fd_set *readfds;
405	fd_set *writefds;
406	fd_set *exceptfds;
407	struct timeval *timeout;
408};
409
410int
411linux_select(struct proc *p, struct linux_select_args *args)
412{
413    struct linux_select_argv linux_args;
414    struct linux_newselect_args newsel;
415    int error;
416
417#ifdef SELECT_DEBUG
418    printf("Linux-emul(%d): select(%x)\n",
419	   p->p_pid, args->ptr);
420#endif
421    if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
422			sizeof(linux_args))))
423	return error;
424
425    newsel.nfds = linux_args.nfds;
426    newsel.readfds = linux_args.readfds;
427    newsel.writefds = linux_args.writefds;
428    newsel.exceptfds = linux_args.exceptfds;
429    newsel.timeout = linux_args.timeout;
430
431    return linux_newselect(p, &newsel);
432}
433
434int
435linux_newselect(struct proc *p, struct linux_newselect_args *args)
436{
437    struct select_args bsa;
438    struct timeval tv0, tv1, utv, *tvp;
439    caddr_t sg;
440    int error;
441
442#ifdef DEBUG
443    printf("Linux-emul(%ld): newselect(%d, %p, %p, %p, %p)\n",
444  	(long)p->p_pid, args->nfds, (void *)args->readfds,
445	(void *)args->writefds, (void *)args->exceptfds,
446	(void *)args->timeout);
447#endif
448    error = 0;
449    bsa.nd = args->nfds;
450    bsa.in = args->readfds;
451    bsa.ou = args->writefds;
452    bsa.ex = args->exceptfds;
453    bsa.tv = args->timeout;
454
455    /*
456     * Store current time for computation of the amount of
457     * time left.
458     */
459    if (args->timeout) {
460	if ((error = copyin(args->timeout, &utv, sizeof(utv))))
461	    goto select_out;
462#ifdef DEBUG
463	printf("Linux-emul(%ld): incoming timeout (%ld/%ld)\n",
464	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
465#endif
466	if (itimerfix(&utv)) {
467	    /*
468	     * The timeval was invalid.  Convert it to something
469	     * valid that will act as it does under Linux.
470	     */
471	    sg = stackgap_init();
472	    tvp = stackgap_alloc(&sg, sizeof(utv));
473	    utv.tv_sec += utv.tv_usec / 1000000;
474	    utv.tv_usec %= 1000000;
475	    if (utv.tv_usec < 0) {
476		utv.tv_sec -= 1;
477		utv.tv_usec += 1000000;
478	    }
479	    if (utv.tv_sec < 0)
480		timevalclear(&utv);
481	    if ((error = copyout(&utv, tvp, sizeof(utv))))
482		goto select_out;
483	    bsa.tv = tvp;
484	}
485	microtime(&tv0);
486    }
487
488    error = select(p, &bsa);
489#ifdef DEBUG
490    printf("Linux-emul(%d): real select returns %d\n",
491	       p->p_pid, error);
492#endif
493
494    if (error) {
495	/*
496	 * See fs/select.c in the Linux kernel.  Without this,
497	 * Maelstrom doesn't work.
498	 */
499	if (error == ERESTART)
500	    error = EINTR;
501	goto select_out;
502    }
503
504    if (args->timeout) {
505	if (p->p_retval[0]) {
506	    /*
507	     * Compute how much time was left of the timeout,
508	     * by subtracting the current time and the time
509	     * before we started the call, and subtracting
510	     * that result from the user-supplied value.
511	     */
512	    microtime(&tv1);
513	    timevalsub(&tv1, &tv0);
514	    timevalsub(&utv, &tv1);
515	    if (utv.tv_sec < 0)
516		timevalclear(&utv);
517	} else
518	    timevalclear(&utv);
519#ifdef DEBUG
520	printf("Linux-emul(%ld): outgoing timeout (%ld/%ld)\n",
521	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
522#endif
523	if ((error = copyout(&utv, args->timeout, sizeof(utv))))
524	    goto select_out;
525    }
526
527select_out:
528#ifdef DEBUG
529    printf("Linux-emul(%d): newselect_out -> %d\n",
530	       p->p_pid, error);
531#endif
532    return error;
533}
534
535int
536linux_getpgid(struct proc *p, struct linux_getpgid_args *args)
537{
538    struct proc *curproc;
539
540#ifdef DEBUG
541    printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid);
542#endif
543    if (args->pid != p->p_pid) {
544	if (!(curproc = pfind(args->pid)))
545	    return ESRCH;
546    }
547    else
548	curproc = p;
549    p->p_retval[0] = curproc->p_pgid;
550    return 0;
551}
552
553int
554linux_fork(struct proc *p, struct linux_fork_args *args)
555{
556    int error;
557
558#ifdef DEBUG
559    printf("Linux-emul(%d): fork()\n", p->p_pid);
560#endif
561    if (error = fork(p, (struct fork_args *)args))
562	return error;
563    if (p->p_retval[1] == 1)
564	p->p_retval[0] = 0;
565    return 0;
566}
567
568/* XXX move */
569struct linux_mmap_argv {
570	linux_caddr_t addr;
571	int len;
572	int prot;
573	int flags;
574	int fd;
575	int pos;
576};
577
578int
579linux_mmap(struct proc *p, struct linux_mmap_args *args)
580{
581    struct mmap_args /* {
582	caddr_t addr;
583	size_t len;
584	int prot;
585	int flags;
586	int fd;
587	long pad;
588	off_t pos;
589    } */ bsd_args;
590    int error;
591    struct linux_mmap_argv linux_args;
592
593    if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
594			sizeof(linux_args))))
595	return error;
596#ifdef DEBUG
597    printf("Linux-emul(%ld): mmap(%p, %d, %d, %08x, %d, %d)\n",
598	(long)p->p_pid, (void *)linux_args.addr, linux_args.len,
599	linux_args.prot, linux_args.flags, linux_args.fd, linux_args.pos);
600#endif
601    bsd_args.flags = 0;
602    if (linux_args.flags & LINUX_MAP_SHARED)
603	bsd_args.flags |= MAP_SHARED;
604    if (linux_args.flags & LINUX_MAP_PRIVATE)
605	bsd_args.flags |= MAP_PRIVATE;
606    if (linux_args.flags & LINUX_MAP_FIXED)
607	bsd_args.flags |= MAP_FIXED;
608    if (linux_args.flags & LINUX_MAP_ANON)
609	bsd_args.flags |= MAP_ANON;
610    bsd_args.addr = linux_args.addr;
611    bsd_args.len = linux_args.len;
612    bsd_args.prot = linux_args.prot | PROT_READ;	/* always required */
613    bsd_args.fd = linux_args.fd;
614    bsd_args.pos = linux_args.pos;
615    bsd_args.pad = 0;
616    return mmap(p, &bsd_args);
617}
618
619int
620linux_mremap(struct proc *p, struct linux_mremap_args *args)
621{
622	struct munmap_args /* {
623		void *addr;
624		size_t len;
625	} */ bsd_args;
626	int error = 0;
627
628#ifdef DEBUG
629	printf("Linux-emul(%ld): mremap(%p, %08x, %08x, %08x)\n",
630	    (long)p->p_pid, (void *)args->addr, args->old_len, args->new_len,
631	    args->flags);
632#endif
633	args->new_len = round_page(args->new_len);
634	args->old_len = round_page(args->old_len);
635
636	if (args->new_len > args->old_len) {
637		p->p_retval[0] = 0;
638		return ENOMEM;
639	}
640
641	if (args->new_len < args->old_len) {
642		bsd_args.addr = args->addr + args->new_len;
643		bsd_args.len = args->old_len - args->new_len;
644		error = munmap(p, &bsd_args);
645	}
646
647	p->p_retval[0] = error ? 0 : (int)args->addr;
648	return error;
649}
650
651int
652linux_msync(struct proc *p, struct linux_msync_args *args)
653{
654	struct msync_args bsd_args;
655
656	bsd_args.addr = args->addr;
657	bsd_args.len = args->len;
658	bsd_args.flags = 0;	/* XXX ignore */
659
660	return msync(p, &bsd_args);
661}
662
663int
664linux_pipe(struct proc *p, struct linux_pipe_args *args)
665{
666    int error;
667
668#ifdef DEBUG
669    printf("Linux-emul(%d): pipe(*)\n", p->p_pid);
670#endif
671    if (error = pipe(p, 0))
672	return error;
673    if (error = copyout(p->p_retval, args->pipefds, 2*sizeof(int)))
674	return error;
675    p->p_retval[0] = 0;
676    return 0;
677}
678
679int
680linux_time(struct proc *p, struct linux_time_args *args)
681{
682    struct timeval tv;
683    linux_time_t tm;
684    int error;
685
686#ifdef DEBUG
687    printf("Linux-emul(%d): time(*)\n", p->p_pid);
688#endif
689    microtime(&tv);
690    tm = tv.tv_sec;
691    if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t))))
692	return error;
693    p->p_retval[0] = tm;
694    return 0;
695}
696
697struct linux_times_argv {
698    long    tms_utime;
699    long    tms_stime;
700    long    tms_cutime;
701    long    tms_cstime;
702};
703
704#define CLK_TCK 100	/* Linux uses 100 */
705#define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
706
707int
708linux_times(struct proc *p, struct linux_times_args *args)
709{
710    struct timeval tv;
711    struct linux_times_argv tms;
712    struct rusage ru;
713    int error;
714
715#ifdef DEBUG
716    printf("Linux-emul(%d): times(*)\n", p->p_pid);
717#endif
718    calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
719
720    tms.tms_utime = CONVTCK(ru.ru_utime);
721    tms.tms_stime = CONVTCK(ru.ru_stime);
722
723    tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
724    tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
725
726    if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf,
727	    	    sizeof(struct linux_times_argv))))
728	return error;
729
730    microuptime(&tv);
731    p->p_retval[0] = (int)CONVTCK(tv);
732    return 0;
733}
734
735/* XXX move */
736struct linux_newuname_t {
737    char sysname[65];
738    char nodename[65];
739    char release[65];
740    char version[65];
741    char machine[65];
742    char domainname[65];
743};
744
745int
746linux_newuname(struct proc *p, struct linux_newuname_args *args)
747{
748    struct linux_newuname_t linux_newuname;
749
750#ifdef DEBUG
751    printf("Linux-emul(%d): newuname(*)\n", p->p_pid);
752#endif
753    bzero(&linux_newuname, sizeof(struct linux_newuname_args));
754    strncpy(linux_newuname.sysname, ostype, 64);
755    strncpy(linux_newuname.nodename, hostname, 64);
756    strncpy(linux_newuname.release, osrelease, 64);
757    strncpy(linux_newuname.version, version, 64);
758    strncpy(linux_newuname.machine, machine, 64);
759    strncpy(linux_newuname.domainname, domainname, 64);
760    return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf,
761	    	    sizeof(struct linux_newuname_t)));
762}
763
764struct linux_utimbuf {
765	linux_time_t l_actime;
766	linux_time_t l_modtime;
767};
768
769int
770linux_utime(struct proc *p, struct linux_utime_args *args)
771{
772    struct utimes_args /* {
773	char	*path;
774	struct	timeval *tptr;
775    } */ bsdutimes;
776    struct timeval tv[2], *tvp;
777    struct linux_utimbuf lut;
778    int error;
779    caddr_t sg;
780
781    sg = stackgap_init();
782    CHECKALTEXIST(p, &sg, args->fname);
783
784#ifdef DEBUG
785    printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname);
786#endif
787    if (args->times) {
788	if ((error = copyin(args->times, &lut, sizeof lut)))
789	    return error;
790	tv[0].tv_sec = lut.l_actime;
791	tv[0].tv_usec = 0;
792	tv[1].tv_sec = lut.l_modtime;
793	tv[1].tv_usec = 0;
794	/* so that utimes can copyin */
795	tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv));
796	if ((error = copyout(tv, tvp, sizeof(tv))))
797	    return error;
798	bsdutimes.tptr = tvp;
799    } else
800	bsdutimes.tptr = NULL;
801
802    bsdutimes.path = args->fname;
803    return utimes(p, &bsdutimes);
804}
805
806int
807linux_waitpid(struct proc *p, struct linux_waitpid_args *args)
808{
809    struct wait_args /* {
810	int pid;
811	int *status;
812	int options;
813	struct	rusage *rusage;
814    } */ tmp;
815    int error, tmpstat;
816
817#ifdef DEBUG
818    printf("Linux-emul(%ld): waitpid(%d, %p, %d)\n",
819	(long)p->p_pid, args->pid, (void *)args->status, args->options);
820#endif
821    tmp.pid = args->pid;
822    tmp.status = args->status;
823    tmp.options = args->options;
824    tmp.rusage = NULL;
825
826    if (error = wait4(p, &tmp))
827	return error;
828    if (args->status) {
829	if (error = copyin(args->status, &tmpstat, sizeof(int)))
830	    return error;
831	if (WIFSIGNALED(tmpstat))
832	    tmpstat = (tmpstat & 0xffffff80) |
833		      bsd_to_linux_signal[WTERMSIG(tmpstat)];
834	else if (WIFSTOPPED(tmpstat))
835	    tmpstat = (tmpstat & 0xffff00ff) |
836		      (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
837	return copyout(&tmpstat, args->status, sizeof(int));
838    } else
839	return 0;
840}
841
842int
843linux_wait4(struct proc *p, struct linux_wait4_args *args)
844{
845    struct wait_args /* {
846	int pid;
847	int *status;
848	int options;
849	struct	rusage *rusage;
850    } */ tmp;
851    int error, tmpstat;
852
853#ifdef DEBUG
854    printf("Linux-emul(%ld): wait4(%d, %p, %d, %p)\n",
855	(long)p->p_pid, args->pid, (void *)args->status, args->options,
856	(void *)args->rusage);
857#endif
858    tmp.pid = args->pid;
859    tmp.status = args->status;
860    tmp.options = args->options;
861    tmp.rusage = args->rusage;
862
863    if (error = wait4(p, &tmp))
864	return error;
865
866    p->p_siglist &= ~sigmask(SIGCHLD);
867
868    if (args->status) {
869	if (error = copyin(args->status, &tmpstat, sizeof(int)))
870	    return error;
871	if (WIFSIGNALED(tmpstat))
872	    tmpstat = (tmpstat & 0xffffff80) |
873		  bsd_to_linux_signal[WTERMSIG(tmpstat)];
874	else if (WIFSTOPPED(tmpstat))
875	    tmpstat = (tmpstat & 0xffff00ff) |
876		  (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
877	return copyout(&tmpstat, args->status, sizeof(int));
878    } else
879	return 0;
880}
881
882int
883linux_mknod(struct proc *p, struct linux_mknod_args *args)
884{
885	caddr_t sg;
886	struct mknod_args bsd_mknod;
887	struct mkfifo_args bsd_mkfifo;
888
889	sg = stackgap_init();
890
891	CHECKALTCREAT(p, &sg, args->path);
892
893#ifdef DEBUG
894	printf("Linux-emul(%d): mknod(%s, %d, %d)\n",
895	   p->p_pid, args->path, args->mode, args->dev);
896#endif
897
898	if (args->mode & S_IFIFO) {
899		bsd_mkfifo.path = args->path;
900		bsd_mkfifo.mode = args->mode;
901		return mkfifo(p, &bsd_mkfifo);
902	} else {
903		bsd_mknod.path = args->path;
904		bsd_mknod.mode = args->mode;
905		bsd_mknod.dev = args->dev;
906		return mknod(p, &bsd_mknod);
907	}
908}
909
910/*
911 * UGH! This is just about the dumbest idea I've ever heard!!
912 */
913int
914linux_personality(struct proc *p, struct linux_personality_args *args)
915{
916#ifdef DEBUG
917	printf("Linux-emul(%d): personality(%d)\n",
918	   p->p_pid, args->per);
919#endif
920	if (args->per != 0)
921		return EINVAL;
922
923	/* Yes Jim, it's still a Linux... */
924	p->p_retval[0] = 0;
925	return 0;
926}
927
928/*
929 * Wrappers for get/setitimer for debugging..
930 */
931int
932linux_setitimer(struct proc *p, struct linux_setitimer_args *args)
933{
934	struct setitimer_args bsa;
935	struct itimerval foo;
936	int error;
937
938#ifdef DEBUG
939	printf("Linux-emul(%ld): setitimer(%p, %p)\n",
940	    (long)p->p_pid, (void *)args->itv, (void *)args->oitv);
941#endif
942	bsa.which = args->which;
943	bsa.itv = args->itv;
944	bsa.oitv = args->oitv;
945	if (args->itv) {
946	    if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo,
947			sizeof(foo))))
948		return error;
949#ifdef DEBUG
950	    printf("setitimer: value: sec: %ld, usec: %ld\n",
951		foo.it_value.tv_sec, foo.it_value.tv_usec);
952	    printf("setitimer: interval: sec: %ld, usec: %ld\n",
953		foo.it_interval.tv_sec, foo.it_interval.tv_usec);
954#endif
955	}
956	return setitimer(p, &bsa);
957}
958
959int
960linux_getitimer(struct proc *p, struct linux_getitimer_args *args)
961{
962	struct getitimer_args bsa;
963#ifdef DEBUG
964	printf("Linux-emul(%ld): getitimer(%p)\n",
965	    (long)p->p_pid, (void *)args->itv);
966#endif
967	bsa.which = args->which;
968	bsa.itv = args->itv;
969	return getitimer(p, &bsa);
970}
971
972int
973linux_iopl(struct proc *p, struct linux_iopl_args *args)
974{
975	int error;
976
977	error = suser(p->p_ucred, &p->p_acflag);
978	if (error != 0)
979		return error;
980	if (securelevel > 0)
981		return EPERM;
982	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
983	return 0;
984}
985
986int
987linux_nice(struct proc *p, struct linux_nice_args *args)
988{
989	struct setpriority_args	bsd_args;
990
991	bsd_args.which = PRIO_PROCESS;
992	bsd_args.who = 0;	/* current process */
993	bsd_args.prio = args->inc;
994	return setpriority(p, &bsd_args);
995}
996
997