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