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.2 1995/10/04 07:08:04 julian Exp $
|
28 * $Id: linux_misc.c,v 1.3 1995/11/06 12:52:24 davidg Exp $ |
29 */ 30
|
31#include <i386/linux/linux.h>
|
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>
|
47#include <sys/time.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>
|
55#include <machine/reg.h>
|
58
|
57#include <vm/vm.h>
58#include <vm/vm_kern.h>
|
59#include <i386/linux/linux.h> 60#include <i386/linux/sysproto.h> |
61
|
60
|
62struct linux_alarm_args { 63 unsigned int secs; 64}; 65 66int 67linux_alarm(struct proc *p, struct linux_alarm_args *args, int *retval) 68{
|
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 103struct linux_brk_args { 104 linux_caddr_t dsend; 105}; 106 107int 108linux_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;
|
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 156struct linux_uselib_args { 157 char *library; 158}; 159 160int 161linux_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 268printf("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 302printf("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 313printf("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 330struct linux_select_args { 331 void *ptr; 332}; 333 334int 335linux_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 370struct linux_getpgid_args { 371 int pid; 372}; 373 374int 375linux_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 392int 393linux_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 407struct linux_mmap_args { 408 void *ptr; 409}; 410 411int 412linux_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 459struct linux_pipe_args { 460 int *pipefds; 461}; 462 463int 464linux_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 479struct linux_time_args { 480 linux_time_t *tm; 481}; 482 483int 484linux_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 501struct linux_tms { 502 long tms_utime; 503 long tms_stime; 504 long tms_cutime; 505 long tms_cstime; 506}; 507 508struct linux_tms_args { 509 char *buf; 510}; 511 512int 513linux_times(struct proc *p, struct linux_tms_args *args, int *retval) 514{
|
516 extern int hz;
|
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 533struct 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 542struct linux_newuname_args { 543 char *buf; 544}; 545 546int 547linux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval) 548{ 549 struct linux_newuname_t linux_newuname;
|
552 extern char ostype[], osrelease[], machine[];
553 extern char hostname[], domainname[];
|
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 565struct linux_utime_args { 566 char *fname; 567 linux_time_t *timeptr; 568}; 569 570int 571linux_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 589struct linux_waitpid_args { 590 int pid; 591 int *status; 592 int options; 593}; 594 595int 596linux_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 630struct linux_wait4_args { 631 int pid; 632 int *status; 633 int options; 634 struct rusage *rusage; 635}; 636 637int 638linux_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}
|