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.10 1996/01/14 10:59:57 sos 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/exec.h> 36 #include <sys/mman.h> 37 #include <sys/proc.h> 38 #include <sys/dirent.h> 39 #include <sys/file.h> 40 #include <sys/filedesc.h> 41 #include <sys/ioctl.h> 42 #include <sys/imgact_aout.h> 43 #include <sys/mount.h> 44 #include <sys/namei.h> 45 #include <sys/resource.h> 46 #include <sys/resourcevar.h> 47 #include <sys/stat.h> 48 #include <sys/sysctl.h> 49 #include <sys/times.h> 50 #include <sys/utsname.h> 51 #include <sys/vnode.h> 52 #include <sys/wait.h> 53 54 #include <vm/vm.h> 55 #include <vm/vm_param.h> 56 #include <vm/pmap.h> 57 #include <vm/lock.h> 58 #include <vm/vm_kern.h> 59 #include <vm/vm_prot.h> 60 #include <vm/vm_map.h> 61 #include <vm/vm_extern.h> 62 63 #include <machine/cpu.h> 64 #include <machine/psl.h> 65 66 #include <i386/linux/linux.h> 67 #include <i386/linux/sysproto.h> 68 69 struct linux_alarm_args { 70 unsigned int secs; 71 }; 72 73 int 74 linux_alarm(struct proc *p, struct linux_alarm_args *args, int *retval) 75 { 76 struct itimerval it, old_it; 77 struct timeval tv; 78 int s; 79 80 #ifdef DEBUG 81 printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs); 82 #endif 83 it.it_value.tv_sec = (long)args->secs; 84 it.it_value.tv_usec = 0; 85 it.it_interval.tv_sec = 0; 86 it.it_interval.tv_usec = 0; 87 s = splclock(); 88 old_it = p->p_realtimer; 89 tv = time; 90 if (timerisset(&old_it.it_value)) 91 if (timercmp(&old_it.it_value, &tv, <)) 92 timerclear(&old_it.it_value); 93 else 94 timevalsub(&old_it.it_value, &tv); 95 splx(s); 96 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) 97 return EINVAL; 98 s = splclock(); 99 untimeout(realitexpire, (caddr_t)p); 100 tv = time; 101 if (timerisset(&it.it_value)) { 102 timevaladd(&it.it_value, &tv); 103 timeout(realitexpire, (caddr_t)p, hzto(&it.it_value)); 104 } 105 p->p_realtimer = it; 106 splx(s); 107 if (old_it.it_value.tv_usec) 108 old_it.it_value.tv_sec++; 109 *retval = old_it.it_value.tv_sec; 110 return 0; 111 } 112 113 struct linux_brk_args { 114 linux_caddr_t dsend; 115 }; 116 117 int 118 linux_brk(struct proc *p, struct linux_brk_args *args, int *retval) 119 { 120 #if 0 121 struct vmspace *vm = p->p_vmspace; 122 vm_offset_t new, old; 123 int error; 124 125 if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr) 126 return EINVAL; 127 if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr) 128 > p->p_rlimit[RLIMIT_DATA].rlim_cur) 129 return ENOMEM; 130 131 old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize); 132 new = round_page((vm_offset_t)args->dsend); 133 *retval = old; 134 if ((new-old) > 0) { 135 if (swap_pager_full) 136 return ENOMEM; 137 error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE, 138 VM_PROT_ALL, VM_PROT_ALL, 0); 139 if (error) 140 return error; 141 vm->vm_dsize += btoc((new-old)); 142 *retval = (int)(vm->vm_daddr + ctob(vm->vm_dsize)); 143 } 144 return 0; 145 #else 146 struct vmspace *vm = p->p_vmspace; 147 vm_offset_t new, old; 148 struct obreak_args /* { 149 char * nsize; 150 } */ tmp; 151 152 #ifdef DEBUG 153 printf("Linux-emul(%d): brk(%08x)\n", p->p_pid, args->dsend); 154 #endif 155 old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); 156 new = (vm_offset_t)args->dsend; 157 tmp.nsize = (char *) new; 158 if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp, retval)) 159 retval[0] = (int)new; 160 else 161 retval[0] = (int)old; 162 163 return 0; 164 #endif 165 } 166 167 struct linux_uselib_args { 168 char *library; 169 }; 170 171 int 172 linux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval) 173 { 174 struct nameidata ni; 175 struct vnode *vp; 176 struct exec *a_out = 0; 177 struct vattr attr; 178 unsigned long vmaddr, virtual_offset, file_offset; 179 unsigned long buffer, bss_size; 180 char *ptr; 181 char path[MAXPATHLEN]; 182 const char *prefix = "/compat/linux"; 183 size_t sz, len; 184 int error; 185 186 #ifdef DEBUG 187 printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library); 188 #endif 189 190 for (ptr = path; (*ptr = *prefix) != '\0'; ptr++, prefix++) ; 191 sz = MAXPATHLEN - (ptr - path); 192 if (error = copyinstr(args->library, ptr, sz, &len)) 193 return error; 194 if (*ptr != '/') 195 return EINVAL; 196 197 #ifdef DEBUG 198 printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, path); 199 #endif 200 201 NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p); 202 if (error = namei(&ni)) 203 return error; 204 205 vp = ni.ni_vp; 206 if (vp == NULL) 207 return ENOEXEC; 208 209 if (vp->v_writecount) { 210 VOP_UNLOCK(vp); 211 return ETXTBSY; 212 } 213 214 if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p)) { 215 VOP_UNLOCK(vp); 216 return error; 217 } 218 219 if ((vp->v_mount->mnt_flag & MNT_NOEXEC) 220 || ((attr.va_mode & 0111) == 0) 221 || (attr.va_type != VREG)) { 222 VOP_UNLOCK(vp); 223 return ENOEXEC; 224 } 225 226 if (attr.va_size == 0) { 227 VOP_UNLOCK(vp); 228 return ENOEXEC; 229 } 230 231 if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) { 232 VOP_UNLOCK(vp); 233 return error; 234 } 235 236 if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) { 237 VOP_UNLOCK(vp); 238 return error; 239 } 240 241 VOP_UNLOCK(vp); /* lock no longer needed */ 242 243 error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, 1024, 244 VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0); 245 if (error) 246 return (error); 247 248 /* 249 * Is it a Linux binary ? 250 */ 251 if (((a_out->a_magic >> 16) & 0xff) != 0x64) 252 return ENOEXEC; 253 254 /* 255 * Set file/virtual offset based on a.out variant. 256 */ 257 switch ((int)(a_out->a_magic & 0xffff)) { 258 case 0413: /* ZMAGIC */ 259 virtual_offset = 0; /* actually aout->a_entry */ 260 file_offset = 1024; 261 break; 262 case 0314: /* QMAGIC */ 263 virtual_offset = 0; /* actually aout->a_entry */ 264 file_offset = 0; 265 break; 266 default: 267 return ENOEXEC; 268 } 269 270 vp->v_flag |= VTEXT; 271 bss_size = round_page(a_out->a_bss); 272 /* 273 * Check if file_offset page aligned,. 274 * Currently we cannot handle misalinged file offsets, 275 * and so we read in the entire image (what a waste). 276 */ 277 if (file_offset & PGOFSET) { 278 #ifdef DEBUG 279 printf("uselib: Non page aligned binary %d\n", file_offset); 280 #endif 281 /* 282 * Map text+data read/write/execute 283 */ 284 vmaddr = virtual_offset + round_page(a_out->a_entry); 285 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, 286 round_page(a_out->a_text + a_out->a_data), FALSE, 287 VM_PROT_ALL, VM_PROT_ALL, 0); 288 if (error) 289 return error; 290 291 error = vm_mmap(kernel_map, &buffer, 292 round_page(a_out->a_text + a_out->a_data + file_offset), 293 VM_PROT_READ, VM_PROT_READ, MAP_FILE, 294 (caddr_t)vp, trunc_page(file_offset)); 295 if (error) 296 return error; 297 298 error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr, 299 a_out->a_text + a_out->a_data); 300 if (error) 301 return error; 302 303 vm_map_remove(kernel_map, trunc_page(vmaddr), 304 round_page(a_out->a_text + a_out->a_data + file_offset)); 305 306 error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, 307 round_page(a_out->a_text + a_out->a_data), 308 VM_PROT_ALL, TRUE); 309 if (error) 310 return error; 311 } 312 else { 313 #ifdef DEBUG 314 printf("uselib: Page aligned binary %d\n", file_offset); 315 #endif 316 vmaddr = virtual_offset + trunc_page(a_out->a_entry); 317 error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr, 318 a_out->a_text + a_out->a_data, 319 VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, 320 (caddr_t)vp, file_offset); 321 if (error) 322 return (error); 323 } 324 #ifdef DEBUG 325 printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]); 326 #endif 327 if (bss_size != 0) { 328 vmaddr = virtual_offset + round_page(a_out->a_entry) + 329 round_page(a_out->a_text + a_out->a_data); 330 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, 331 bss_size, FALSE, 332 VM_PROT_ALL, VM_PROT_ALL, 0); 333 if (error) 334 return error; 335 error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, bss_size, 336 VM_PROT_ALL, TRUE); 337 if (error) 338 return error; 339 } 340 return 0; 341 } 342 343 struct linux_select_args { 344 void *ptr; 345 }; 346 347 int 348 linux_select(struct proc *p, struct linux_select_args *args, int *retval) 349 { 350 struct { 351 int nfds; 352 fd_set *readfds; 353 fd_set *writefds; 354 fd_set *exceptfds; 355 struct timeval *timeout; 356 } linux_args; 357 struct select_args /* { 358 unsigned int nd; 359 fd_set *in; 360 fd_set *ou; 361 fd_set *ex; 362 struct timeval *tv; 363 } */ bsd_args; 364 int error; 365 366 if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, 367 sizeof(linux_args)))) 368 return error; 369 #ifdef DEBUG 370 printf("Linux-emul(%d): select(%d, %d, %d, %d, %d)\n", 371 p->p_pid, linux_args.nfds, linux_args.readfds, 372 linux_args.writefds, linux_args.exceptfds, 373 linux_args.timeout); 374 #endif 375 bsd_args.nd = linux_args.nfds; 376 bsd_args.in = linux_args.readfds; 377 bsd_args.ou = linux_args.writefds; 378 bsd_args.ex = linux_args.exceptfds; 379 bsd_args.tv = linux_args.timeout; 380 return select(p, &bsd_args, retval); 381 } 382 383 struct linux_getpgid_args { 384 int pid; 385 }; 386 387 int 388 linux_getpgid(struct proc *p, struct linux_getpgid_args *args, int *retval) 389 { 390 struct proc *curproc; 391 392 #ifdef DEBUG 393 printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid); 394 #endif 395 if (args->pid != p->p_pid) { 396 if (!(curproc = pfind(args->pid))) 397 return ESRCH; 398 } 399 else 400 curproc = p; 401 *retval = curproc->p_pgid; 402 return 0; 403 } 404 405 int 406 linux_fork(struct proc *p, void *args, int *retval) 407 { 408 int error; 409 410 #ifdef DEBUG 411 printf("Linux-emul(%d): fork()\n", p->p_pid); 412 #endif 413 if (error = fork(p, args, retval)) 414 return error; 415 if (retval[1] == 1) 416 retval[0] = 0; 417 return 0; 418 } 419 420 struct linux_mmap_args { 421 void *ptr; 422 }; 423 424 int 425 linux_mmap(struct proc *p, struct linux_mmap_args *args, int *retval) 426 { 427 struct { 428 linux_caddr_t addr; 429 int len; 430 int prot; 431 int flags; 432 int fd; 433 int pos; 434 } linux_args; 435 struct mmap_args /* { 436 caddr_t addr; 437 size_t len; 438 int prot; 439 int flags; 440 int fd; 441 long pad; 442 off_t pos; 443 } */ bsd_args; 444 int error; 445 446 if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, 447 sizeof(linux_args)))) 448 return error; 449 #ifdef DEBUG 450 printf("Linux-emul(%d): mmap(%08x, %d, %d, %08x, %d, %d)\n", 451 p->p_pid, linux_args.addr, linux_args.len, linux_args.prot, 452 linux_args.flags, linux_args.fd, linux_args.pos); 453 #endif 454 bsd_args.flags = 0; 455 if (linux_args.flags & LINUX_MAP_SHARED) 456 bsd_args.flags |= MAP_SHARED; 457 if (linux_args.flags & LINUX_MAP_PRIVATE) 458 bsd_args.flags |= MAP_PRIVATE; 459 if (linux_args.flags & LINUX_MAP_FIXED) 460 bsd_args.flags |= MAP_FIXED; 461 if (linux_args.flags & LINUX_MAP_ANON) 462 bsd_args.flags |= MAP_ANON; 463 bsd_args.addr = linux_args.addr; 464 bsd_args.len = linux_args.len; 465 bsd_args.prot = linux_args.prot; 466 bsd_args.fd = linux_args.fd; 467 bsd_args.pos = linux_args.pos; 468 bsd_args.pad = 0; 469 return mmap(p, &bsd_args, retval); 470 } 471 472 struct linux_pipe_args { 473 int *pipefds; 474 }; 475 476 int 477 linux_pipe(struct proc *p, struct linux_pipe_args *args, int *retval) 478 { 479 int error; 480 481 #ifdef DEBUG 482 printf("Linux-emul(%d): pipe(*)\n", p->p_pid); 483 #endif 484 if (error = pipe(p, 0, retval)) 485 return error; 486 if (error = copyout(retval, args->pipefds, 2*sizeof(int))) 487 return error; 488 *retval = 0; 489 return 0; 490 } 491 492 struct linux_time_args { 493 linux_time_t *tm; 494 }; 495 496 int 497 linux_time(struct proc *p, struct linux_time_args *args, int *retval) 498 { 499 struct timeval tv; 500 linux_time_t tm; 501 int error; 502 503 #ifdef DEBUG 504 printf("Linux-emul(%d): time(*)\n", p->p_pid); 505 #endif 506 microtime(&tv); 507 tm = tv.tv_sec; 508 if (error = copyout(&tm, args->tm, sizeof(linux_time_t))) 509 return error; 510 *retval = tv.tv_sec; 511 return 0; 512 } 513 514 struct linux_tms { 515 long tms_utime; 516 long tms_stime; 517 long tms_cutime; 518 long tms_cstime; 519 }; 520 521 struct linux_tms_args { 522 char *buf; 523 }; 524 525 int 526 linux_times(struct proc *p, struct linux_tms_args *args, int *retval) 527 { 528 struct timeval tv; 529 struct linux_tms tms; 530 531 #ifdef DEBUG 532 printf("Linux-emul(%d): times(*)\n", p->p_pid); 533 #endif 534 tms.tms_utime = p->p_uticks; 535 tms.tms_stime = p->p_sticks; 536 tms.tms_cutime = p->p_stats->p_cru.ru_utime.tv_sec * hz + 537 ((p->p_stats->p_cru.ru_utime.tv_usec * hz)/1000000); 538 tms.tms_cstime = p->p_stats->p_cru.ru_stime.tv_sec * hz + 539 ((p->p_stats->p_cru.ru_stime.tv_usec * hz)/1000000); 540 microtime(&tv); 541 *retval = tv.tv_sec * hz + (tv.tv_usec * hz)/1000000; 542 return (copyout((caddr_t)&tms, (caddr_t)args->buf, 543 sizeof(struct linux_tms))); 544 } 545 546 struct linux_newuname_t { 547 char sysname[65]; 548 char nodename[65]; 549 char release[65]; 550 char version[65]; 551 char machine[65]; 552 char domainname[65]; 553 }; 554 555 struct linux_newuname_args { 556 char *buf; 557 }; 558 559 int 560 linux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval) 561 { 562 struct linux_newuname_t linux_newuname; 563 564 #ifdef DEBUG 565 printf("Linux-emul(%d): newuname(*)\n", p->p_pid); 566 #endif 567 bzero(&linux_newuname, sizeof(struct linux_newuname_args)); 568 strncpy(linux_newuname.sysname, ostype, 64); 569 strncpy(linux_newuname.nodename, hostname, 64); 570 strncpy(linux_newuname.release, osrelease, 64); 571 strncpy(linux_newuname.version, version, 64); 572 strncpy(linux_newuname.machine, machine, 64); 573 strncpy(linux_newuname.domainname, domainname, 64); 574 return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf, 575 sizeof(struct linux_newuname_t))); 576 } 577 578 struct linux_utime_args { 579 char *fname; 580 linux_time_t *timeptr; 581 }; 582 583 int 584 linux_utime(struct proc *p, struct linux_utime_args *args, int *retval) 585 { 586 struct utimes_args /* { 587 char *path; 588 struct timeval *tptr; 589 } */ bsdutimes; 590 struct timeval tv; 591 592 #ifdef DEBUG 593 printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname); 594 #endif 595 tv.tv_sec = (long)args->timeptr; 596 tv.tv_usec = 0; 597 bsdutimes.tptr = &tv; 598 bsdutimes.path = args->fname; 599 return utimes(p, &bsdutimes, retval); 600 } 601 602 struct linux_waitpid_args { 603 int pid; 604 int *status; 605 int options; 606 }; 607 608 int 609 linux_waitpid(struct proc *p, struct linux_waitpid_args *args, int *retval) 610 { 611 struct wait_args /* { 612 int pid; 613 int *status; 614 int options; 615 struct rusage *rusage; 616 } */ tmp; 617 int error, tmpstat; 618 619 #ifdef DEBUG 620 printf("Linux-emul(%d): waitpid(%d, *, %d)\n", 621 p->p_pid, args->pid, args->options); 622 #endif 623 tmp.pid = args->pid; 624 tmp.status = args->status; 625 tmp.options = args->options; 626 tmp.rusage = NULL; 627 628 if (error = wait4(p, &tmp, retval)) 629 return error; 630 if (error = copyin(args->status, &tmpstat, sizeof(int))) 631 return error; 632 if (WIFSIGNALED(tmpstat)) 633 tmpstat = (tmpstat & 0xffffff80) | 634 bsd_to_linux_signal[WTERMSIG(tmpstat)]; 635 else if (WIFSTOPPED(tmpstat)) 636 tmpstat = (tmpstat & 0xffff00ff) | 637 (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); 638 return copyout(&tmpstat, args->status, sizeof(int)); 639 } 640 641 struct linux_wait4_args { 642 int pid; 643 int *status; 644 int options; 645 struct rusage *rusage; 646 }; 647 648 int 649 linux_wait4(struct proc *p, struct linux_wait4_args *args, int *retval) 650 { 651 struct wait_args /* { 652 int pid; 653 int *status; 654 int options; 655 struct rusage *rusage; 656 } */ tmp; 657 int error, tmpstat; 658 659 #ifdef DEBUG 660 printf("Linux-emul(%d): wait4(%d, *, %d, *)\n", 661 p->p_pid, args->pid, args->options); 662 #endif 663 tmp.pid = args->pid; 664 tmp.status = args->status; 665 tmp.options = args->options; 666 tmp.rusage = args->rusage; 667 668 if (error = wait4(p, &tmp, retval)) 669 return error; 670 if (error = copyin(args->status, &tmpstat, sizeof(int))) 671 return error; 672 if (WIFSIGNALED(tmpstat)) 673 tmpstat = (tmpstat & 0xffffff80) | 674 bsd_to_linux_signal[WTERMSIG(tmpstat)]; 675 else if (WIFSTOPPED(tmpstat)) 676 tmpstat = (tmpstat & 0xffff00ff) | 677 (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); 678 return copyout(&tmpstat, args->status, sizeof(int)); 679 } 680 681 struct linux_mknod_args { 682 char *path; 683 int mode; 684 int dev; 685 }; 686 687 int 688 linux_mknod(struct proc *p, struct linux_mknod_args *args, int *retval) 689 { 690 if (args->mode & S_IFIFO) 691 return mkfifo(p, (struct mkfifo_args *)args, retval); 692 else 693 return mknod(p, (struct mknod_args *)args, retval); 694 } 695