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