|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 University of Utah. ! 3: * Copyright (c) 1991 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Systems Programming Group of the University of Utah Computer ! 8: * Science Department. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by the University of ! 21: * California, Berkeley and its contributors. ! 22: * 4. Neither the name of the University nor the names of its contributors ! 23: * may be used to endorse or promote products derived from this software ! 24: * without specific prior written permission. ! 25: * ! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 36: * SUCH DAMAGE. ! 37: * ! 38: * from: Utah $Hdr: vm_mmap.c 1.3 90/01/21$ ! 39: * ! 40: * @(#)vm_mmap.c 7.5 (Berkeley) 6/28/91 ! 41: */ ! 42: ! 43: /* ! 44: * Mapped file (mmap) interface to VM ! 45: */ ! 46: ! 47: #include "param.h" ! 48: #include "systm.h" ! 49: #include "filedesc.h" ! 50: #include "proc.h" ! 51: #include "vnode.h" ! 52: #include "specdev.h" ! 53: #include "file.h" ! 54: #include "mman.h" ! 55: #include "conf.h" ! 56: ! 57: #include "vm.h" ! 58: #include "vm_pager.h" ! 59: #include "vm_prot.h" ! 60: #include "vm_statistics.h" ! 61: ! 62: #ifdef DEBUG ! 63: int mmapdebug = 0; ! 64: #define MDB_FOLLOW 0x01 ! 65: #define MDB_SYNC 0x02 ! 66: #define MDB_MAPIT 0x04 ! 67: #endif ! 68: ! 69: /* ARGSUSED */ ! 70: getpagesize(p, uap, retval) ! 71: struct proc *p; ! 72: void *uap; ! 73: int *retval; ! 74: { ! 75: ! 76: *retval = NBPG * CLSIZE; ! 77: return (0); ! 78: } ! 79: ! 80: /* ARGSUSED */ ! 81: sbrk(p, uap, retval) ! 82: struct proc *p; ! 83: struct args { ! 84: int incr; ! 85: } *uap; ! 86: int *retval; ! 87: { ! 88: ! 89: /* Not yet implemented */ ! 90: return (EOPNOTSUPP); ! 91: } ! 92: ! 93: /* ARGSUSED */ ! 94: sstk(p, uap, retval) ! 95: struct proc *p; ! 96: struct args { ! 97: int incr; ! 98: } *uap; ! 99: int *retval; ! 100: { ! 101: ! 102: /* Not yet implemented */ ! 103: return (EOPNOTSUPP); ! 104: } ! 105: ! 106: smmap(p, uap, retval) ! 107: struct proc *p; ! 108: register struct args { ! 109: caddr_t addr; ! 110: int len; ! 111: int prot; ! 112: int flags; ! 113: int fd; ! 114: off_t pos; ! 115: } *uap; ! 116: int *retval; ! 117: { ! 118: register struct filedesc *fdp = p->p_fd; ! 119: register struct file *fp; ! 120: struct vnode *vp; ! 121: vm_offset_t addr; ! 122: vm_size_t size; ! 123: vm_prot_t prot; ! 124: caddr_t handle; ! 125: int mtype, error; ! 126: ! 127: #ifdef DEBUG ! 128: if (mmapdebug & MDB_FOLLOW) ! 129: printf("mmap(%d): addr %x len %x pro %x flg %x fd %d pos %x\n", ! 130: p->p_pid, uap->addr, uap->len, uap->prot, ! 131: uap->flags, uap->fd, uap->pos); ! 132: #endif ! 133: /* ! 134: * Make sure one of the sharing types is specified ! 135: */ ! 136: mtype = uap->flags & MAP_TYPE; ! 137: switch (mtype) { ! 138: case MAP_FILE: ! 139: case MAP_ANON: ! 140: break; ! 141: default: ! 142: return(EINVAL); ! 143: } ! 144: /* ! 145: * Address (if FIXED) must be page aligned. ! 146: * Size is implicitly rounded to a page boundary. ! 147: */ ! 148: addr = (vm_offset_t) uap->addr; ! 149: if ((uap->flags & MAP_FIXED) && (addr & page_mask) || uap->len < 0) ! 150: return(EINVAL); ! 151: size = (vm_size_t) round_page(uap->len); ! 152: /* ! 153: * XXX if no hint provided for a non-fixed mapping place it after ! 154: * the end of the largest possible heap. ! 155: * ! 156: * There should really be a pmap call to determine a reasonable ! 157: * location. ! 158: */ ! 159: if (addr == 0 && (uap->flags & MAP_FIXED) == 0) ! 160: addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ); ! 161: /* ! 162: * Mapping file or named anonymous, get fp for validation ! 163: */ ! 164: if (mtype == MAP_FILE || uap->fd != -1) { ! 165: if (((unsigned)uap->fd) >= fdp->fd_nfiles || ! 166: (fp = fdp->fd_ofiles[uap->fd]) == NULL) ! 167: return(EBADF); ! 168: } ! 169: /* ! 170: * If we are mapping a file we need to check various ! 171: * file/vnode related things. ! 172: */ ! 173: if (mtype == MAP_FILE) { ! 174: /* ! 175: * Obtain vnode and make sure it is of appropriate type ! 176: */ ! 177: if (fp->f_type != DTYPE_VNODE) ! 178: return(EINVAL); ! 179: vp = (struct vnode *)fp->f_data; ! 180: if (vp->v_type != VREG && vp->v_type != VCHR) ! 181: return(EINVAL); ! 182: /* ! 183: * Ensure that file protection and desired protection ! 184: * are compatible. Note that we only worry about writability ! 185: * if mapping is shared. ! 186: */ ! 187: if ((uap->prot & PROT_READ) && (fp->f_flag & FREAD) == 0 || ! 188: ((uap->flags & MAP_SHARED) && ! 189: (uap->prot & PROT_WRITE) && (fp->f_flag & FWRITE) == 0)) ! 190: return(EACCES); ! 191: handle = (caddr_t)vp; ! 192: } else if (uap->fd != -1) ! 193: handle = (caddr_t)fp; ! 194: else ! 195: handle = NULL; ! 196: /* ! 197: * Map protections to MACH style ! 198: */ ! 199: prot = VM_PROT_NONE; ! 200: if (uap->prot & PROT_READ) ! 201: prot |= VM_PROT_READ; ! 202: if (uap->prot & PROT_WRITE) ! 203: prot |= VM_PROT_WRITE; ! 204: if (uap->prot & PROT_EXEC) ! 205: prot |= VM_PROT_EXECUTE; ! 206: ! 207: error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, ! 208: uap->flags, handle, (vm_offset_t)uap->pos); ! 209: if (error == 0) ! 210: *retval = (int) addr; ! 211: return(error); ! 212: } ! 213: ! 214: msync(p, uap, retval) ! 215: struct proc *p; ! 216: struct args { ! 217: caddr_t addr; ! 218: int len; ! 219: } *uap; ! 220: int *retval; ! 221: { ! 222: vm_offset_t addr, objoff, oaddr; ! 223: vm_size_t size, osize; ! 224: vm_prot_t prot, mprot; ! 225: vm_inherit_t inherit; ! 226: vm_object_t object; ! 227: boolean_t shared; ! 228: int rv; ! 229: ! 230: #ifdef DEBUG ! 231: if (mmapdebug & (MDB_FOLLOW|MDB_SYNC)) ! 232: printf("msync(%d): addr %x len %x\n", ! 233: p->p_pid, uap->addr, uap->len); ! 234: #endif ! 235: if (((int)uap->addr & page_mask) || uap->len < 0) ! 236: return(EINVAL); ! 237: addr = oaddr = (vm_offset_t)uap->addr; ! 238: osize = (vm_size_t)uap->len; ! 239: /* ! 240: * Region must be entirely contained in a single entry ! 241: */ ! 242: if (!vm_map_is_allocated(&p->p_vmspace->vm_map, addr, addr+osize, ! 243: TRUE)) ! 244: return(EINVAL); ! 245: /* ! 246: * Determine the object associated with that entry ! 247: * (object is returned locked on KERN_SUCCESS) ! 248: */ ! 249: rv = vm_region(&p->p_vmspace->vm_map, &addr, &size, &prot, &mprot, ! 250: &inherit, &shared, &object, &objoff); ! 251: if (rv != KERN_SUCCESS) ! 252: return(EINVAL); ! 253: #ifdef DEBUG ! 254: if (mmapdebug & MDB_SYNC) ! 255: printf("msync: region: object %x addr %x size %d objoff %d\n", ! 256: object, addr, size, objoff); ! 257: #endif ! 258: /* ! 259: * Do not msync non-vnoded backed objects. ! 260: */ ! 261: if (object->internal || object->pager == NULL || ! 262: object->pager->pg_type != PG_VNODE) { ! 263: vm_object_unlock(object); ! 264: return(EINVAL); ! 265: } ! 266: objoff += oaddr - addr; ! 267: if (osize == 0) ! 268: osize = size; ! 269: #ifdef DEBUG ! 270: if (mmapdebug & MDB_SYNC) ! 271: printf("msync: cleaning/flushing object range [%x-%x)\n", ! 272: objoff, objoff+osize); ! 273: #endif ! 274: if (prot & VM_PROT_WRITE) ! 275: vm_object_page_clean(object, objoff, objoff+osize); ! 276: /* ! 277: * (XXX) ! 278: * Bummer, gotta flush all cached pages to ensure ! 279: * consistency with the file system cache. ! 280: */ ! 281: vm_object_page_remove(object, objoff, objoff+osize); ! 282: vm_object_unlock(object); ! 283: return(0); ! 284: } ! 285: ! 286: munmap(p, uap, retval) ! 287: register struct proc *p; ! 288: register struct args { ! 289: caddr_t addr; ! 290: int len; ! 291: } *uap; ! 292: int *retval; ! 293: { ! 294: vm_offset_t addr; ! 295: vm_size_t size; ! 296: ! 297: #ifdef DEBUG ! 298: if (mmapdebug & MDB_FOLLOW) ! 299: printf("munmap(%d): addr %x len %x\n", ! 300: p->p_pid, uap->addr, uap->len); ! 301: #endif ! 302: ! 303: addr = (vm_offset_t) uap->addr; ! 304: if ((addr & page_mask) || uap->len < 0) ! 305: return(EINVAL); ! 306: size = (vm_size_t) round_page(uap->len); ! 307: if (size == 0) ! 308: return(0); ! 309: if (!vm_map_is_allocated(&p->p_vmspace->vm_map, addr, addr+size, ! 310: FALSE)) ! 311: return(EINVAL); ! 312: /* returns nothing but KERN_SUCCESS anyway */ ! 313: (void) vm_map_remove(&p->p_vmspace->vm_map, addr, addr+size); ! 314: return(0); ! 315: } ! 316: ! 317: munmapfd(fd) ! 318: { ! 319: #ifdef DEBUG ! 320: if (mmapdebug & MDB_FOLLOW) ! 321: printf("munmapfd(%d): fd %d\n", curproc->p_pid, fd); ! 322: #endif ! 323: ! 324: /* ! 325: * XXX -- should vm_deallocate any regions mapped to this file ! 326: */ ! 327: curproc->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; ! 328: } ! 329: ! 330: mprotect(p, uap, retval) ! 331: struct proc *p; ! 332: struct args { ! 333: caddr_t addr; ! 334: int len; ! 335: int prot; ! 336: } *uap; ! 337: int *retval; ! 338: { ! 339: vm_offset_t addr; ! 340: vm_size_t size; ! 341: register vm_prot_t prot; ! 342: ! 343: #ifdef DEBUG ! 344: if (mmapdebug & MDB_FOLLOW) ! 345: printf("mprotect(%d): addr %x len %x prot %d\n", ! 346: p->p_pid, uap->addr, uap->len, uap->prot); ! 347: #endif ! 348: ! 349: addr = (vm_offset_t) uap->addr; ! 350: if ((addr & page_mask) || uap->len < 0) ! 351: return(EINVAL); ! 352: size = (vm_size_t) uap->len; ! 353: /* ! 354: * Map protections ! 355: */ ! 356: prot = VM_PROT_NONE; ! 357: if (uap->prot & PROT_READ) ! 358: prot |= VM_PROT_READ; ! 359: if (uap->prot & PROT_WRITE) ! 360: prot |= VM_PROT_WRITE; ! 361: if (uap->prot & PROT_EXEC) ! 362: prot |= VM_PROT_EXECUTE; ! 363: ! 364: switch (vm_map_protect(&p->p_vmspace->vm_map, addr, addr+size, prot, ! 365: FALSE)) { ! 366: case KERN_SUCCESS: ! 367: return (0); ! 368: case KERN_PROTECTION_FAILURE: ! 369: return (EACCES); ! 370: } ! 371: return (EINVAL); ! 372: } ! 373: ! 374: /* ARGSUSED */ ! 375: madvise(p, uap, retval) ! 376: struct proc *p; ! 377: struct args { ! 378: caddr_t addr; ! 379: int len; ! 380: int behav; ! 381: } *uap; ! 382: int *retval; ! 383: { ! 384: ! 385: /* Not yet implemented */ ! 386: return (EOPNOTSUPP); ! 387: } ! 388: ! 389: /* ARGSUSED */ ! 390: mincore(p, uap, retval) ! 391: struct proc *p; ! 392: struct args { ! 393: caddr_t addr; ! 394: int len; ! 395: char *vec; ! 396: } *uap; ! 397: int *retval; ! 398: { ! 399: ! 400: /* Not yet implemented */ ! 401: return (EOPNOTSUPP); ! 402: } ! 403: ! 404: /* ! 405: * Internal version of mmap. ! 406: * Currently used by mmap, exec, and sys5 shared memory. ! 407: * Handle is: ! 408: * MAP_FILE: a vnode pointer ! 409: * MAP_ANON: NULL or a file pointer ! 410: */ ! 411: vm_mmap(map, addr, size, prot, flags, handle, foff) ! 412: register vm_map_t map; ! 413: register vm_offset_t *addr; ! 414: register vm_size_t size; ! 415: vm_prot_t prot; ! 416: register int flags; ! 417: caddr_t handle; /* XXX should be vp */ ! 418: vm_offset_t foff; ! 419: { ! 420: register vm_pager_t pager; ! 421: boolean_t fitit; ! 422: vm_object_t object; ! 423: struct vnode *vp; ! 424: int type; ! 425: int rv = KERN_SUCCESS; ! 426: ! 427: if (size == 0) ! 428: return (0); ! 429: ! 430: if ((flags & MAP_FIXED) == 0) { ! 431: fitit = TRUE; ! 432: *addr = round_page(*addr); ! 433: } else { ! 434: fitit = FALSE; ! 435: (void) vm_deallocate(map, *addr, size); ! 436: } ! 437: ! 438: /* ! 439: * Lookup/allocate pager. All except an unnamed anonymous lookup ! 440: * gain a reference to ensure continued existance of the object. ! 441: * (XXX the exception is to appease the pageout daemon) ! 442: */ ! 443: if ((flags & MAP_TYPE) == MAP_ANON) ! 444: type = PG_DFLT; ! 445: else { ! 446: vp = (struct vnode *)handle; ! 447: if (vp->v_type == VCHR) { ! 448: type = PG_DEVICE; ! 449: handle = (caddr_t)vp->v_rdev; ! 450: } else ! 451: type = PG_VNODE; ! 452: } ! 453: pager = vm_pager_allocate(type, handle, size, prot); ! 454: if (pager == NULL) ! 455: return (type == PG_DEVICE ? EINVAL : ENOMEM); ! 456: /* ! 457: * Find object and release extra reference gained by lookup ! 458: */ ! 459: object = vm_object_lookup(pager); ! 460: vm_object_deallocate(object); ! 461: ! 462: /* ! 463: * Anonymous memory. ! 464: */ ! 465: if ((flags & MAP_TYPE) == MAP_ANON) { ! 466: rv = vm_allocate_with_pager(map, addr, size, fitit, ! 467: pager, (vm_offset_t)foff, TRUE); ! 468: if (rv != KERN_SUCCESS) { ! 469: if (handle == NULL) ! 470: vm_pager_deallocate(pager); ! 471: else ! 472: vm_object_deallocate(object); ! 473: goto out; ! 474: } ! 475: /* ! 476: * Don't cache anonymous objects. ! 477: * Loses the reference gained by vm_pager_allocate. ! 478: */ ! 479: (void) pager_cache(object, FALSE); ! 480: #ifdef DEBUG ! 481: if (mmapdebug & MDB_MAPIT) ! 482: printf("vm_mmap(%d): ANON *addr %x size %x pager %x\n", ! 483: curproc->p_pid, *addr, size, pager); ! 484: #endif ! 485: } ! 486: /* ! 487: * Must be type MAP_FILE. ! 488: * Distinguish between character special and regular files. ! 489: */ ! 490: else if (vp->v_type == VCHR) { ! 491: rv = vm_allocate_with_pager(map, addr, size, fitit, ! 492: pager, (vm_offset_t)foff, FALSE); ! 493: /* ! 494: * Uncache the object and lose the reference gained ! 495: * by vm_pager_allocate(). If the call to ! 496: * vm_allocate_with_pager() was sucessful, then we ! 497: * gained an additional reference ensuring the object ! 498: * will continue to exist. If the call failed then ! 499: * the deallocate call below will terminate the ! 500: * object which is fine. ! 501: */ ! 502: (void) pager_cache(object, FALSE); ! 503: if (rv != KERN_SUCCESS) ! 504: goto out; ! 505: } ! 506: /* ! 507: * A regular file ! 508: */ ! 509: else { ! 510: #ifdef DEBUG ! 511: if (object == NULL) ! 512: printf("vm_mmap: no object: vp %x, pager %x\n", ! 513: vp, pager); ! 514: #endif ! 515: /* ! 516: * Map it directly. ! 517: * Allows modifications to go out to the vnode. ! 518: */ ! 519: if (flags & MAP_SHARED) { ! 520: rv = vm_allocate_with_pager(map, addr, size, ! 521: fitit, pager, ! 522: (vm_offset_t)foff, FALSE); ! 523: if (rv != KERN_SUCCESS) { ! 524: vm_object_deallocate(object); ! 525: goto out; ! 526: } ! 527: /* ! 528: * Don't cache the object. This is the easiest way ! 529: * of ensuring that data gets back to the filesystem ! 530: * because vnode_pager_deallocate() will fsync the ! 531: * vnode. pager_cache() will lose the extra ref. ! 532: */ ! 533: if (prot & VM_PROT_WRITE) ! 534: pager_cache(object, FALSE); ! 535: else ! 536: vm_object_deallocate(object); ! 537: } ! 538: /* ! 539: * Copy-on-write of file. Two flavors. ! 540: * MAP_COPY is true COW, you essentially get a snapshot of ! 541: * the region at the time of mapping. MAP_PRIVATE means only ! 542: * that your changes are not reflected back to the object. ! 543: * Changes made by others will be seen. ! 544: */ ! 545: else { ! 546: vm_map_t tmap; ! 547: vm_offset_t off; ! 548: ! 549: /* locate and allocate the target address space */ ! 550: rv = vm_map_find(map, NULL, (vm_offset_t)0, ! 551: addr, size, fitit); ! 552: if (rv != KERN_SUCCESS) { ! 553: vm_object_deallocate(object); ! 554: goto out; ! 555: } ! 556: tmap = vm_map_create(pmap_create(size), VM_MIN_ADDRESS, ! 557: VM_MIN_ADDRESS+size, TRUE); ! 558: off = VM_MIN_ADDRESS; ! 559: rv = vm_allocate_with_pager(tmap, &off, size, ! 560: TRUE, pager, ! 561: (vm_offset_t)foff, FALSE); ! 562: if (rv != KERN_SUCCESS) { ! 563: vm_object_deallocate(object); ! 564: vm_map_deallocate(tmap); ! 565: goto out; ! 566: } ! 567: /* ! 568: * (XXX) ! 569: * MAP_PRIVATE implies that we see changes made by ! 570: * others. To ensure that we need to guarentee that ! 571: * no copy object is created (otherwise original ! 572: * pages would be pushed to the copy object and we ! 573: * would never see changes made by others). We ! 574: * totally sleeze it right now by marking the object ! 575: * internal temporarily. ! 576: */ ! 577: if ((flags & MAP_COPY) == 0) ! 578: object->internal = TRUE; ! 579: rv = vm_map_copy(map, tmap, *addr, size, off, ! 580: FALSE, FALSE); ! 581: object->internal = FALSE; ! 582: /* ! 583: * (XXX) ! 584: * My oh my, this only gets worse... ! 585: * Force creation of a shadow object so that ! 586: * vm_map_fork will do the right thing. ! 587: */ ! 588: if ((flags & MAP_COPY) == 0) { ! 589: vm_map_t tmap; ! 590: vm_map_entry_t tentry; ! 591: vm_object_t tobject; ! 592: vm_offset_t toffset; ! 593: vm_prot_t tprot; ! 594: boolean_t twired, tsu; ! 595: ! 596: tmap = map; ! 597: vm_map_lookup(&tmap, *addr, VM_PROT_WRITE, ! 598: &tentry, &tobject, &toffset, ! 599: &tprot, &twired, &tsu); ! 600: vm_map_lookup_done(tmap, tentry); ! 601: } ! 602: /* ! 603: * (XXX) ! 604: * Map copy code cannot detect sharing unless a ! 605: * sharing map is involved. So we cheat and write ! 606: * protect everything ourselves. ! 607: */ ! 608: vm_object_pmap_copy(object, (vm_offset_t)foff, ! 609: (vm_offset_t)foff+size); ! 610: vm_object_deallocate(object); ! 611: vm_map_deallocate(tmap); ! 612: if (rv != KERN_SUCCESS) ! 613: goto out; ! 614: } ! 615: #ifdef DEBUG ! 616: if (mmapdebug & MDB_MAPIT) ! 617: printf("vm_mmap(%d): FILE *addr %x size %x pager %x\n", ! 618: curproc->p_pid, *addr, size, pager); ! 619: #endif ! 620: } ! 621: /* ! 622: * Correct protection (default is VM_PROT_ALL). ! 623: * Note that we set the maximum protection. This may not be ! 624: * entirely correct. Maybe the maximum protection should be based ! 625: * on the object permissions where it makes sense (e.g. a vnode). ! 626: * ! 627: * Changed my mind: leave max prot at VM_PROT_ALL. ! 628: */ ! 629: if (prot != VM_PROT_ALL) { ! 630: rv = vm_map_protect(map, *addr, *addr+size, prot, FALSE); ! 631: if (rv != KERN_SUCCESS) { ! 632: (void) vm_deallocate(map, *addr, size); ! 633: goto out; ! 634: } ! 635: } ! 636: /* ! 637: * Shared memory is also shared with children. ! 638: */ ! 639: if (flags & MAP_SHARED) { ! 640: rv = vm_inherit(map, *addr, size, VM_INHERIT_SHARE); ! 641: if (rv != KERN_SUCCESS) { ! 642: (void) vm_deallocate(map, *addr, size); ! 643: goto out; ! 644: } ! 645: } ! 646: out: ! 647: #ifdef DEBUG ! 648: if (mmapdebug & MDB_MAPIT) ! 649: printf("vm_mmap: rv %d\n", rv); ! 650: #endif ! 651: switch (rv) { ! 652: case KERN_SUCCESS: ! 653: return (0); ! 654: case KERN_INVALID_ADDRESS: ! 655: case KERN_NO_SPACE: ! 656: return (ENOMEM); ! 657: case KERN_PROTECTION_FAILURE: ! 658: return (EACCES); ! 659: default: ! 660: return (EINVAL); ! 661: } ! 662: } ! 663: ! 664: /* ! 665: * Internal bastardized version of MACHs vm_region system call. ! 666: * Given address and size it returns map attributes as well ! 667: * as the (locked) object mapped at that location. ! 668: */ ! 669: vm_region(map, addr, size, prot, max_prot, inheritance, shared, object, objoff) ! 670: vm_map_t map; ! 671: vm_offset_t *addr; /* IN/OUT */ ! 672: vm_size_t *size; /* OUT */ ! 673: vm_prot_t *prot; /* OUT */ ! 674: vm_prot_t *max_prot; /* OUT */ ! 675: vm_inherit_t *inheritance; /* OUT */ ! 676: boolean_t *shared; /* OUT */ ! 677: vm_object_t *object; /* OUT */ ! 678: vm_offset_t *objoff; /* OUT */ ! 679: { ! 680: vm_map_entry_t tmp_entry; ! 681: register ! 682: vm_map_entry_t entry; ! 683: register ! 684: vm_offset_t tmp_offset; ! 685: vm_offset_t start; ! 686: ! 687: if (map == NULL) ! 688: return(KERN_INVALID_ARGUMENT); ! 689: ! 690: start = *addr; ! 691: ! 692: vm_map_lock_read(map); ! 693: if (!vm_map_lookup_entry(map, start, &tmp_entry)) { ! 694: if ((entry = tmp_entry->next) == &map->header) { ! 695: vm_map_unlock_read(map); ! 696: return(KERN_NO_SPACE); ! 697: } ! 698: start = entry->start; ! 699: *addr = start; ! 700: } else ! 701: entry = tmp_entry; ! 702: ! 703: *prot = entry->protection; ! 704: *max_prot = entry->max_protection; ! 705: *inheritance = entry->inheritance; ! 706: ! 707: tmp_offset = entry->offset + (start - entry->start); ! 708: *size = (entry->end - start); ! 709: ! 710: if (entry->is_a_map) { ! 711: register vm_map_t share_map; ! 712: vm_size_t share_size; ! 713: ! 714: share_map = entry->object.share_map; ! 715: ! 716: vm_map_lock_read(share_map); ! 717: (void) vm_map_lookup_entry(share_map, tmp_offset, &tmp_entry); ! 718: ! 719: if ((share_size = (tmp_entry->end - tmp_offset)) < *size) ! 720: *size = share_size; ! 721: ! 722: vm_object_lock(tmp_entry->object); ! 723: *object = tmp_entry->object.vm_object; ! 724: *objoff = tmp_entry->offset + (tmp_offset - tmp_entry->start); ! 725: ! 726: *shared = (share_map->ref_count != 1); ! 727: vm_map_unlock_read(share_map); ! 728: } else { ! 729: vm_object_lock(entry->object); ! 730: *object = entry->object.vm_object; ! 731: *objoff = tmp_offset; ! 732: ! 733: *shared = FALSE; ! 734: } ! 735: ! 736: vm_map_unlock_read(map); ! 737: ! 738: return(KERN_SUCCESS); ! 739: } ! 740: ! 741: /* ! 742: * Yet another bastard routine. ! 743: */ ! 744: vm_allocate_with_pager(map, addr, size, fitit, pager, poffset, internal) ! 745: register vm_map_t map; ! 746: register vm_offset_t *addr; ! 747: register vm_size_t size; ! 748: boolean_t fitit; ! 749: vm_pager_t pager; ! 750: vm_offset_t poffset; ! 751: boolean_t internal; ! 752: { ! 753: register vm_object_t object; ! 754: register int result; ! 755: ! 756: if (map == NULL) ! 757: return(KERN_INVALID_ARGUMENT); ! 758: ! 759: *addr = trunc_page(*addr); ! 760: size = round_page(size); ! 761: ! 762: /* ! 763: * Lookup the pager/paging-space in the object cache. ! 764: * If it's not there, then create a new object and cache ! 765: * it. ! 766: */ ! 767: object = vm_object_lookup(pager); ! 768: vm_stat.lookups++; ! 769: if (object == NULL) { ! 770: object = vm_object_allocate(size); ! 771: vm_object_enter(object, pager); ! 772: } else ! 773: vm_stat.hits++; ! 774: object->internal = internal; ! 775: ! 776: result = vm_map_find(map, object, poffset, addr, size, fitit); ! 777: if (result != KERN_SUCCESS) ! 778: vm_object_deallocate(object); ! 779: else if (pager != NULL) ! 780: vm_object_setpager(object, pager, (vm_offset_t) 0, TRUE); ! 781: return(result); ! 782: } ! 783: ! 784: /* ! 785: * XXX: this routine belongs in vm_map.c. ! 786: * ! 787: * Returns TRUE if the range [start - end) is allocated in either ! 788: * a single entry (single_entry == TRUE) or multiple contiguous ! 789: * entries (single_entry == FALSE). ! 790: * ! 791: * start and end should be page aligned. ! 792: */ ! 793: boolean_t ! 794: vm_map_is_allocated(map, start, end, single_entry) ! 795: vm_map_t map; ! 796: vm_offset_t start, end; ! 797: boolean_t single_entry; ! 798: { ! 799: vm_map_entry_t mapent; ! 800: register vm_offset_t nend; ! 801: ! 802: vm_map_lock_read(map); ! 803: ! 804: /* ! 805: * Start address not in any entry ! 806: */ ! 807: if (!vm_map_lookup_entry(map, start, &mapent)) { ! 808: vm_map_unlock_read(map); ! 809: return (FALSE); ! 810: } ! 811: /* ! 812: * Find the maximum stretch of contiguously allocated space ! 813: */ ! 814: nend = mapent->end; ! 815: if (!single_entry) { ! 816: mapent = mapent->next; ! 817: while (mapent != &map->header && mapent->start == nend) { ! 818: nend = mapent->end; ! 819: mapent = mapent->next; ! 820: } ! 821: } ! 822: ! 823: vm_map_unlock_read(map); ! 824: return (end <= nend); ! 825: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.