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