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