The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/kern_mman.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 2c795d2c483b4ce708089342b6b61436


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.