|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1988 University of Utah. ! 24: * Copyright (c) 1991, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * ! 27: * This code is derived from software contributed to Berkeley by ! 28: * the Systems Programming Group of the University of Utah Computer ! 29: * Science Department. ! 30: * ! 31: * Redistribution and use in source and binary forms, with or without ! 32: * modification, are permitted provided that the following conditions ! 33: * are met: ! 34: * 1. Redistributions of source code must retain the above copyright ! 35: * notice, this list of conditions and the following disclaimer. ! 36: * 2. Redistributions in binary form must reproduce the above copyright ! 37: * notice, this list of conditions and the following disclaimer in the ! 38: * documentation and/or other materials provided with the distribution. ! 39: * 3. All advertising materials mentioning features or use of this software ! 40: * must display the following acknowledgement: ! 41: * This product includes software developed by the University of ! 42: * California, Berkeley and its contributors. ! 43: * 4. Neither the name of the University nor the names of its contributors ! 44: * may be used to endorse or promote products derived from this software ! 45: * without specific prior written permission. ! 46: * ! 47: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 48: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 49: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 50: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 51: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 52: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 53: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 54: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 55: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 56: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 57: * SUCH DAMAGE. ! 58: * ! 59: * from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$ ! 60: * ! 61: * @(#)vm_mmap.c 8.10 (Berkeley) 2/19/95 ! 62: */ ! 63: ! 64: /* ! 65: * Mapped file (mmap) interface to VM ! 66: */ ! 67: ! 68: #include <sys/param.h> ! 69: #include <sys/systm.h> ! 70: #include <sys/filedesc.h> ! 71: #include <sys/proc.h> ! 72: #include <sys/resourcevar.h> ! 73: #include <sys/buf.h> ! 74: #include <sys/vnode.h> ! 75: #include <sys/acct.h> ! 76: #include <sys/wait.h> ! 77: #include <sys/file.h> ! 78: #include <sys/vadvise.h> ! 79: #include <sys/trace.h> ! 80: #include <sys/mman.h> ! 81: #include <sys/conf.h> ! 82: #include <sys/stat.h> ! 83: ! 84: #include <mach/mach_types.h> ! 85: ! 86: #include <kern/cpu_number.h> ! 87: ! 88: #include <vm/vm_map.h> ! 89: #include <vm/vm_kern.h> ! 90: #include <vm/vm_pager.h> ! 91: #include <vm/vnode_pager.h> ! 92: #include <kern/mapfs.h> ! 93: ! 94: #include <mach/vm_sync.h> ! 95: #include <mach/vm_behavior.h> ! 96: #include <mach/vm_inherit.h> ! 97: #include <mach/vm_statistics.h> ! 98: ! 99: struct sbrk_args { ! 100: int incr; ! 101: }; ! 102: ! 103: /* ARGSUSED */ ! 104: int ! 105: sbrk(p, uap, retval) ! 106: struct proc *p; ! 107: struct sbrk_args *uap; ! 108: register_t *retval; ! 109: { ! 110: /* Not yet implemented */ ! 111: return (EOPNOTSUPP); ! 112: } ! 113: ! 114: struct sstk_args { ! 115: int incr; ! 116: } *uap; ! 117: ! 118: /* ARGSUSED */ ! 119: int ! 120: sstk(p, uap, retval) ! 121: struct proc *p; ! 122: struct sstk_args *uap; ! 123: register_t *retval; ! 124: { ! 125: /* Not yet implemented */ ! 126: return (EOPNOTSUPP); ! 127: } ! 128: ! 129: #if COMPAT_43 ! 130: /* ARGSUSED */ ! 131: int ! 132: ogetpagesize(p, uap, retval) ! 133: struct proc *p; ! 134: void *uap; ! 135: register_t *retval; ! 136: { ! 137: ! 138: *retval = PAGE_SIZE; ! 139: return (0); ! 140: } ! 141: #endif /* COMPAT_43 */ ! 142: ! 143: struct osmmap_args { ! 144: caddr_t addr; ! 145: int len; ! 146: int prot; ! 147: int share; ! 148: int fd; ! 149: long pos; ! 150: }; ! 151: ! 152: osmmap(curp, uap, retval) ! 153: struct proc *curp; ! 154: register struct osmmap_args *uap; ! 155: register_t *retval; ! 156: { ! 157: struct mmap_args { ! 158: caddr_t addr; ! 159: size_t len; ! 160: int prot; ! 161: int flags; ! 162: int fd; ! 163: #ifdef DOUBLE_ALIGN_PARAMS ! 164: long pad; ! 165: #endif ! 166: off_t pos; ! 167: } newargs; ! 168: ! 169: if ((uap->share == MAP_SHARED )|| (uap->share == MAP_PRIVATE )) { ! 170: newargs.addr = uap->addr; ! 171: newargs.len = (size_t)uap->len; ! 172: newargs.prot = uap->prot; ! 173: newargs.flags = uap->share; ! 174: newargs.fd = uap->fd; ! 175: newargs.pos = (off_t)uap->pos; ! 176: return(mmap(curp,&newargs, retval)); ! 177: } else ! 178: return(EINVAL); ! 179: } ! 180: ! 181: struct mmap_args { ! 182: caddr_t addr; ! 183: size_t len; ! 184: int prot; ! 185: int flags; ! 186: int fd; ! 187: #ifdef DOUBLE_ALIGN_PARAMS ! 188: long pad; ! 189: #endif ! 190: off_t pos; ! 191: }; ! 192: int ! 193: mmap(p, uap, retval) ! 194: struct proc *p; ! 195: struct mmap_args *uap; ! 196: register_t *retval; ! 197: { ! 198: /* ! 199: * Map in special device (must be SHARED) or file ! 200: */ ! 201: struct file *fp; ! 202: register struct vnode *vp; ! 203: int flags; ! 204: int prot; ! 205: int err=0; ! 206: vm_map_t user_map; ! 207: kern_return_t result; ! 208: vm_offset_t user_addr; ! 209: vm_size_t user_size, pageoff; ! 210: vm_offset_t file_pos; ! 211: boolean_t find_space, docow; ! 212: vm_prot_t maxprot; ! 213: void *handle; ! 214: vm_pager_t pager; ! 215: struct vm_info *vmp; ! 216: int mapanon=0; ! 217: ! 218: user_addr = (vm_offset_t)uap->addr; ! 219: user_size = (vm_size_t) uap->len; ! 220: prot = (uap->prot & VM_PROT_ALL); ! 221: flags = uap->flags; ! 222: ! 223: /* ! 224: * The vm code does not have prototypes & compiler doesn't do the' ! 225: * the right thing when you cast 64bit value and pass it in function ! 226: * call. So here it is. ! 227: */ ! 228: file_pos = (vm_offset_t)uap->pos; ! 229: ! 230: ! 231: /* make sure mapping fits into numeric range etc */ ! 232: if ((file_pos + user_size > (vm_offset_t)-PAGE_SIZE) || ! 233: ((ssize_t) uap->len < 0 )|| ! 234: ((flags & MAP_ANON) && uap->fd != -1)) ! 235: return (EINVAL); ! 236: ! 237: /* ! 238: * Align the file position to a page boundary, ! 239: * and save its page offset component. ! 240: */ ! 241: pageoff = (file_pos & PAGE_MASK); ! 242: file_pos -= pageoff; ! 243: ! 244: ! 245: /* Adjust size for rounding (on both ends). */ ! 246: user_size += pageoff; /* low end... */ ! 247: user_size = (vm_size_t) round_page(user_size); /* hi end */ ! 248: ! 249: ! 250: /* ! 251: * Check for illegal addresses. Watch out for address wrap... Note ! 252: * that VM_*_ADDRESS are not constants due to casts (argh). ! 253: */ ! 254: if (flags & MAP_FIXED) { ! 255: /* ! 256: * The specified address must have the same remainder ! 257: * as the file offset taken modulo PAGE_SIZE, so it ! 258: * should be aligned after adjustment by pageoff. ! 259: */ ! 260: user_addr -= pageoff; ! 261: if (user_addr & PAGE_MASK) ! 262: return (EINVAL); ! 263: /* Address range must be all in user VM space. */ ! 264: if (VM_MAX_ADDRESS > 0 && (user_addr + user_size > VM_MAX_ADDRESS)) ! 265: return (EINVAL); ! 266: if (VM_MIN_ADDRESS > 0 && user_addr < VM_MIN_ADDRESS) ! 267: return (EINVAL); ! 268: if (user_addr + user_size < user_addr) ! 269: return (EINVAL); ! 270: } ! 271: #ifdef notyet ! 272: /* DO not have apis to get this info, need to wait till then*/ ! 273: /* ! 274: * XXX for non-fixed mappings where no hint is provided or ! 275: * the hint would fall in the potential heap space, ! 276: * place it after the end of the largest possible heap. ! 277: * ! 278: * There should really be a pmap call to determine a reasonable ! 279: * location. ! 280: */ ! 281: else if (addr < round_page(p->p_vmspace->vm_daddr + MAXDSIZ)) ! 282: addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); ! 283: ! 284: #endif ! 285: ! 286: ! 287: if (flags & MAP_ANON) { ! 288: /* ! 289: * Mapping blank space is trivial. ! 290: */ ! 291: handle = NULL; ! 292: maxprot = VM_PROT_ALL; ! 293: file_pos = 0; ! 294: mapanon = 1; ! 295: } else { ! 296: /* ! 297: * Mapping file, get fp for validation. Obtain vnode and make ! 298: * sure it is of appropriate type. ! 299: */ ! 300: err = fdgetf(p, uap->fd, &fp); ! 301: if (err) ! 302: return(err); ! 303: if(fp->f_type == DTYPE_PSXSHM) { ! 304: uap->addr = user_addr; ! 305: uap->len = user_size; ! 306: uap->prot = prot; ! 307: uap->flags = flags; ! 308: uap->pos = file_pos; ! 309: return(pshm_mmap(p, uap, retval, fp , pageoff)); ! 310: } ! 311: ! 312: if (fp->f_type != DTYPE_VNODE) ! 313: return(EINVAL); ! 314: vp = (struct vnode *)fp->f_data; ! 315: ! 316: if (vp->v_type != VREG && vp->v_type != VCHR) ! 317: return (EINVAL); ! 318: /* ! 319: * XXX hack to handle use of /dev/zero to map anon memory (ala ! 320: * SunOS). ! 321: */ ! 322: if (vp->v_type == VCHR || vp->v_type == VSTR) { ! 323: return(EOPNOTSUPP); ! 324: } else { ! 325: /* ! 326: * Ensure that file and memory protections are ! 327: * compatible. Note that we only worry about ! 328: * writability if mapping is shared; in this case, ! 329: * current and max prot are dictated by the open file. ! 330: * XXX use the vnode instead? Problem is: what ! 331: * credentials do we use for determination? What if ! 332: * proc does a setuid? ! 333: */ ! 334: maxprot = VM_PROT_EXECUTE; /* ??? */ ! 335: if (fp->f_flag & FREAD) ! 336: maxprot |= VM_PROT_READ; ! 337: else if (prot & PROT_READ) ! 338: return (EACCES); ! 339: /* ! 340: * If we are sharing potential changes (either via ! 341: * MAP_SHARED or via the implicit sharing of character ! 342: * device mappings), and we are trying to get write ! 343: * permission although we opened it without asking ! 344: * for it, bail out. ! 345: */ ! 346: ! 347: if ((flags & MAP_SHARED) != 0) { ! 348: if ((fp->f_flag & FWRITE) != 0) { ! 349: struct vattr va; ! 350: if ((err = ! 351: VOP_GETATTR(vp, &va, ! 352: p->p_ucred, p))) ! 353: return (err); ! 354: if ((va.va_flags & ! 355: (IMMUTABLE|APPEND)) == 0) ! 356: maxprot |= VM_PROT_WRITE; ! 357: else if (prot & PROT_WRITE) ! 358: return (EPERM); ! 359: } else if ((prot & PROT_WRITE) != 0) ! 360: return (EACCES); ! 361: } else ! 362: maxprot |= VM_PROT_WRITE; ! 363: ! 364: handle = (void *)vp; ! 365: } ! 366: } ! 367: ! 368: if (user_size == 0) ! 369: return(0); ! 370: ! 371: /* ! 372: * We bend a little - round the start and end addresses ! 373: * to the nearest page boundary. ! 374: */ ! 375: user_size = round_page(user_size); ! 376: ! 377: if (file_pos & PAGE_MASK) ! 378: return (EINVAL); ! 379: ! 380: user_map = current_map(); ! 381: ! 382: if ((flags & MAP_FIXED) == 0) { ! 383: find_space = TRUE; ! 384: user_addr = round_page(user_addr); ! 385: } else { ! 386: if (user_addr != trunc_page(user_addr)) ! 387: return (EINVAL); ! 388: find_space = FALSE; ! 389: (void) vm_deallocate(user_map, user_addr, user_size); ! 390: } ! 391: ! 392: ! 393: /* ! 394: * Lookup/allocate object. ! 395: */ ! 396: if (flags & MAP_ANON) { ! 397: /* ! 398: * Unnamed anonymous regions always start at 0. ! 399: */ ! 400: if (handle == 0) ! 401: file_pos = 0; ! 402: } ! 403: ! 404: if (handle == NULL) { ! 405: pager = NULL; ! 406: #ifdef notyet ! 407: /* Hmm .. */ ! 408: #if defined(VM_PROT_READ_IS_EXEC) ! 409: if (prot & VM_PROT_READ) ! 410: prot |= VM_PROT_EXECUTE; ! 411: ! 412: if (maxprot & VM_PROT_READ) ! 413: maxprot |= VM_PROT_EXECUTE; ! 414: #endif ! 415: #endif ! 416: result = vm_allocate(user_map, &user_addr, user_size, find_space); ! 417: if (result != KERN_SUCCESS) ! 418: goto out; ! 419: ! 420: } else { ! 421: if (!vp->v_vm_info) { ! 422: vm_info_init(vp); ! 423: } ! 424: pager = vnode_pager_setup(vp, ! 425: vp->v_vm_info->pager, FALSE, FALSE); ! 426: ! 427: if (pager == NULL) ! 428: return (ENOMEM); ! 429: /* ! 430: * Set credentials: ! 431: * FIXME: if we're writing the file we need a way to ! 432: * ensure that someone doesn't replace our R/W creds ! 433: * with ones that only work for read. ! 434: */ ! 435: vmp = vp->v_vm_info; ! 436: if (vmp->cred == NULL) { ! 437: crhold(p->p_ucred); ! 438: vmp->cred = p->p_ucred; ! 439: } ! 440: docow = FALSE; ! 441: if ((flags & (MAP_ANON|MAP_SHARED)) == 0) { ! 442: docow = TRUE; ! 443: } ! 444: ! 445: #ifdef notyet ! 446: /* Hmm .. */ ! 447: #if defined(VM_PROT_READ_IS_EXEC) ! 448: if (prot & VM_PROT_READ) ! 449: prot |= VM_PROT_EXECUTE; ! 450: ! 451: if (maxprot & VM_PROT_READ) ! 452: maxprot |= VM_PROT_EXECUTE; ! 453: #endif ! 454: #endif /* notyet */ ! 455: ! 456: result = vm_map(user_map, &user_addr, user_size, ! 457: 0, find_space, pager, file_pos, docow, ! 458: prot, maxprot, ! 459: VM_INHERIT_DEFAULT); ! 460: ! 461: if (result != KERN_SUCCESS) ! 462: goto out; ! 463: ! 464: } ! 465: ! 466: if (flags & (MAP_SHARED|MAP_INHERIT)) { ! 467: result = vm_inherit(user_map, user_addr, user_size, ! 468: VM_INHERIT_SHARE); ! 469: if (result != KERN_SUCCESS) { ! 470: (void) vm_deallocate(user_map, user_addr, user_size); ! 471: goto out; ! 472: } ! 473: } ! 474: ! 475: out: ! 476: switch (result) { ! 477: case KERN_SUCCESS: ! 478: if(!mapanon) { ! 479: *fdflags(p, uap->fd) |= UF_MAPPED; ! 480: if (ISMAPPABLEFILE(vp)) ! 481: vp->v_vm_info->mapped = 1; ! 482: } ! 483: *retval = (register_t)(user_addr + pageoff); ! 484: return (0); ! 485: case KERN_INVALID_ADDRESS: ! 486: case KERN_NO_SPACE: ! 487: return (ENOMEM); ! 488: case KERN_PROTECTION_FAILURE: ! 489: return (EACCES); ! 490: default: ! 491: return (EINVAL); ! 492: } ! 493: /*NOTREACHED*/ ! 494: } ! 495: ! 496: struct msync_args { ! 497: caddr_t addr; ! 498: int len; ! 499: int flags; ! 500: }; ! 501: int ! 502: msync(p, uap, retval) ! 503: struct proc *p; ! 504: struct msync_args *uap; ! 505: register_t *retval; ! 506: { ! 507: vm_offset_t addr; ! 508: vm_size_t size, pageoff; ! 509: int flags; ! 510: vm_map_t user_map; ! 511: int rv; ! 512: vm_sync_t sync_flags=0; ! 513: ! 514: addr = (vm_offset_t) uap->addr; ! 515: pageoff = (addr & PAGE_MASK); ! 516: addr -= pageoff; ! 517: size = uap->len; ! 518: size = (vm_size_t) round_page(size); ! 519: flags = uap->flags; ! 520: ! 521: if (addr + size < addr) ! 522: return(EINVAL); ! 523: ! 524: user_map = current_map(); ! 525: ! 526: if ((flags & (MS_ASYNC|MS_INVALIDATE)) == (MS_ASYNC|MS_INVALIDATE)) ! 527: return (EINVAL); ! 528: ! 529: #ifdef notyet ! 530: /* XXX Gak! If size is zero we are supposed to sync "all modified ! 531: * pages with the region containing addr". Unfortunately, we don't ! 532: * really keep track of individual mmaps so we approximate by flushing ! 533: * the range of the map entry containing addr. This can be incorrect ! 534: * if the region splits or is coalesced with a neighbor. ! 535: */ ! 536: if (size == 0) { ! 537: vm_map_entry_t entry; ! 538: ! 539: vm_map_lock_read(map); ! 540: rv = vm_map_lookup_entry(map, addr, &entry); ! 541: vm_map_unlock_read(map); ! 542: if (rv == FALSE) ! 543: return (EINVAL); ! 544: addr = entry->start; ! 545: size = entry->end - entry->start; ! 546: } ! 547: #endif /* notyet */ ! 548: ! 549: if (flags & MS_ASYNC) ! 550: sync_flags |= VM_SYNC_ASYNCHRONOUS; ! 551: else ! 552: sync_flags |= VM_SYNC_SYNCHRONOUS; ! 553: ! 554: if (flags & MS_INVALIDATE) ! 555: sync_flags |= VM_SYNC_INVALIDATE; ! 556: ! 557: rv = vm_msync(user_map, addr, size, sync_flags); ! 558: ! 559: switch (rv) { ! 560: case KERN_SUCCESS: ! 561: break; ! 562: case KERN_INVALID_ADDRESS: ! 563: return (EINVAL); /* Sun returns ENOMEM? */ ! 564: case KERN_FAILURE: ! 565: return (EIO); ! 566: default: ! 567: return (EINVAL); ! 568: } ! 569: ! 570: return (0); ! 571: ! 572: } ! 573: ! 574: ! 575: mremap() ! 576: { ! 577: /* Not yet implemented */ ! 578: return (EOPNOTSUPP); ! 579: } ! 580: ! 581: struct munmap_args { ! 582: caddr_t addr; ! 583: int len; ! 584: }; ! 585: munmap(p, uap, retval) ! 586: struct proc *p; ! 587: struct munmap_args *uap; ! 588: register_t *retval; ! 589: ! 590: { ! 591: vm_offset_t user_addr; ! 592: vm_size_t user_size, pageoff; ! 593: kern_return_t result; ! 594: ! 595: user_addr = (vm_offset_t) uap->addr; ! 596: user_size = (vm_size_t) uap->len; ! 597: ! 598: pageoff = (user_addr & PAGE_MASK); ! 599: ! 600: user_addr -= pageoff; ! 601: user_size += pageoff; ! 602: user_size = round_page(user_size); ! 603: if (user_addr + user_size < user_addr) ! 604: return(EINVAL); ! 605: ! 606: if (user_size == 0) ! 607: return (0); ! 608: ! 609: /* Address range must be all in user VM space. */ ! 610: if (VM_MAX_ADDRESS > 0 && (user_addr + user_size > VM_MAX_ADDRESS)) ! 611: return (EINVAL); ! 612: if (VM_MIN_ADDRESS > 0 && user_addr < VM_MIN_ADDRESS) ! 613: return (EINVAL); ! 614: ! 615: ! 616: result = vm_deallocate(current_map(), user_addr, user_size); ! 617: if (result != KERN_SUCCESS) { ! 618: return(EINVAL); ! 619: } ! 620: return(0); ! 621: } ! 622: ! 623: void ! 624: munmapfd(p, fd) ! 625: struct proc *p; ! 626: int fd; ! 627: { ! 628: /* ! 629: * XXX should vm_deallocate any regions mapped to this file ! 630: */ ! 631: *fdflags(p, fd) &= ~UF_MAPPED; ! 632: } ! 633: ! 634: struct mprotect_args { ! 635: caddr_t addr; ! 636: int len; ! 637: int prot; ! 638: }; ! 639: int ! 640: mprotect(p, uap, retval) ! 641: struct proc *p; ! 642: struct mprotect_args *uap; ! 643: register_t *retval; ! 644: { ! 645: register vm_prot_t prot; ! 646: vm_offset_t user_addr; ! 647: vm_size_t user_size, pageoff; ! 648: kern_return_t result; ! 649: vm_map_t user_map; ! 650: ! 651: user_addr = (vm_offset_t) uap->addr; ! 652: user_size = (vm_size_t) uap->len; ! 653: prot = (vm_prot_t)(uap->prot & VM_PROT_ALL); ! 654: ! 655: #ifdef notyet ! 656: /* Hmm .. */ ! 657: #if defined(VM_PROT_READ_IS_EXEC) ! 658: if (prot & VM_PROT_READ) ! 659: prot |= VM_PROT_EXECUTE; ! 660: #endif ! 661: #endif /* notyet */ ! 662: ! 663: pageoff = (user_addr & PAGE_MASK); ! 664: user_addr -= pageoff; ! 665: user_size += pageoff; ! 666: user_size = round_page(user_size); ! 667: if (user_addr + user_size < user_addr) ! 668: return(EINVAL); ! 669: ! 670: user_map = current_map(); ! 671: ! 672: result = vm_map_protect(user_map, user_addr, user_addr+user_size, prot, ! 673: FALSE); ! 674: switch (result) { ! 675: case KERN_SUCCESS: ! 676: return (0); ! 677: case KERN_PROTECTION_FAILURE: ! 678: return (EACCES); ! 679: } ! 680: return (EINVAL); ! 681: } ! 682: ! 683: ! 684: struct minherit_args { ! 685: void *addr; ! 686: size_t len; ! 687: int inherit; ! 688: }; ! 689: ! 690: int ! 691: minherit(p, uap, retval) ! 692: struct proc *p; ! 693: struct minherit_args *uap; ! 694: register_t *retval; ! 695: { ! 696: vm_offset_t addr; ! 697: vm_size_t size, pageoff; ! 698: register vm_inherit_t inherit; ! 699: vm_map_t user_map; ! 700: kern_return_t result; ! 701: ! 702: addr = (vm_offset_t)uap->addr; ! 703: size = uap->len; ! 704: inherit = uap->inherit; ! 705: ! 706: pageoff = (addr & PAGE_MASK); ! 707: addr -= pageoff; ! 708: size += pageoff; ! 709: size = (vm_size_t) round_page(size); ! 710: if (addr + size < addr) ! 711: return(EINVAL); ! 712: ! 713: user_map = current_map(); ! 714: result = vm_inherit(user_map, addr, size, ! 715: inherit); ! 716: switch (result) { ! 717: case KERN_SUCCESS: ! 718: return (0); ! 719: case KERN_PROTECTION_FAILURE: ! 720: return (EACCES); ! 721: } ! 722: return (EINVAL); ! 723: } ! 724: ! 725: struct madvise_args { ! 726: caddr_t addr; ! 727: int len; ! 728: int behav; ! 729: }; ! 730: /* ARGSUSED */ ! 731: int ! 732: madvise(p, uap, retval) ! 733: struct proc *p; ! 734: struct madvise_args *uap; ! 735: register_t *retval; ! 736: { ! 737: vm_map_t user_map; ! 738: vm_offset_t start, end; ! 739: vm_behavior_t new_behavior; ! 740: kern_return_t result; ! 741: ! 742: /* ! 743: * Check for illegal addresses. Watch out for address wrap... Note ! 744: * that VM_*_ADDRESS are not constants due to casts (argh). ! 745: */ ! 746: if (VM_MAX_ADDRESS > 0 && ! 747: ((vm_offset_t) uap->addr + uap->len) > VM_MAX_ADDRESS) ! 748: return (EINVAL); ! 749: if (VM_MIN_ADDRESS > 0 && uap->addr < VM_MIN_ADDRESS) ! 750: return (EINVAL); ! 751: ! 752: if (((vm_offset_t) uap->addr + uap->len) < (vm_offset_t) uap->addr) ! 753: return (EINVAL); ! 754: ! 755: /* ! 756: * Since this routine is only advisory, we default to conservative ! 757: * behavior. ! 758: */ ! 759: start = trunc_page((vm_offset_t) uap->addr); ! 760: end = round_page((vm_offset_t) uap->addr + uap->len); ! 761: ! 762: user_map = current_map(); ! 763: ! 764: switch (uap->behav) { ! 765: case MADV_RANDOM: ! 766: new_behavior = VM_BEHAVIOR_RANDOM; ! 767: case MADV_SEQUENTIAL: ! 768: new_behavior = VM_BEHAVIOR_SEQUENTIAL; ! 769: case MADV_NORMAL: ! 770: default: ! 771: new_behavior = VM_BEHAVIOR_DEFAULT; ! 772: } ! 773: ! 774: result = vm_behavior_set(user_map, start, end, uap->behav); ! 775: switch (result) { ! 776: case KERN_SUCCESS: ! 777: return (0); ! 778: case KERN_INVALID_ADDRESS: ! 779: return (EINVAL); ! 780: } ! 781: ! 782: return (EINVAL); ! 783: } ! 784: ! 785: struct mincore_args { ! 786: const void *addr; ! 787: size_t len; ! 788: char *vec; ! 789: }; ! 790: /* ARGSUSED */ ! 791: int ! 792: mincore(p, uap, retval) ! 793: struct proc *p; ! 794: struct mincore_args *uap; ! 795: register_t *retval; ! 796: { ! 797: vm_offset_t addr, first_addr; ! 798: vm_offset_t end; ! 799: vm_map_t map; ! 800: char *vec; ! 801: int error; ! 802: int vecindex, lastvecindex; ! 803: int mincoreinfo=0; ! 804: int pqueryinfo; ! 805: kern_return_t ret; ! 806: int numref; ! 807: ! 808: map = current_map(); ! 809: ! 810: /* ! 811: * Make sure that the addresses presented are valid for user ! 812: * mode. ! 813: */ ! 814: first_addr = addr = trunc_page((vm_offset_t) uap->addr); ! 815: end = addr + (vm_size_t)round_page(uap->len); ! 816: ! 817: if (VM_MAX_ADDRESS > 0 && end > VM_MAX_ADDRESS) ! 818: return (EINVAL); ! 819: if (end < addr) ! 820: return (EINVAL); ! 821: ! 822: /* ! 823: * Address of byte vector ! 824: */ ! 825: vec = uap->vec; ! 826: ! 827: map = current_map(); ! 828: ! 829: /* ! 830: * Do this on a map entry basis so that if the pages are not ! 831: * in the current processes address space, we can easily look ! 832: * up the pages elsewhere. ! 833: */ ! 834: lastvecindex = -1; ! 835: for(addr; addr < end; addr += PAGE_SIZE) { ! 836: pqueryinfo = 0; ! 837: ret = vm_map_page_query(map, addr, &pqueryinfo, &numref); ! 838: if (ret != KERN_SUCCESS) ! 839: pqueryinfo = 0; ! 840: mincoreinfo = 0; ! 841: if (pqueryinfo & VM_PAGE_QUERY_PAGE_PRESENT) ! 842: mincoreinfo |= MINCORE_INCORE; ! 843: if (pqueryinfo & VM_PAGE_QUERY_PAGE_REF) ! 844: mincoreinfo |= MINCORE_REFERENCED; ! 845: if (pqueryinfo & VM_PAGE_QUERY_PAGE_DIRTY) ! 846: mincoreinfo |= MINCORE_MODIFIED; ! 847: ! 848: ! 849: /* ! 850: * calculate index into user supplied byte vector ! 851: */ ! 852: vecindex = (addr - first_addr)>> PAGE_SHIFT; ! 853: ! 854: /* ! 855: * If we have skipped map entries, we need to make sure that ! 856: * the byte vector is zeroed for those skipped entries. ! 857: */ ! 858: while((lastvecindex + 1) < vecindex) { ! 859: error = subyte( vec + lastvecindex, 0); ! 860: if (error) { ! 861: return (EFAULT); ! 862: } ! 863: ++lastvecindex; ! 864: } ! 865: ! 866: /* ! 867: * Pass the page information to the user ! 868: */ ! 869: error = subyte( vec + vecindex, mincoreinfo); ! 870: if (error) { ! 871: return (EFAULT); ! 872: } ! 873: lastvecindex = vecindex; ! 874: } ! 875: ! 876: ! 877: /* ! 878: * Zero the last entries in the byte vector. ! 879: */ ! 880: vecindex = (end - first_addr) >> PAGE_SHIFT; ! 881: while((lastvecindex + 1) < vecindex) { ! 882: error = subyte( vec + lastvecindex, 0); ! 883: if (error) { ! 884: return (EFAULT); ! 885: } ! 886: ++lastvecindex; ! 887: } ! 888: ! 889: return (0); ! 890: } ! 891: ! 892: struct mlock_args { ! 893: caddr_t addr; ! 894: size_t len; ! 895: }; ! 896: ! 897: #define BSD_DUMMY_HOST 1 ! 898: ! 899: int ! 900: mlock(p, uap, retval) ! 901: struct proc *p; ! 902: struct mlock_args *uap; ! 903: register_t *retval; ! 904: { ! 905: vm_map_t user_map; ! 906: vm_offset_t addr; ! 907: vm_size_t size, pageoff; ! 908: int error; ! 909: kern_return_t result; ! 910: ! 911: addr = (vm_offset_t) uap->addr; ! 912: size = uap->len; ! 913: ! 914: pageoff = (addr & PAGE_MASK); ! 915: addr -= pageoff; ! 916: size += pageoff; ! 917: size = (vm_size_t) round_page(size); ! 918: ! 919: /* disable wrap around */ ! 920: if (addr + size < addr) ! 921: return (EINVAL); ! 922: #ifdef notyet ! 923: /* Hmm.. What am I going to do with this? */ ! 924: if (atop(size) + cnt.v_wire_count > vm_page_max_wired) ! 925: return (EAGAIN); ! 926: #ifdef pmap_wired_count ! 927: if (size + ptoa(pmap_wired_count(vm_map_pmap(&p->p_vmspace->vm_map))) > ! 928: p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur) ! 929: return (ENOMEM); ! 930: #else ! 931: error = suser(p->p_ucred, &p->p_acflag); ! 932: if (error) ! 933: return (error); ! 934: #endif ! 935: #endif /* notyet */ ! 936: ! 937: user_map = current_map(); ! 938: ! 939: /* vm_wire */ ! 940: result = vm_wire(BSD_DUMMY_HOST, user_map, addr, size, VM_PROT_ALL); ! 941: return (result == KERN_SUCCESS ? 0 : ENOMEM); ! 942: } ! 943: ! 944: struct munlock_args { ! 945: caddr_t addr; ! 946: size_t len; ! 947: }; ! 948: int ! 949: munlock(p, uap, retval) ! 950: struct proc *p; ! 951: struct munlock_args *uap; ! 952: register_t *retval; ! 953: { ! 954: vm_offset_t addr; ! 955: vm_size_t size, pageoff; ! 956: int error; ! 957: vm_map_t user_map; ! 958: kern_return_t result; ! 959: ! 960: addr = (vm_offset_t) uap->addr; ! 961: size = uap->len; ! 962: ! 963: pageoff = (addr & PAGE_MASK); ! 964: addr -= pageoff; ! 965: size += pageoff; ! 966: size = (vm_size_t) round_page(size); ! 967: ! 968: /* disable wrap around */ ! 969: if (addr + size < addr) ! 970: return (EINVAL); ! 971: ! 972: #ifdef notyet ! 973: /* Hmm.. What am I going to do with this? */ ! 974: #ifndef pmap_wired_count ! 975: error = suser(p->p_ucred, &p->p_acflag); ! 976: if (error) ! 977: return (error); ! 978: #endif ! 979: #endif /* notyet */ ! 980: ! 981: user_map = current_map(); ! 982: ! 983: /* vm_wire */ ! 984: result = vm_wire(BSD_DUMMY_HOST, user_map, addr, size, VM_PROT_NONE); ! 985: return (result == KERN_SUCCESS ? 0 : ENOMEM); ! 986: } ! 987: ! 988: ! 989: struct mlockall_args { ! 990: int how; ! 991: }; ! 992: ! 993: int ! 994: mlockall(p, uap) ! 995: struct proc *p; ! 996: struct mlockall_args *uap; ! 997: { ! 998: return 0; ! 999: } ! 1000: ! 1001: struct munlockall_args { ! 1002: int how; ! 1003: }; ! 1004: ! 1005: int ! 1006: munlockall(p, uap) ! 1007: struct proc *p; ! 1008: struct munlockall_args *uap; ! 1009: { ! 1010: return 0; ! 1011: } ! 1012: ! 1013: ! 1014: /* BEGIN DEFUNCT */ ! 1015: struct obreak_args { ! 1016: char *nsiz; ! 1017: }; ! 1018: obreak(p, uap, retval) ! 1019: struct proc *p; ! 1020: struct obreak_args *uap; ! 1021: register_t *retval; ! 1022: { ! 1023: /* Not implemented, obsolete */ ! 1024: return (ENOMEM); ! 1025: } ! 1026: ! 1027: int both; ! 1028: ! 1029: ovadvise() ! 1030: { ! 1031: ! 1032: #ifdef lint ! 1033: both = 0; ! 1034: #endif ! 1035: } ! 1036: /* END DEFUNCT */ ! 1037: #if 1 ! 1038: int print_map_addr=0; ! 1039: #endif /* 1 */ ! 1040: ! 1041: kern_return_t map_fd( ! 1042: int fd, ! 1043: vm_offset_t offset, ! 1044: vm_offset_t *va, ! 1045: boolean_t findspace, ! 1046: vm_size_t size) ! 1047: { ! 1048: kern_return_t ret; ! 1049: boolean_t funnel_state; ! 1050: ! 1051: funnel_state = thread_set_funneled(TRUE); ! 1052: ! 1053: ret = map_fd_funneled( fd, offset, va, findspace, size); ! 1054: ! 1055: (void) thread_set_funneled(funnel_state); ! 1056: ! 1057: return ret; ! 1058: } ! 1059: ! 1060: kern_return_t map_fd_funneled( ! 1061: int fd, ! 1062: vm_offset_t offset, ! 1063: vm_offset_t *va, ! 1064: boolean_t findspace, ! 1065: vm_size_t size) ! 1066: { ! 1067: kern_return_t result; ! 1068: struct file *fp; ! 1069: struct vnode *vp; ! 1070: void * pager; ! 1071: vm_offset_t map_addr=0; ! 1072: vm_size_t map_size; ! 1073: vm_map_copy_t tmp; ! 1074: int err=0; ! 1075: vm_map_t my_map; ! 1076: struct proc *p =(struct proc *)(get_bsdtask_info(current_task())); ! 1077: #if 0 ! 1078: extern int print_map_addr; ! 1079: #endif /* 0 */ ! 1080: ! 1081: /* ! 1082: * Find the inode; verify that it's a regular file. ! 1083: */ ! 1084: ! 1085: err = fdgetf(p, fd, &fp); ! 1086: if (err) ! 1087: return(err); ! 1088: ! 1089: if (fp->f_type != DTYPE_VNODE) ! 1090: return(KERN_INVALID_ARGUMENT); ! 1091: vp = (struct vnode *)fp->f_data; ! 1092: ! 1093: if (vp->v_type != VREG) ! 1094: return (KERN_INVALID_ARGUMENT); ! 1095: ! 1096: map_size = round_page(size); ! 1097: ! 1098: /* ! 1099: * Allow user to map in a zero length file. ! 1100: */ ! 1101: if (size == 0) ! 1102: return (KERN_SUCCESS); ! 1103: /* ! 1104: * Map in the file. ! 1105: */ ! 1106: if (!vp->v_vm_info) { ! 1107: vm_info_init(vp); ! 1108: } ! 1109: ! 1110: pager = (void *) vnode_pager_setup(vp, vp->v_vm_info->pager, FALSE, TRUE); ! 1111: if (pager == NULL) ! 1112: return (KERN_FAILURE); ! 1113: ! 1114: ! 1115: my_map = current_map(); ! 1116: ! 1117: result = vm_map( ! 1118: my_map, ! 1119: &map_addr, map_size, (vm_offset_t)0, TRUE, ! 1120: pager, offset, TRUE, ! 1121: VM_PROT_DEFAULT, VM_PROT_ALL, ! 1122: VM_INHERIT_DEFAULT); ! 1123: if (result != KERN_SUCCESS) ! 1124: return (result); ! 1125: ! 1126: ! 1127: if (!findspace) { ! 1128: vm_offset_t dst_addr; ! 1129: vm_map_copy_t tmp; ! 1130: ! 1131: if (copyin(va, &dst_addr, sizeof (dst_addr)) || ! 1132: trunc_page(dst_addr) != dst_addr) { ! 1133: (void) vm_map_remove( ! 1134: my_map, ! 1135: map_addr, map_addr + map_size, ! 1136: VM_MAP_NO_FLAGS); ! 1137: return (KERN_INVALID_ADDRESS); ! 1138: } ! 1139: ! 1140: result = vm_map_copyin( ! 1141: my_map, ! 1142: map_addr, map_size, TRUE, ! 1143: &tmp); ! 1144: if (result != KERN_SUCCESS) { ! 1145: ! 1146: (void) vm_map_remove( ! 1147: my_map, ! 1148: map_addr, map_addr + map_size, ! 1149: VM_MAP_NO_FLAGS); ! 1150: return (result); ! 1151: } ! 1152: ! 1153: result = vm_map_copy_overwrite( ! 1154: my_map, ! 1155: dst_addr, tmp, FALSE); ! 1156: if (result != KERN_SUCCESS) { ! 1157: vm_map_copy_discard(tmp); ! 1158: return (result); ! 1159: } ! 1160: } ! 1161: else { ! 1162: if (copyout(&map_addr, va, sizeof (map_addr))) { ! 1163: (void) vm_map_remove( ! 1164: my_map, ! 1165: map_addr, map_addr + map_size, ! 1166: VM_MAP_NO_FLAGS); ! 1167: return (KERN_INVALID_ADDRESS); ! 1168: } ! 1169: } ! 1170: if (ISMAPPABLEFILE(vp)) ! 1171: vp->v_vm_info->mapped = 1; ! 1172: ! 1173: /* ! 1174: * Set credentials. ! 1175: */ ! 1176: if (vp->v_vm_info->cred == NULL) { ! 1177: crhold(current_proc()->p_ucred); ! 1178: vp->v_vm_info->cred = current_proc()->p_ucred; ! 1179: } ! 1180: ! 1181: return (KERN_SUCCESS); ! 1182: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.