Annotation of XNU/bsd/kern/kern_mman.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.