linux_misc.c revision 37950
157416Smarkm/*- 257416Smarkm * Copyright (c) 1994-1995 S�ren Schmidt 357416Smarkm * All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer 1057416Smarkm * in this position and unchanged. 1157416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1257416Smarkm * notice, this list of conditions and the following disclaimer in the 1357416Smarkm * documentation and/or other materials provided with the distribution. 1457416Smarkm * 3. The name of the author may not be used to endorse or promote products 1557416Smarkm * derived from this software withough specific prior written permission 1657416Smarkm * 1757416Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1857416Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1957416Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2057416Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2157416Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2257416Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2357416Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2457416Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2557416Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2657416Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2757416Smarkm * 2857416Smarkm * $Id: linux_misc.c,v 1.39 1998/07/10 22:30:01 jkh Exp $ 2957416Smarkm */ 3057416Smarkm 3157416Smarkm#include <sys/param.h> 3257416Smarkm#include <sys/systm.h> 3357416Smarkm#include <sys/sysproto.h> 3457416Smarkm#include <sys/kernel.h> 3557416Smarkm#include <sys/mman.h> 36233294Sstas#include <sys/proc.h> 3757416Smarkm#include <sys/fcntl.h> 3857416Smarkm#include <sys/imgact_aout.h> 3957416Smarkm#include <sys/mount.h> 4057416Smarkm#include <sys/namei.h> 4157416Smarkm#include <sys/resourcevar.h> 4257416Smarkm#include <sys/stat.h> 4357416Smarkm#include <sys/sysctl.h> 4457416Smarkm#include <sys/vnode.h> 4557416Smarkm#include <sys/wait.h> 4657416Smarkm#include <sys/time.h> 4757416Smarkm 4857416Smarkm#include <vm/vm.h> 4957416Smarkm#include <vm/pmap.h> 5057416Smarkm#include <vm/vm_kern.h> 5157416Smarkm#include <vm/vm_prot.h> 5257416Smarkm#include <vm/vm_map.h> 5357416Smarkm#include <vm/vm_extern.h> 5457416Smarkm 5557416Smarkm#include <machine/frame.h> 5657416Smarkm#include <machine/psl.h> 5757416Smarkm 5857416Smarkm#include <i386/linux/linux.h> 5957416Smarkm#include <i386/linux/linux_proto.h> 60178825Sdfr#include <i386/linux/linux_util.h> 6157416Smarkm 6257416Smarkmint 6357416Smarkmlinux_alarm(struct proc *p, struct linux_alarm_args *args) 6457416Smarkm{ 6557416Smarkm struct itimerval it, old_it; 6657416Smarkm struct timeval tv; 6757416Smarkm int s; 6857416Smarkm 6957416Smarkm#ifdef DEBUG 7057416Smarkm printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs); 7157416Smarkm#endif 7257416Smarkm it.it_value.tv_sec = (long)args->secs; 7357416Smarkm it.it_value.tv_usec = 0; 7457416Smarkm it.it_interval.tv_sec = 0; 7557416Smarkm it.it_interval.tv_usec = 0; 7657416Smarkm s = splclock(); /* XXX Still needed ? */ 7757416Smarkm old_it = p->p_realtimer; 7857416Smarkm getmicrotime(&tv); 7957416Smarkm if (timevalisset(&old_it.it_value)) 8057416Smarkm if (timevalcmp(&old_it.it_value, &tv, <)) 8172445Sassar timevalclear(&old_it.it_value); 8257416Smarkm else 8357416Smarkm timevalsub(&old_it.it_value, &tv); 8457416Smarkm splx(s); 8557416Smarkm if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) 8657416Smarkm return EINVAL; 8757416Smarkm s = splclock(); /* XXX Still needed ? */ 8857416Smarkm if (timevalisset(&p->p_realtimer.it_value)) 8957416Smarkm untimeout(realitexpire, (caddr_t)p, p->p_ithandle); 9057416Smarkm getmicrotime(&tv); 9157416Smarkm if (timevalisset(&it.it_value)) { 9257416Smarkm timevaladd(&it.it_value, &tv); 9357416Smarkm p->p_ithandle = timeout(realitexpire, (caddr_t)p, hzto(&it.it_value)); 9457416Smarkm } 9557416Smarkm p->p_realtimer = it; 9657416Smarkm splx(s); 9757416Smarkm if (old_it.it_value.tv_usec) 9857416Smarkm old_it.it_value.tv_sec++; 9957416Smarkm p->p_retval[0] = old_it.it_value.tv_sec; 10057416Smarkm return 0; 10157416Smarkm} 10257416Smarkm 10357416Smarkmint 10457416Smarkmlinux_brk(struct proc *p, struct linux_brk_args *args) 10557416Smarkm{ 10657416Smarkm#if 0 10757416Smarkm struct vmspace *vm = p->p_vmspace; 10857416Smarkm vm_offset_t new, old; 10957416Smarkm int error; 11057416Smarkm 11157416Smarkm if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr) 11257416Smarkm return EINVAL; 11357416Smarkm if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr) 11457416Smarkm > p->p_rlimit[RLIMIT_DATA].rlim_cur) 11557416Smarkm return ENOMEM; 11657416Smarkm 11757416Smarkm old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize); 118178825Sdfr new = round_page((vm_offset_t)args->dsend); 11978527Sassar p->p_retval[0] = old; 12057416Smarkm if ((new-old) > 0) { 12178527Sassar if (swap_pager_full) 12257416Smarkm return ENOMEM; 12357416Smarkm error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE, 12457416Smarkm VM_PROT_ALL, VM_PROT_ALL, 0); 12557416Smarkm if (error) 12657416Smarkm return error; 12778527Sassar vm->vm_dsize += btoc((new-old)); 12857416Smarkm p->p_retval[0] = (int)(vm->vm_daddr + ctob(vm->vm_dsize)); 12957416Smarkm } 13057416Smarkm return 0; 13157416Smarkm#else 13257416Smarkm struct vmspace *vm = p->p_vmspace; 13357416Smarkm vm_offset_t new, old; 13457416Smarkm struct obreak_args /* { 13557416Smarkm char * nsize; 13657416Smarkm } */ tmp; 13757416Smarkm 13857416Smarkm#ifdef DEBUG 13957416Smarkm printf("Linux-emul(%ld): brk(%p)\n", (long)p->p_pid, (void *)args->dsend); 14057416Smarkm#endif 141178825Sdfr old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); 14257416Smarkm new = (vm_offset_t)args->dsend; 14357416Smarkm tmp.nsize = (char *) new; 14478527Sassar if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp)) 14557416Smarkm p->p_retval[0] = (int)new; 14657416Smarkm else 14757416Smarkm p->p_retval[0] = (int)old; 14857416Smarkm 14957416Smarkm return 0; 150233294Sstas#endif 151233294Sstas} 15257416Smarkm 15357416Smarkmint 15457416Smarkmlinux_uselib(struct proc *p, struct linux_uselib_args *args) 15557416Smarkm{ 15657416Smarkm struct nameidata ni; 15757416Smarkm struct vnode *vp; 15857416Smarkm struct exec *a_out; 15957416Smarkm struct vattr attr; 16057416Smarkm vm_offset_t vmaddr; 16157416Smarkm unsigned long file_offset; 16257416Smarkm vm_offset_t buffer; 16357416Smarkm unsigned long bss_size; 16457416Smarkm int error; 16557416Smarkm caddr_t sg; 16657416Smarkm int locked; 16757416Smarkm 16857416Smarkm sg = stackgap_init(); 16957416Smarkm CHECKALTEXIST(p, &sg, args->library); 17057416Smarkm 17157416Smarkm#ifdef DEBUG 17257416Smarkm printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library); 17357416Smarkm#endif 17457416Smarkm 17557416Smarkm a_out = NULL; 17657416Smarkm locked = 0; 17757416Smarkm vp = NULL; 17857416Smarkm 17957416Smarkm NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, args->library, p); 18057416Smarkm if (error = namei(&ni)) 18157416Smarkm goto cleanup; 18257416Smarkm 18357416Smarkm vp = ni.ni_vp; 18457416Smarkm if (vp == NULL) { 18590926Snectar error = ENOEXEC; /* ?? */ 18690926Snectar goto cleanup; 18790926Snectar } 18890926Snectar 18990926Snectar /* 19057416Smarkm * From here on down, we have a locked vnode that must be unlocked. 19157416Smarkm */ 19257416Smarkm locked++; 19357416Smarkm 19457416Smarkm /* 19557416Smarkm * Writable? 19657416Smarkm */ 19757416Smarkm if (vp->v_writecount) { 19857416Smarkm error = ETXTBSY; 19957416Smarkm goto cleanup; 20057416Smarkm } 20157416Smarkm 20257416Smarkm /* 20357416Smarkm * Executable? 20457416Smarkm */ 20557416Smarkm if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p)) 20657416Smarkm goto cleanup; 20757416Smarkm 20857416Smarkm if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || 209 ((attr.va_mode & 0111) == 0) || 210 (attr.va_type != VREG)) { 211 error = ENOEXEC; 212 goto cleanup; 213 } 214 215 /* 216 * Sensible size? 217 */ 218 if (attr.va_size == 0) { 219 error = ENOEXEC; 220 goto cleanup; 221 } 222 223 /* 224 * Can we access it? 225 */ 226 if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) 227 goto cleanup; 228 229 if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) 230 goto cleanup; 231 232 /* 233 * Lock no longer needed 234 */ 235 VOP_UNLOCK(vp, 0, p); 236 locked = 0; 237 238 /* 239 * Pull in executable header into kernel_map 240 */ 241 error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE, 242 VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0); 243 if (error) 244 goto cleanup; 245 246 /* 247 * Is it a Linux binary ? 248 */ 249 if (((a_out->a_magic >> 16) & 0xff) != 0x64) { 250 error = ENOEXEC; 251 goto cleanup; 252 } 253 254 /* While we are here, we should REALLY do some more checks */ 255 256 /* 257 * Set file/virtual offset based on a.out variant. 258 */ 259 switch ((int)(a_out->a_magic & 0xffff)) { 260 case 0413: /* ZMAGIC */ 261 file_offset = 1024; 262 break; 263 case 0314: /* QMAGIC */ 264 file_offset = 0; 265 break; 266 default: 267 error = ENOEXEC; 268 goto cleanup; 269 } 270 271 bss_size = round_page(a_out->a_bss); 272 273 /* 274 * Check various fields in header for validity/bounds. 275 */ 276 if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { 277 error = ENOEXEC; 278 goto cleanup; 279 } 280 281 /* text + data can't exceed file size */ 282 if (a_out->a_data + a_out->a_text > attr.va_size) { 283 error = EFAULT; 284 goto cleanup; 285 } 286 287 /* 288 * text/data/bss must not exceed limits 289 * XXX: this is not complete. it should check current usage PLUS 290 * the resources needed by this library. 291 */ 292 if (a_out->a_text > MAXTSIZ || 293 a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) { 294 error = ENOMEM; 295 goto cleanup; 296 } 297 298 /* 299 * prevent more writers 300 */ 301 vp->v_flag |= VTEXT; 302 303 /* 304 * Check if file_offset page aligned,. 305 * Currently we cannot handle misalinged file offsets, 306 * and so we read in the entire image (what a waste). 307 */ 308 if (file_offset & PAGE_MASK) { 309#ifdef DEBUG 310printf("uselib: Non page aligned binary %lu\n", file_offset); 311#endif 312 /* 313 * Map text+data read/write/execute 314 */ 315 316 /* a_entry is the load address and is page aligned */ 317 vmaddr = trunc_page(a_out->a_entry); 318 319 /* get anon user mapping, read+write+execute */ 320 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, 321 a_out->a_text + a_out->a_data, FALSE, 322 VM_PROT_ALL, VM_PROT_ALL, 0); 323 if (error) 324 goto cleanup; 325 326 /* map file into kernel_map */ 327 error = vm_mmap(kernel_map, &buffer, 328 round_page(a_out->a_text + a_out->a_data + file_offset), 329 VM_PROT_READ, VM_PROT_READ, 0, 330 (caddr_t)vp, trunc_page(file_offset)); 331 if (error) 332 goto cleanup; 333 334 /* copy from kernel VM space to user space */ 335 error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr, 336 a_out->a_text + a_out->a_data); 337 338 /* release temporary kernel space */ 339 vm_map_remove(kernel_map, buffer, 340 buffer + round_page(a_out->a_text + a_out->a_data + file_offset)); 341 342 if (error) 343 goto cleanup; 344 } 345 else { 346#ifdef DEBUG 347printf("uselib: Page aligned binary %lu\n", file_offset); 348#endif 349 /* 350 * for QMAGIC, a_entry is 20 bytes beyond the load address 351 * to skip the executable header 352 */ 353 vmaddr = trunc_page(a_out->a_entry); 354 355 /* 356 * Map it all into the process's space as a single copy-on-write 357 * "data" segment. 358 */ 359 error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr, 360 a_out->a_text + a_out->a_data, 361 VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, 362 (caddr_t)vp, file_offset); 363 if (error) 364 goto cleanup; 365 } 366#ifdef DEBUG 367printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]); 368#endif 369 if (bss_size != 0) { 370 /* 371 * Calculate BSS start address 372 */ 373 vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data; 374 375 /* 376 * allocate some 'anon' space 377 */ 378 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, 379 bss_size, FALSE, 380 VM_PROT_ALL, VM_PROT_ALL, 0); 381 if (error) 382 goto cleanup; 383 } 384 385cleanup: 386 /* 387 * Unlock vnode if needed 388 */ 389 if (locked) 390 VOP_UNLOCK(vp, 0, p); 391 392 /* 393 * Release the kernel mapping. 394 */ 395 if (a_out) 396 vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE); 397 398 return error; 399} 400 401/* XXX move */ 402struct linux_select_argv { 403 int nfds; 404 fd_set *readfds; 405 fd_set *writefds; 406 fd_set *exceptfds; 407 struct timeval *timeout; 408}; 409 410int 411linux_select(struct proc *p, struct linux_select_args *args) 412{ 413 struct linux_select_argv linux_args; 414 struct linux_newselect_args newsel; 415 int error; 416 417#ifdef SELECT_DEBUG 418 printf("Linux-emul(%d): select(%x)\n", 419 p->p_pid, args->ptr); 420#endif 421 if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, 422 sizeof(linux_args)))) 423 return error; 424 425 newsel.nfds = linux_args.nfds; 426 newsel.readfds = linux_args.readfds; 427 newsel.writefds = linux_args.writefds; 428 newsel.exceptfds = linux_args.exceptfds; 429 newsel.timeout = linux_args.timeout; 430 431 return linux_newselect(p, &newsel); 432} 433 434int 435linux_newselect(struct proc *p, struct linux_newselect_args *args) 436{ 437 struct select_args bsa; 438 struct timeval tv0, tv1, utv, *tvp; 439 caddr_t sg; 440 int error; 441 442#ifdef DEBUG 443 printf("Linux-emul(%ld): newselect(%d, %p, %p, %p, %p)\n", 444 (long)p->p_pid, args->nfds, (void *)args->readfds, 445 (void *)args->writefds, (void *)args->exceptfds, 446 (void *)args->timeout); 447#endif 448 error = 0; 449 bsa.nd = args->nfds; 450 bsa.in = args->readfds; 451 bsa.ou = args->writefds; 452 bsa.ex = args->exceptfds; 453 bsa.tv = args->timeout; 454 455 /* 456 * Store current time for computation of the amount of 457 * time left. 458 */ 459 if (args->timeout) { 460 if ((error = copyin(args->timeout, &utv, sizeof(utv)))) 461 goto select_out; 462#ifdef DEBUG 463 printf("Linux-emul(%ld): incoming timeout (%ld/%ld)\n", 464 (long)p->p_pid, utv.tv_sec, utv.tv_usec); 465#endif 466 if (itimerfix(&utv)) { 467 /* 468 * The timeval was invalid. Convert it to something 469 * valid that will act as it does under Linux. 470 */ 471 sg = stackgap_init(); 472 tvp = stackgap_alloc(&sg, sizeof(utv)); 473 utv.tv_sec += utv.tv_usec / 1000000; 474 utv.tv_usec %= 1000000; 475 if (utv.tv_usec < 0) { 476 utv.tv_sec -= 1; 477 utv.tv_usec += 1000000; 478 } 479 if (utv.tv_sec < 0) 480 timevalclear(&utv); 481 if ((error = copyout(&utv, tvp, sizeof(utv)))) 482 goto select_out; 483 bsa.tv = tvp; 484 } 485 microtime(&tv0); 486 } 487 488 error = select(p, &bsa); 489#ifdef DEBUG 490 printf("Linux-emul(%d): real select returns %d\n", 491 p->p_pid, error); 492#endif 493 494 if (error) { 495 /* 496 * See fs/select.c in the Linux kernel. Without this, 497 * Maelstrom doesn't work. 498 */ 499 if (error == ERESTART) 500 error = EINTR; 501 goto select_out; 502 } 503 504 if (args->timeout) { 505 if (p->p_retval[0]) { 506 /* 507 * Compute how much time was left of the timeout, 508 * by subtracting the current time and the time 509 * before we started the call, and subtracting 510 * that result from the user-supplied value. 511 */ 512 microtime(&tv1); 513 timevalsub(&tv1, &tv0); 514 timevalsub(&utv, &tv1); 515 if (utv.tv_sec < 0) 516 timevalclear(&utv); 517 } else 518 timevalclear(&utv); 519#ifdef DEBUG 520 printf("Linux-emul(%ld): outgoing timeout (%ld/%ld)\n", 521 (long)p->p_pid, utv.tv_sec, utv.tv_usec); 522#endif 523 if ((error = copyout(&utv, args->timeout, sizeof(utv)))) 524 goto select_out; 525 } 526 527select_out: 528#ifdef DEBUG 529 printf("Linux-emul(%d): newselect_out -> %d\n", 530 p->p_pid, error); 531#endif 532 return error; 533} 534 535int 536linux_getpgid(struct proc *p, struct linux_getpgid_args *args) 537{ 538 struct proc *curproc; 539 540#ifdef DEBUG 541 printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid); 542#endif 543 if (args->pid != p->p_pid) { 544 if (!(curproc = pfind(args->pid))) 545 return ESRCH; 546 } 547 else 548 curproc = p; 549 p->p_retval[0] = curproc->p_pgid; 550 return 0; 551} 552 553int 554linux_fork(struct proc *p, struct linux_fork_args *args) 555{ 556 int error; 557 558#ifdef DEBUG 559 printf("Linux-emul(%d): fork()\n", p->p_pid); 560#endif 561 if (error = fork(p, (struct fork_args *)args)) 562 return error; 563 if (p->p_retval[1] == 1) 564 p->p_retval[0] = 0; 565 return 0; 566} 567 568/* XXX move */ 569struct linux_mmap_argv { 570 linux_caddr_t addr; 571 int len; 572 int prot; 573 int flags; 574 int fd; 575 int pos; 576}; 577 578int 579linux_mmap(struct proc *p, struct linux_mmap_args *args) 580{ 581 struct mmap_args /* { 582 caddr_t addr; 583 size_t len; 584 int prot; 585 int flags; 586 int fd; 587 long pad; 588 off_t pos; 589 } */ bsd_args; 590 int error; 591 struct linux_mmap_argv linux_args; 592 593 if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, 594 sizeof(linux_args)))) 595 return error; 596#ifdef DEBUG 597 printf("Linux-emul(%ld): mmap(%p, %d, %d, %08x, %d, %d)\n", 598 (long)p->p_pid, (void *)linux_args.addr, linux_args.len, 599 linux_args.prot, linux_args.flags, linux_args.fd, linux_args.pos); 600#endif 601 bsd_args.flags = 0; 602 if (linux_args.flags & LINUX_MAP_SHARED) 603 bsd_args.flags |= MAP_SHARED; 604 if (linux_args.flags & LINUX_MAP_PRIVATE) 605 bsd_args.flags |= MAP_PRIVATE; 606 if (linux_args.flags & LINUX_MAP_FIXED) 607 bsd_args.flags |= MAP_FIXED; 608 if (linux_args.flags & LINUX_MAP_ANON) 609 bsd_args.flags |= MAP_ANON; 610 bsd_args.addr = linux_args.addr; 611 bsd_args.len = linux_args.len; 612 bsd_args.prot = linux_args.prot | PROT_READ; /* always required */ 613 bsd_args.fd = linux_args.fd; 614 bsd_args.pos = linux_args.pos; 615 bsd_args.pad = 0; 616 return mmap(p, &bsd_args); 617} 618 619int 620linux_mremap(struct proc *p, struct linux_mremap_args *args) 621{ 622 struct munmap_args /* { 623 void *addr; 624 size_t len; 625 } */ bsd_args; 626 int error = 0; 627 628#ifdef DEBUG 629 printf("Linux-emul(%ld): mremap(%p, %08x, %08x, %08x)\n", 630 (long)p->p_pid, (void *)args->addr, args->old_len, args->new_len, 631 args->flags); 632#endif 633 args->new_len = round_page(args->new_len); 634 args->old_len = round_page(args->old_len); 635 636 if (args->new_len > args->old_len) { 637 p->p_retval[0] = 0; 638 return ENOMEM; 639 } 640 641 if (args->new_len < args->old_len) { 642 bsd_args.addr = args->addr + args->new_len; 643 bsd_args.len = args->old_len - args->new_len; 644 error = munmap(p, &bsd_args); 645 } 646 647 p->p_retval[0] = error ? 0 : (int)args->addr; 648 return error; 649} 650 651int 652linux_msync(struct proc *p, struct linux_msync_args *args) 653{ 654 struct msync_args bsd_args; 655 656 bsd_args.addr = args->addr; 657 bsd_args.len = args->len; 658 bsd_args.flags = 0; /* XXX ignore */ 659 660 return msync(p, &bsd_args); 661} 662 663int 664linux_pipe(struct proc *p, struct linux_pipe_args *args) 665{ 666 int error; 667 668#ifdef DEBUG 669 printf("Linux-emul(%d): pipe(*)\n", p->p_pid); 670#endif 671 if (error = pipe(p, 0)) 672 return error; 673 if (error = copyout(p->p_retval, args->pipefds, 2*sizeof(int))) 674 return error; 675 p->p_retval[0] = 0; 676 return 0; 677} 678 679int 680linux_time(struct proc *p, struct linux_time_args *args) 681{ 682 struct timeval tv; 683 linux_time_t tm; 684 int error; 685 686#ifdef DEBUG 687 printf("Linux-emul(%d): time(*)\n", p->p_pid); 688#endif 689 microtime(&tv); 690 tm = tv.tv_sec; 691 if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t)))) 692 return error; 693 p->p_retval[0] = tm; 694 return 0; 695} 696 697struct linux_times_argv { 698 long tms_utime; 699 long tms_stime; 700 long tms_cutime; 701 long tms_cstime; 702}; 703 704#define CLK_TCK 100 /* Linux uses 100 */ 705#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 706 707int 708linux_times(struct proc *p, struct linux_times_args *args) 709{ 710 struct timeval tv; 711 struct linux_times_argv tms; 712 struct rusage ru; 713 int error; 714 715#ifdef DEBUG 716 printf("Linux-emul(%d): times(*)\n", p->p_pid); 717#endif 718 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL); 719 720 tms.tms_utime = CONVTCK(ru.ru_utime); 721 tms.tms_stime = CONVTCK(ru.ru_stime); 722 723 tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 724 tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 725 726 if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf, 727 sizeof(struct linux_times_argv)))) 728 return error; 729 730 microuptime(&tv); 731 p->p_retval[0] = (int)CONVTCK(tv); 732 return 0; 733} 734 735/* XXX move */ 736struct linux_newuname_t { 737 char sysname[65]; 738 char nodename[65]; 739 char release[65]; 740 char version[65]; 741 char machine[65]; 742 char domainname[65]; 743}; 744 745int 746linux_newuname(struct proc *p, struct linux_newuname_args *args) 747{ 748 struct linux_newuname_t linux_newuname; 749 750#ifdef DEBUG 751 printf("Linux-emul(%d): newuname(*)\n", p->p_pid); 752#endif 753 bzero(&linux_newuname, sizeof(struct linux_newuname_args)); 754 strncpy(linux_newuname.sysname, ostype, 64); 755 strncpy(linux_newuname.nodename, hostname, 64); 756 strncpy(linux_newuname.release, osrelease, 64); 757 strncpy(linux_newuname.version, version, 64); 758 strncpy(linux_newuname.machine, machine, 64); 759 strncpy(linux_newuname.domainname, domainname, 64); 760 return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf, 761 sizeof(struct linux_newuname_t))); 762} 763 764struct linux_utimbuf { 765 linux_time_t l_actime; 766 linux_time_t l_modtime; 767}; 768 769int 770linux_utime(struct proc *p, struct linux_utime_args *args) 771{ 772 struct utimes_args /* { 773 char *path; 774 struct timeval *tptr; 775 } */ bsdutimes; 776 struct timeval tv[2], *tvp; 777 struct linux_utimbuf lut; 778 int error; 779 caddr_t sg; 780 781 sg = stackgap_init(); 782 CHECKALTEXIST(p, &sg, args->fname); 783 784#ifdef DEBUG 785 printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname); 786#endif 787 if (args->times) { 788 if ((error = copyin(args->times, &lut, sizeof lut))) 789 return error; 790 tv[0].tv_sec = lut.l_actime; 791 tv[0].tv_usec = 0; 792 tv[1].tv_sec = lut.l_modtime; 793 tv[1].tv_usec = 0; 794 /* so that utimes can copyin */ 795 tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv)); 796 if ((error = copyout(tv, tvp, sizeof(tv)))) 797 return error; 798 bsdutimes.tptr = tvp; 799 } else 800 bsdutimes.tptr = NULL; 801 802 bsdutimes.path = args->fname; 803 return utimes(p, &bsdutimes); 804} 805 806int 807linux_waitpid(struct proc *p, struct linux_waitpid_args *args) 808{ 809 struct wait_args /* { 810 int pid; 811 int *status; 812 int options; 813 struct rusage *rusage; 814 } */ tmp; 815 int error, tmpstat; 816 817#ifdef DEBUG 818 printf("Linux-emul(%ld): waitpid(%d, %p, %d)\n", 819 (long)p->p_pid, args->pid, (void *)args->status, args->options); 820#endif 821 tmp.pid = args->pid; 822 tmp.status = args->status; 823 tmp.options = args->options; 824 tmp.rusage = NULL; 825 826 if (error = wait4(p, &tmp)) 827 return error; 828 if (args->status) { 829 if (error = copyin(args->status, &tmpstat, sizeof(int))) 830 return error; 831 if (WIFSIGNALED(tmpstat)) 832 tmpstat = (tmpstat & 0xffffff80) | 833 bsd_to_linux_signal[WTERMSIG(tmpstat)]; 834 else if (WIFSTOPPED(tmpstat)) 835 tmpstat = (tmpstat & 0xffff00ff) | 836 (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); 837 return copyout(&tmpstat, args->status, sizeof(int)); 838 } else 839 return 0; 840} 841 842int 843linux_wait4(struct proc *p, struct linux_wait4_args *args) 844{ 845 struct wait_args /* { 846 int pid; 847 int *status; 848 int options; 849 struct rusage *rusage; 850 } */ tmp; 851 int error, tmpstat; 852 853#ifdef DEBUG 854 printf("Linux-emul(%ld): wait4(%d, %p, %d, %p)\n", 855 (long)p->p_pid, args->pid, (void *)args->status, args->options, 856 (void *)args->rusage); 857#endif 858 tmp.pid = args->pid; 859 tmp.status = args->status; 860 tmp.options = args->options; 861 tmp.rusage = args->rusage; 862 863 if (error = wait4(p, &tmp)) 864 return error; 865 866 p->p_siglist &= ~sigmask(SIGCHLD); 867 868 if (args->status) { 869 if (error = copyin(args->status, &tmpstat, sizeof(int))) 870 return error; 871 if (WIFSIGNALED(tmpstat)) 872 tmpstat = (tmpstat & 0xffffff80) | 873 bsd_to_linux_signal[WTERMSIG(tmpstat)]; 874 else if (WIFSTOPPED(tmpstat)) 875 tmpstat = (tmpstat & 0xffff00ff) | 876 (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); 877 return copyout(&tmpstat, args->status, sizeof(int)); 878 } else 879 return 0; 880} 881 882int 883linux_mknod(struct proc *p, struct linux_mknod_args *args) 884{ 885 caddr_t sg; 886 struct mknod_args bsd_mknod; 887 struct mkfifo_args bsd_mkfifo; 888 889 sg = stackgap_init(); 890 891 CHECKALTCREAT(p, &sg, args->path); 892 893#ifdef DEBUG 894 printf("Linux-emul(%d): mknod(%s, %d, %d)\n", 895 p->p_pid, args->path, args->mode, args->dev); 896#endif 897 898 if (args->mode & S_IFIFO) { 899 bsd_mkfifo.path = args->path; 900 bsd_mkfifo.mode = args->mode; 901 return mkfifo(p, &bsd_mkfifo); 902 } else { 903 bsd_mknod.path = args->path; 904 bsd_mknod.mode = args->mode; 905 bsd_mknod.dev = args->dev; 906 return mknod(p, &bsd_mknod); 907 } 908} 909 910/* 911 * UGH! This is just about the dumbest idea I've ever heard!! 912 */ 913int 914linux_personality(struct proc *p, struct linux_personality_args *args) 915{ 916#ifdef DEBUG 917 printf("Linux-emul(%d): personality(%d)\n", 918 p->p_pid, args->per); 919#endif 920 if (args->per != 0) 921 return EINVAL; 922 923 /* Yes Jim, it's still a Linux... */ 924 p->p_retval[0] = 0; 925 return 0; 926} 927 928/* 929 * Wrappers for get/setitimer for debugging.. 930 */ 931int 932linux_setitimer(struct proc *p, struct linux_setitimer_args *args) 933{ 934 struct setitimer_args bsa; 935 struct itimerval foo; 936 int error; 937 938#ifdef DEBUG 939 printf("Linux-emul(%ld): setitimer(%p, %p)\n", 940 (long)p->p_pid, (void *)args->itv, (void *)args->oitv); 941#endif 942 bsa.which = args->which; 943 bsa.itv = args->itv; 944 bsa.oitv = args->oitv; 945 if (args->itv) { 946 if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo, 947 sizeof(foo)))) 948 return error; 949#ifdef DEBUG 950 printf("setitimer: value: sec: %ld, usec: %ld\n", 951 foo.it_value.tv_sec, foo.it_value.tv_usec); 952 printf("setitimer: interval: sec: %ld, usec: %ld\n", 953 foo.it_interval.tv_sec, foo.it_interval.tv_usec); 954#endif 955 } 956 return setitimer(p, &bsa); 957} 958 959int 960linux_getitimer(struct proc *p, struct linux_getitimer_args *args) 961{ 962 struct getitimer_args bsa; 963#ifdef DEBUG 964 printf("Linux-emul(%ld): getitimer(%p)\n", 965 (long)p->p_pid, (void *)args->itv); 966#endif 967 bsa.which = args->which; 968 bsa.itv = args->itv; 969 return getitimer(p, &bsa); 970} 971 972int 973linux_iopl(struct proc *p, struct linux_iopl_args *args) 974{ 975 int error; 976 977 error = suser(p->p_ucred, &p->p_acflag); 978 if (error != 0) 979 return error; 980 if (securelevel > 0) 981 return EPERM; 982 p->p_md.md_regs->tf_eflags |= PSL_IOPL; 983 return 0; 984} 985 986int 987linux_nice(struct proc *p, struct linux_nice_args *args) 988{ 989 struct setpriority_args bsd_args; 990 991 bsd_args.which = PRIO_PROCESS; 992 bsd_args.who = 0; /* current process */ 993 bsd_args.prio = args->inc; 994 return setpriority(p, &bsd_args); 995} 996 997