Index: sys/sys/file.h
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/sys/file.h,v
retrieving revision 1.77
diff -u -p -r1.77 file.h
--- sys/sys/file.h      5 Sep 2014 09:17:04 -0000       1.77
+++ sys/sys/file.h      19 Nov 2014 15:24:37 -0000
@@ -77,6 +77,7 @@ struct uio;
struct iovec;
struct stat;
struct knote;
+struct uvm_object;

struct fileops {
       int     (*fo_read)      (struct file *, off_t *, struct uio *,
@@ -90,17 +91,11 @@ struct fileops {
       int     (*fo_close)     (struct file *);
       int     (*fo_kqfilter)  (struct file *, struct knote *);
       void    (*fo_restart)   (struct file *);
-       void    (*fo_spare1)    (void);
+       int     (*fo_mmap)      (struct file *, off_t *, size_t, int, int *,
+                                int *, struct uvm_object **, int *);
       void    (*fo_spare2)    (void);
};

-/*
- * Kernel file descriptor.  One entry for each open kernel vnode and
- * socket.
- *
- * This structure is exported via the KERN_FILE and KERN_FILE2 sysctl
- * calls.  Only add members to the end, do not delete them.
- */
union file_data {
       struct vnode *fd_vp;            // DTYPE_VNODE
       struct socket *fd_so;           // DTYPE_SOCKET
@@ -115,6 +110,13 @@ union file_data {
       struct ksem *fd_ks;             // DTYPE_SEM
};

+/*
+ * Kernel file descriptor.  One entry for each open kernel vnode and
+ * socket.
+ *
+ * This structure is exported via the KERN_FILE and KERN_FILE2 sysctl
+ * calls.  Only add members to the end, do not delete them.
+ */
struct file {
       off_t           f_offset;       /* first, is 64-bit */
       kauth_cred_t    f_cred;         /* creds associated with descriptor */
Index: sys/uvm/uvm_extern.h
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.191
diff -u -p -r1.191 uvm_extern.h
--- sys/uvm/uvm_extern.h        7 Jul 2014 20:14:43 -0000       1.191
+++ sys/uvm/uvm_extern.h        21 Nov 2014 02:41:16 -0000
@@ -668,9 +668,9 @@ int                 uvm_pctparam_createsysctlnode(stru
                           const char *, const char *);

/* uvm_mmap.c */
-int                    uvm_mmap(struct vm_map *, vaddr_t *, vsize_t,
-                           vm_prot_t, vm_prot_t, int,
-                           void *, voff_t, vsize_t);
+int                    uvm_mmap_dev(struct proc *, void **, size_t, dev_t,
+                           off_t);
+int                    uvm_mmap_anon(struct proc *, void **, size_t);
vaddr_t                        uvm_default_mapaddr(struct proc *, vaddr_t, vsize_t);

/* uvm_mremap.c */
Index: sys/uvm/uvm_mmap.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.149
diff -u -p -r1.149 uvm_mmap.c
--- sys/uvm/uvm_mmap.c  5 Sep 2014 09:24:48 -0000       1.149
+++ sys/uvm/uvm_mmap.c  21 Nov 2014 02:48:11 -0000
@@ -78,9 +78,8 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_mmap.c,v
#include <uvm/uvm.h>
#include <uvm/uvm_device.h>

-#ifndef COMPAT_ZERODEV
-#define COMPAT_ZERODEV(dev)    (0)
-#endif
+static int uvm_mmap(struct vm_map *, vaddr_t *, vsize_t, vm_prot_t, vm_prot_t,
+                   int, int, struct uvm_object *, voff_t, vsize_t);

static int
range_test(vaddr_t addr, vsize_t size, bool ismmap)
@@ -301,15 +300,13 @@ sys_mmap(struct lwp *l, const struct sys
       } */
       struct proc *p = l->l_proc;
       vaddr_t addr;
-       struct vattr va;
       off_t pos;
       vsize_t size, pageoff;
       vm_prot_t prot, maxprot;
-       int flags, fd;
+       int flags, fd, advice;
       vaddr_t defaddr;
       struct file *fp = NULL;
-       struct vnode *vp;
-       void *handle;
+       struct uvm_object *uobj;
       int error;
#ifdef PAX_ASLR
       vaddr_t orig_addr;
@@ -368,8 +365,10 @@ sys_mmap(struct lwp *l, const struct sys
                       return (EINVAL);

               error = range_test(addr, size, true);
-               if (error)
+               if (error) {
                       return error;
+               }
+
       } else if (addr == 0 || !(flags & MAP_TRYFIXED)) {

               /*
@@ -393,113 +392,26 @@ sys_mmap(struct lwp *l, const struct sys
        * check for file mappings (i.e. not anonymous) and verify file.
        */

+       advice = UVM_ADV_NORMAL;
       if ((flags & MAP_ANON) == 0) {
               if ((fp = fd_getfile(fd)) == NULL)
                       return (EBADF);
-               if (fp->f_type != DTYPE_VNODE) {
-                       fd_putfile(fd);
-                       return (ENODEV);                /* only mmap vnodes! */
-               }
-               vp = fp->f_vnode;               /* convert to vnode */
-               if (vp->v_type != VREG && vp->v_type != VCHR &&
-                   vp->v_type != VBLK) {
-                       fd_putfile(fd);
-                       return (ENODEV);  /* only REG/CHR/BLK support mmap */
-               }
-               if (vp->v_type != VCHR && pos < 0) {
-                       fd_putfile(fd);
-                       return (EINVAL);
+
+               if (fp->f_ops->fo_mmap == NULL) {
+                       error = ENODEV;
+                       goto out;
               }
-               if (vp->v_type != VCHR && (off_t)(pos + size) < pos) {
-                       fd_putfile(fd);
-                       return (EOVERFLOW);             /* no offset wrapping */
+               error = (*fp->f_ops->fo_mmap)(fp, &pos, size, prot, &flags,
+                                             &advice, &uobj, &maxprot);
+               if (error) {
+                       goto out;
               }
-
-               /* special case: catch SunOS style /dev/zero */
-               if (vp->v_type == VCHR
-                   && (vp->v_rdev == zerodev || COMPAT_ZERODEV(vp->v_rdev))) {
+               if (uobj == NULL) {
                       flags |= MAP_ANON;
                       fd_putfile(fd);
                       fp = NULL;
                       goto is_anon;
               }
-
-               /*
-                * Old programs may not select a specific sharing type, so
-                * default to an appropriate one.
-                *
-                * XXX: how does MAP_ANON fit in the picture?
-                */
-               if ((flags & (MAP_SHARED|MAP_PRIVATE)) == 0) {
-#if defined(DEBUG)
-                       printf("WARNING: defaulted mmap() share type to "
-                          "%s (pid %d command %s)\n", vp->v_type == VCHR ?
-                          "MAP_SHARED" : "MAP_PRIVATE", p->p_pid,
-                           p->p_comm);
-#endif
-                       if (vp->v_type == VCHR)
-                               flags |= MAP_SHARED;    /* for a device */
-                       else
-                               flags |= MAP_PRIVATE;   /* for a file */
-               }
-
-               /*
-                * MAP_PRIVATE device mappings don't make sense (and aren't
-                * supported anyway).  However, some programs rely on this,
-                * so just change it to MAP_SHARED.
-                */
-               if (vp->v_type == VCHR && (flags & MAP_PRIVATE) != 0) {
-                       flags = (flags & ~MAP_PRIVATE) | MAP_SHARED;
-               }
-
-               /*
-                * now check protection
-                */
-
-               maxprot = VM_PROT_EXECUTE;
-
-               /* check read access */
-               if (fp->f_flag & FREAD)
-                       maxprot |= VM_PROT_READ;
-               else if (prot & PROT_READ) {
-                       fd_putfile(fd);
-                       return (EACCES);
-               }
-
-               /* check write access, shared case first */
-               if (flags & MAP_SHARED) {
-                       /*
-                        * if the file is writable, only add PROT_WRITE to
-                        * maxprot if the file is not immutable, append-only.
-                        * otherwise, if we have asked for PROT_WRITE, return
-                        * EPERM.
-                        */
-                       if (fp->f_flag & FWRITE) {
-                               vn_lock(vp, LK_SHARED | LK_RETRY);
-                               error = VOP_GETATTR(vp, &va, l->l_cred);
-                               VOP_UNLOCK(vp);
-                               if (error) {
-                                       fd_putfile(fd);
-                                       return (error);
-                               }
-                               if ((va.va_flags &
-                                   (SF_SNAPSHOT|IMMUTABLE|APPEND)) == 0)
-                                       maxprot |= VM_PROT_WRITE;
-                               else if (prot & PROT_WRITE) {
-                                       fd_putfile(fd);
-                                       return (EPERM);
-                               }
-                       }
-                       else if (prot & PROT_WRITE) {
-                               fd_putfile(fd);
-                               return (EACCES);
-                       }
-               } else {
-                       /* MAP_PRIVATE mappings can always write to */
-                       maxprot |= VM_PROT_WRITE;
-               }
-               handle = vp;
-
       } else {                /* MAP_ANON case */
               /*
                * XXX What do we do about (MAP_SHARED|MAP_PRIVATE) == 0?
@@ -508,41 +420,11 @@ sys_mmap(struct lwp *l, const struct sys
                       return (EINVAL);

 is_anon:              /* label for SunOS style /dev/zero */
-               handle = NULL;
+               uobj = NULL;
               maxprot = VM_PROT_ALL;
               pos = 0;
       }

-#if NVERIEXEC > 0
-       if (handle != NULL) {
-               /*
-                * Check if the file can be executed indirectly.
-                *
-                * XXX: This gives false warnings about "Incorrect access type"
-                * XXX: if the mapping is not executable. Harmless, but will be
-                * XXX: fixed as part of other changes.
-                */
-               if (veriexec_verify(l, handle, "(mmap)", VERIEXEC_INDIRECT,
-                   NULL)) {
-                       /*
-                        * Don't allow executable mappings if we can't
-                        * indirectly execute the file.
-                        */
-                       if (prot & VM_PROT_EXECUTE) {
-                               if (fp != NULL)
-                                       fd_putfile(fd);
-                               return (EPERM);
-                       }
-
-                       /*
-                        * Strip the executable bit from 'maxprot' to make sure
-                        * it can't be made executable later.
-                        */
-                       maxprot &= ~VM_PROT_EXECUTE;
-               }
-       }
-#endif /* NVERIEXEC > 0 */
-
#ifdef PAX_MPROTECT
       pax_mprotect(l, &prot, &maxprot);
#endif /* PAX_MPROTECT */
@@ -556,12 +438,12 @@ sys_mmap(struct lwp *l, const struct sys
        */

       error = uvm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot,
-           flags, handle, pos, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+           flags, advice, uobj, pos, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);

-       if (error == 0)
-               /* remember to add offset */
-               *retval = (register_t)(addr + pageoff);
+       /* remember to add offset */
+       *retval = (register_t)(addr + pageoff);

+ out:
       if (fp != NULL)
               fd_putfile(fd);

@@ -1045,21 +927,18 @@ sys_munlockall(struct lwp *l, const void
 * uvm_mmap: internal version of mmap
 *
 * - used by sys_mmap and various framebuffers
- * - handle is a vnode pointer or NULL for MAP_ANON
+ * - uobj is a struct uvm_object pointer or NULL for MAP_ANON
 * - caller must page-align the file offset
 */

int
uvm_mmap(struct vm_map *map, vaddr_t *addr, vsize_t size, vm_prot_t prot,
-    vm_prot_t maxprot, int flags, void *handle, voff_t foff, vsize_t locklimit)
+    vm_prot_t maxprot, int flags, int advice, struct uvm_object *uobj,
+    voff_t foff, vsize_t locklimit)
{
-       struct uvm_object *uobj;
-       struct vnode *vp;
       vaddr_t align = 0;
       int error;
-       int advice = UVM_ADV_NORMAL;
       uvm_flag_t uvmflag = 0;
-       bool needwritemap;

       /*
        * check params
@@ -1125,9 +1004,8 @@ uvm_mmap(struct vm_map *map, vaddr_t *ad
        */

       if (flags & MAP_ANON) {
-               KASSERT(handle == NULL);
+               KASSERT(uobj == NULL);
               foff = UVM_UNKNOWN_OFFSET;
-               uobj = NULL;
               if ((flags & MAP_SHARED) == 0)
                       /* XXX: defer amap create */
                       uvmflag |= UVM_FLAG_COPYONW;
@@ -1136,75 +1014,10 @@ uvm_mmap(struct vm_map *map, vaddr_t *ad
                       uvmflag |= UVM_FLAG_OVERLAY;

       } else {
-               KASSERT(handle != NULL);
-               vp = (struct vnode *)handle;
-
-               /*
-                * Don't allow mmap for EXEC if the file system
-                * is mounted NOEXEC.
-                */
-               if ((prot & PROT_EXEC) != 0 &&
-                   (vp->v_mount->mnt_flag & MNT_NOEXEC) != 0)
-                       return (EACCES);
-
-               if (vp->v_type != VCHR) {
-                       error = VOP_MMAP(vp, prot, curlwp->l_cred);
-                       if (error) {
-                               return error;
-                       }
-                       vref(vp);
-                       uobj = &vp->v_uobj;
-
-                       /*
-                        * If the vnode is being mapped with PROT_EXEC,
-                        * then mark it as text.
-                        */
-                       if (prot & PROT_EXEC) {
-                               vn_markexec(vp);
-                       }
-               } else {
-                       int i = maxprot;
-
-                       /*
-                        * XXX Some devices don't like to be mapped with
-                        * XXX PROT_EXEC or PROT_WRITE, but we don't really
-                        * XXX have a better way of handling this, right now
-                        */
-                       do {
-                               uobj = udv_attach((void *) &vp->v_rdev,
-                                   (flags & MAP_SHARED) ? i :
-                                   (i & ~VM_PROT_WRITE), foff, size);
-                               i--;
-                       } while ((uobj == NULL) && (i > 0));
-                       if (uobj == NULL)
-                               return EINVAL;
-                       advice = UVM_ADV_RANDOM;
-               }
+               KASSERT(uobj != NULL);
               if ((flags & MAP_SHARED) == 0) {
                       uvmflag |= UVM_FLAG_COPYONW;
               }
-
-               /*
-                * Set vnode flags to indicate the new kinds of mapping.
-                * We take the vnode lock in exclusive mode here to serialize
-                * with direct I/O.
-                *
-                * Safe to check for these flag values without a lock, as
-                * long as a reference to the vnode is held.
-                */
-               needwritemap = (vp->v_iflag & VI_WRMAP) == 0 &&
-                       (flags & MAP_SHARED) != 0 &&
-                       (maxprot & VM_PROT_WRITE) != 0;
-               if ((vp->v_vflag & VV_MAPPED) == 0 || needwritemap) {
-                       vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
-                       vp->v_vflag |= VV_MAPPED;
-                       if (needwritemap) {
-                               mutex_enter(vp->v_interlock);
-                               vp->v_iflag |= VI_WRMAP;
-                               mutex_exit(vp->v_interlock);
-                       }
-                       VOP_UNLOCK(vp);
-               }
       }

       uvmflag = UVM_MAPFLAG(prot, maxprot,
@@ -1267,3 +1080,48 @@ uvm_default_mapaddr(struct proc *p, vadd
       else
               return VM_DEFAULT_ADDRESS_BOTTOMUP(base, sz);
}
+
+int
+uvm_mmap_dev(struct proc *p, void **addrp, size_t len, dev_t dev,
+    off_t off)
+{
+       struct uvm_object *uobj;
+       int error, flags, prot;
+
+       flags = MAP_SHARED;
+       prot = VM_PROT_READ | VM_PROT_WRITE;
+       if (*addrp)
+               flags |= MAP_FIXED;
+       else
+               *addrp = (void *)p->p_emul->e_vm_default_addr(p,
+                   (vaddr_t)p->p_vmspace->vm_daddr, len);
+
+       uobj = udv_attach(dev, prot, 0, len);
+       if (uobj == NULL)
+               return EINVAL;
+
+       error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp,
+                        (vsize_t)len, prot, prot, flags, UVM_ADV_RANDOM,
+                        uobj, 0, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+       return error;
+}
+
+int
+uvm_mmap_anon(struct proc *p, void **addrp, size_t len)
+{
+       int error, flags, prot;
+
+       flags = MAP_PRIVATE | MAP_ANON;
+       prot = VM_PROT_READ | VM_PROT_WRITE;
+       if (*addrp)
+               flags |= MAP_FIXED;
+       else
+               *addrp = (void *)p->p_emul->e_vm_default_addr(p,
+                   (vaddr_t)p->p_vmspace->vm_daddr, len);
+
+       error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp,
+                        (vsize_t)len, prot, prot, flags, UVM_ADV_NORMAL,
+                        NULL, 0, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+       return error;
+
+}
Index: sys/uvm/uvm_device.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/uvm/uvm_device.c,v
retrieving revision 1.63
diff -u -p -r1.63 uvm_device.c
--- sys/uvm/uvm_device.c        27 Jan 2012 19:48:41 -0000      1.63
+++ sys/uvm/uvm_device.c        19 Nov 2014 16:12:20 -0000
@@ -106,11 +106,10 @@ udv_init(void)
 */

struct uvm_object *
-udv_attach(void *arg, vm_prot_t accessprot,
+udv_attach(dev_t device, vm_prot_t accessprot,
    voff_t off,                /* used only for access check */
    vsize_t size       /* used only for access check */)
{
-       dev_t device = *((dev_t *)arg);
       struct uvm_device *udv, *lcv;
       const struct cdevsw *cdev;
       dev_type_mmap((*mapfn));
Index: sys/uvm/uvm_device.h
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/uvm/uvm_device.h,v
retrieving revision 1.12
diff -u -p -r1.12 uvm_device.h
--- sys/uvm/uvm_device.h        2 Feb 2011 15:13:34 -0000       1.12
+++ sys/uvm/uvm_device.h        19 Nov 2014 16:12:41 -0000
@@ -62,7 +62,7 @@ struct uvm_device {
 * prototypes
 */

-struct uvm_object *udv_attach(void *, vm_prot_t, voff_t, vsize_t);
+struct uvm_object *udv_attach(dev_t, vm_prot_t, voff_t, vsize_t);

#endif /* _KERNEL */

Index: sys/kern/vfs_vnops.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/kern/vfs_vnops.c,v
retrieving revision 1.191
diff -u -p -r1.191 vfs_vnops.c
--- sys/kern/vfs_vnops.c        5 Sep 2014 09:20:59 -0000       1.191
+++ sys/kern/vfs_vnops.c        19 Nov 2014 16:30:00 -0000
@@ -89,17 +89,23 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,
#include <sys/atomic.h>
#include <sys/filedesc.h>
#include <sys/wapbl.h>
+#include <sys/mman.h>

#include <miscfs/specfs/specdev.h>
#include <miscfs/fifofs/fifo.h>

#include <uvm/uvm_extern.h>
#include <uvm/uvm_readahead.h>
+#include <uvm/uvm_device.h>

#ifdef UNION
#include <fs/union/union.h>
#endif

+#ifndef COMPAT_ZERODEV
+#define COMPAT_ZERODEV(dev)    (0)
+#endif
+
int (*vn_union_readdir_hook) (struct vnode **, struct file *, struct lwp *);

#include <sys/verified_exec.h>
@@ -113,6 +119,8 @@ static int vn_poll(file_t *fp, int event
static int vn_fcntl(file_t *fp, u_int com, void *data);
static int vn_statfile(file_t *fp, struct stat *sb);
static int vn_ioctl(file_t *fp, u_long com, void *data);
+static int vn_mmap(struct file *, off_t *, size_t, int, int *, int *,
+                  struct uvm_object **, int *);

const struct fileops vnops = {
       .fo_read = vn_read,
@@ -124,6 +132,7 @@ const struct fileops vnops = {
       .fo_close = vn_closefile,
       .fo_kqfilter = vn_kqfilter,
       .fo_restart = fnullop_restart,
+       .fo_mmap = vn_mmap,
};

/*
@@ -789,6 +798,219 @@ vn_kqfilter(file_t *fp, struct knote *kn
       return (VOP_KQFILTER(fp->f_vnode, kn));
}

+static int
+vn_mmap(struct file *fp, off_t *offp, size_t size, int prot, int *flagsp,
+       int *advicep, struct uvm_object **uobjp, int *maxprotp)
+{
+       struct uvm_object *uobj;
+       struct vnode *vp;
+       struct vattr va;
+       struct lwp *l;
+       vm_prot_t maxprot;
+       off_t off;
+       int error, flags;
+       bool needwritemap;
+
+       l = curlwp;
+
+       off = *offp;
+       flags = *flagsp;
+       maxprot = VM_PROT_EXECUTE;
+
+       vp = fp->f_vnode;
+       if (vp->v_type != VREG && vp->v_type != VCHR &&
+           vp->v_type != VBLK) {
+               /* only REG/CHR/BLK support mmap */
+               return ENODEV;
+       }
+       if (vp->v_type != VCHR && off < 0) {
+               return EINVAL;
+       }
+       if (vp->v_type != VCHR && (off_t)(off + size) < off) {
+               /* no offset wrapping */
+               return EOVERFLOW;
+       }
+
+       /* special case: catch SunOS style /dev/zero */
+       if (vp->v_type == VCHR &&
+           (vp->v_rdev == zerodev || COMPAT_ZERODEV(vp->v_rdev))) {
+               *uobjp = NULL;
+               *maxprotp = VM_PROT_ALL;
+               return 0;
+       }
+
+       /*
+        * Old programs may not select a specific sharing type, so
+        * default to an appropriate one.
+        *
+        * XXX: how does MAP_ANON fit in the picture?
+        */
+       if ((flags & (MAP_SHARED|MAP_PRIVATE)) == 0) {
+#if defined(DEBUG)
+               struct proc *p = l->l_proc;
+               printf("WARNING: defaulted mmap() share type to "
+                      "%s (pid %d command %s)\n", vp->v_type == VCHR ?
+                      "MAP_SHARED" : "MAP_PRIVATE", p->p_pid,
+                      p->p_comm);
+#endif
+               if (vp->v_type == VCHR)
+                       flags |= MAP_SHARED;    /* for a device */
+               else
+                       flags |= MAP_PRIVATE;   /* for a file */
+       }
+
+       /*
+        * MAP_PRIVATE device mappings don't make sense (and aren't
+        * supported anyway).  However, some programs rely on this,
+        * so just change it to MAP_SHARED.
+        */
+       if (vp->v_type == VCHR && (flags & MAP_PRIVATE) != 0) {
+               flags = (flags & ~MAP_PRIVATE) | MAP_SHARED;
+       }
+
+       /*
+        * now check protection
+        */
+
+       /* check read access */
+       if (fp->f_flag & FREAD)
+               maxprot |= VM_PROT_READ;
+       else if (prot & PROT_READ) {
+               return EACCES;
+       }
+
+       /* check write access, shared case first */
+       if (flags & MAP_SHARED) {
+               /*
+                * if the file is writable, only add PROT_WRITE to
+                * maxprot if the file is not immutable, append-only.
+                * otherwise, if we have asked for PROT_WRITE, return
+                * EPERM.
+                */
+               if (fp->f_flag & FWRITE) {
+                       vn_lock(vp, LK_SHARED | LK_RETRY);
+                       error = VOP_GETATTR(vp, &va, l->l_cred);
+                       VOP_UNLOCK(vp);
+                       if (error) {
+                               return error;
+                       }
+                       if ((va.va_flags &
+                            (SF_SNAPSHOT|IMMUTABLE|APPEND)) == 0)
+                               maxprot |= VM_PROT_WRITE;
+                       else if (prot & PROT_WRITE) {
+                               return EPERM;
+                       }
+               } else if (prot & PROT_WRITE) {
+                       return EACCES;
+               }
+       } else {
+               /* MAP_PRIVATE mappings can always write to */
+               maxprot |= VM_PROT_WRITE;
+       }
+
+       /*
+        * Don't allow mmap for EXEC if the file system
+        * is mounted NOEXEC.
+        */
+       if ((prot & PROT_EXEC) != 0 &&
+           (vp->v_mount->mnt_flag & MNT_NOEXEC) != 0) {
+               return EACCES;
+       }
+
+       if (vp->v_type != VCHR) {
+               error = VOP_MMAP(vp, prot, curlwp->l_cred);
+               if (error) {
+                       return error;
+               }
+               vref(vp);
+               uobj = &vp->v_uobj;
+
+               /*
+                * If the vnode is being mapped with PROT_EXEC,
+                * then mark it as text.
+                */
+               if (prot & PROT_EXEC) {
+                       vn_markexec(vp);
+               }
+       } else {
+               int i = maxprot;
+
+               /*
+                * XXX Some devices don't like to be mapped with
+                * XXX PROT_EXEC or PROT_WRITE, but we don't really
+                * XXX have a better way of handling this, right now
+                */
+               do {
+                       uobj = udv_attach(vp->v_rdev,
+                                         (flags & MAP_SHARED) ? i :
+                                         (i & ~VM_PROT_WRITE), off, size);
+                       i--;
+               } while ((uobj == NULL) && (i > 0));
+               if (uobj == NULL) {
+                       return EINVAL;
+               }
+               *advicep = UVM_ADV_RANDOM;
+       }
+
+       /*
+        * Set vnode flags to indicate the new kinds of mapping.
+        * We take the vnode lock in exclusive mode here to serialize
+        * with direct I/O.
+        *
+        * Safe to check for these flag values without a lock, as
+        * long as a reference to the vnode is held.
+        */
+       needwritemap = (vp->v_iflag & VI_WRMAP) == 0 &&
+               (flags & MAP_SHARED) != 0 &&
+               (maxprot & VM_PROT_WRITE) != 0;
+       if ((vp->v_vflag & VV_MAPPED) == 0 || needwritemap) {
+               vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+               vp->v_vflag |= VV_MAPPED;
+               if (needwritemap) {
+                       mutex_enter(vp->v_interlock);
+                       vp->v_iflag |= VI_WRMAP;
+                       mutex_exit(vp->v_interlock);
+               }
+               VOP_UNLOCK(vp);
+       }
+
+#if NVERIEXEC > 0
+
+       /*
+        * Check if the file can be executed indirectly.
+        *
+        * XXX: This gives false warnings about "Incorrect access type"
+        * XXX: if the mapping is not executable. Harmless, but will be
+        * XXX: fixed as part of other changes.
+        */
+       if (veriexec_verify(l, vp, "(mmap)", VERIEXEC_INDIRECT,
+                           NULL)) {
+
+               /*
+                * Don't allow executable mappings if we can't
+                * indirectly execute the file.
+                */
+               if (prot & VM_PROT_EXECUTE) {
+                       return EPERM;
+               }
+
+               /*
+                * Strip the executable bit from 'maxprot' to make sure
+                * it can't be made executable later.
+                */
+               maxprot &= ~VM_PROT_EXECUTE;
+       }
+#endif /* NVERIEXEC > 0 */
+
+       *uobjp = uobj;
+       *maxprotp = maxprot;
+       *flagsp = flags;
+
+       return 0;
+}
+
+
+
/*
 * Check that the vnode is still valid, and if so
 * acquire requested lock.
Index: common/lib/libprop/prop_kern.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/common/lib/libprop/prop_kern.c,v
retrieving revision 1.17
diff -u -p -r1.17 prop_kern.c
--- common/lib/libprop/prop_kern.c      30 Sep 2011 22:08:18 -0000      1.17
+++ common/lib/libprop/prop_kern.c      21 Nov 2014 02:47:43 -0000
@@ -507,9 +507,9 @@ _prop_object_copyout(struct plistref *pr
       struct lwp *l = curlwp;         /* XXX */
       struct proc *p = l->l_proc;
       char *buf;
+       void *uaddr;
       size_t len, rlen;
       int error = 0;
-       vaddr_t uaddr;

       switch (prop_object_type(obj)) {
       case PROP_TYPE_ARRAY:
@@ -526,26 +526,12 @@ _prop_object_copyout(struct plistref *pr

       len = strlen(buf) + 1;
       rlen = round_page(len);
-
-       /*
-        * See sys_mmap() in sys/uvm/uvm_mmap.c.
-        * Let's act as if we were calling mmap(0, ...)
-        */
-       uaddr = p->p_emul->e_vm_default_addr(p,
-           (vaddr_t)p->p_vmspace->vm_daddr, rlen);
-
-       error = uvm_mmap(&p->p_vmspace->vm_map,
-                        &uaddr, rlen,
-                        VM_PROT_READ|VM_PROT_WRITE,
-                        VM_PROT_READ|VM_PROT_WRITE,
-                        MAP_PRIVATE|MAP_ANON,
-                        NULL, 0,
-                        p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
-
+       uaddr = NULL;
+       error = uvm_mmap_anon(p, &uaddr, rlen);
       if (error == 0) {
-               error = copyout(buf, (char *)uaddr, len);
+               error = copyout(buf, uaddr, len);
               if (error == 0) {
-                       pref->pref_plist = (char *)uaddr;
+                       pref->pref_plist = uaddr;
                       pref->pref_len   = len;
               }
       }
Index: sys/arch/mac68k/dev/grf_compat.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/arch/mac68k/dev/grf_compat.c,v
retrieving revision 1.26
diff -u -p -r1.26 grf_compat.c
--- sys/arch/mac68k/dev/grf_compat.c    25 Jul 2014 08:10:33 -0000      1.26
+++ sys/arch/mac68k/dev/grf_compat.c    21 Nov 2014 02:48:52 -0000
@@ -59,6 +59,7 @@ __KERNEL_RCSID(0, "$NetBSD: grf_compat.c
#include <miscfs/specfs/specdev.h>

#include <uvm/uvm_extern.h>
+#include <uvm/uvm_device.h>
#include <uvm/uvm_map.h>

dev_type_open(grfopen);
@@ -320,24 +321,14 @@ grfmmap(dev_t dev, off_t off, int prot)
int
grfmap(dev_t dev, struct macfb_softc *sc, void **addrp, struct proc *p)
{
-       struct vnode vn;
-       u_long len;
-       int error, flags;
+       size_t len;
+       int error;

       len = m68k_round_page(sc->sc_dc->dc_offset + sc->sc_dc->dc_size);
-       *addrp = (void *)p->p_emul->e_vm_default_addr(p,
-           (vaddr_t)p->p_vmspace->vm_daddr, len);
-       flags = MAP_SHARED | MAP_FIXED;
-
-       vn.v_type = VCHR;               /* XXX */
-       vn.v_rdev = dev;                /* XXX */
-
-       error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp,
-           (vsize_t)len, VM_PROT_ALL, VM_PROT_ALL,
-           flags, (void *)&vn, 0, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+       error = uvm_mmap_dev(p, addrp, len, dev, 0);

       /* Offset into page: */
-       *addrp = (char*)*addrp + sc->sc_dc->dc_offset;
+       *addrp = (char *)*addrp + sc->sc_dc->dc_offset;

       return (error);
}
@@ -345,9 +336,9 @@ grfmap(dev_t dev, struct macfb_softc *sc
int
grfunmap(dev_t dev, struct macfb_softc *sc, void *addr, struct proc *p)
{
-       vm_size_t size;
+       size_t size;

-       addr = (char*)addr - sc->sc_dc->dc_offset;
+       addr = (char *)addr - sc->sc_dc->dc_offset;

       if (addr <= 0)
               return (-1);
Index: sys/arch/x68k/dev/grf.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/arch/x68k/dev/grf.c,v
retrieving revision 1.44
diff -u -p -r1.44 grf.c
--- sys/arch/x68k/dev/grf.c     25 Jul 2014 08:10:35 -0000      1.44
+++ sys/arch/x68k/dev/grf.c     21 Nov 2014 02:46:27 -0000
@@ -66,6 +66,7 @@ __KERNEL_RCSID(0, "$NetBSD: grf.c,v 1.44
#include <x68k/dev/itevar.h>

#include <uvm/uvm_extern.h>
+#include <uvm/uvm_device.h>
#include <uvm/uvm_map.h>

#include <miscfs/specfs/specdev.h>
@@ -266,9 +267,8 @@ int
grfmap(dev_t dev, void **addrp, struct proc *p)
{
       struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev));
-       int len, error;
-       struct vnode vn;
-       int flags;
+       size_t len;
+       int error;

#ifdef DEBUG
       if (grfdebug & GDB_MMAP)
@@ -276,19 +276,8 @@ grfmap(dev_t dev, void **addrp, struct p
#endif

       len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize;
-       flags = MAP_SHARED;
-       if (*addrp)
-               flags |= MAP_FIXED;
-       else
-               *addrp = (void *)p->p_emul->e_vm_default_addr(p,
-                   (vaddr_t)p->p_vmspace->vm_daddr, len);
-
-       vn.v_type = VCHR;                       /* XXX */
-       vn.v_rdev = dev;                        /* XXX */
-       error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp,
-                        (vsize_t)len, VM_PROT_ALL, VM_PROT_ALL,
-                        flags, (void *)&vn, 0,
-                        p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+
+       error = uvm_mmap_dev(p, addrp, len, dev, 0);
       if (error == 0)
               (void) (*gp->g_sw->gd_mode)(gp, GM_MAP, *addrp);

Index: sys/external/bsd/drm2/drm/drm_drv.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/external/bsd/drm2/drm/drm_drv.c,v
retrieving revision 1.10
diff -u -p -r1.10 drm_drv.c
--- sys/external/bsd/drm2/drm/drm_drv.c 4 Nov 2014 11:27:31 -0000       1.10
+++ sys/external/bsd/drm2/drm/drm_drv.c 19 Nov 2014 17:05:26 -0000
@@ -72,11 +72,12 @@ static int  drm_poll(struct file *, int);
static int     drm_kqfilter(struct file *, struct knote *);
static int     drm_stat(struct file *, struct stat *);
static int     drm_ioctl(struct file *, unsigned long, void *);
+static int     drm_fop_mmap(struct file *, off_t *, size_t, int, int *, int *,
+                            struct uvm_object **, int *);
static int     drm_version_string(char *, size_t *, const char *);
static paddr_t drm_mmap(dev_t, off_t, int);

static drm_ioctl_t     drm_version;
-static drm_ioctl_t     drm_mmap_ioctl;

#define        DRM_IOCTL_DEF(IOCTL, FUNC, FLAGS)                               \
       [DRM_IOCTL_NR(IOCTL)] = {                                       \
@@ -215,10 +216,6 @@ static const struct drm_ioctl_desc drm_i
       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
       DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-
-#ifdef __NetBSD__
-       DRM_IOCTL_DEF(DRM_IOCTL_MMAP, drm_mmap_ioctl, DRM_UNLOCKED),
-#endif
};

const struct cdevsw drm_cdevsw = {
@@ -247,6 +244,7 @@ static const struct fileops drm_fileops
       .fo_close = drm_close,
       .fo_kqfilter = drm_kqfilter,
       .fo_restart = fnullop_restart,
+       .fo_mmap = drm_fop_mmap,
};

static int
@@ -669,6 +667,22 @@ drm_ioctl(struct file *fp, unsigned long
}

static int
+drm_fop_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp,
+            int *advicep, struct uvm_object **uobjp, int *maxprotp)
+{
+       struct drm_file *const file = fp->f_data;
+       struct drm_device *const dev = file->minor->dev;
+       int error;
+
+       KASSERT(fp == file->filp);
+       error = (*dev->driver->mmap_object)(dev, *offp, len, prot, uobjp,
+           offp, file->filp);
+       *maxprotp = prot;
+       *advicep = UVM_ADV_RANDOM;
+       return -error;
+}
+
+static int
drm_version_string(char *target, size_t *lenp, const char *source)
{
       const size_t len = strlen(source);
@@ -722,66 +736,6 @@ drm_mmap(dev_t d, off_t offset, int prot
       return paddr;
}

-static int
-drm_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
-{
-       struct drm_mmap *const args = data;
-       void *addr = args->dnm_addr;
-       const size_t size = args->dnm_size;
-       const int prot = args->dnm_prot;
-       const int flags = args->dnm_flags;
-       const off_t offset = args->dnm_offset;
-       struct uvm_object *uobj;
-       voff_t uoffset;
-       const vm_prot_t vm_maxprot = (VM_PROT_READ | VM_PROT_WRITE);
-       vm_prot_t vm_prot;
-       int uvmflag;
-       vaddr_t align, vaddr;
-       int ret;
-
-       /* XXX Copypasta from drm_gem_mmap.  */
-       if (drm_device_is_unplugged(dev))
-               return -ENODEV;
-
-       if (prot != (prot & (PROT_READ | PROT_WRITE)))
-               return -EACCES;
-       if (flags != MAP_SHARED)
-               return -EINVAL;
-       if (offset != (offset & ~(PAGE_SIZE-1)))
-               return -EINVAL;
-       if (size != (size & ~(PAGE_SIZE-1)))
-               return -EINVAL;
-       (void)addr;             /* XXX ignore -- no MAP_FIXED for now */
-
-       ret = (*dev->driver->mmap_object)(dev, offset, size, prot, &uobj,
-           &uoffset, file->filp);
-       if (ret)
-               return ret;
-       if (uobj == NULL)
-               return -EINVAL;
-
-       vm_prot = ((ISSET(prot, PROT_READ)? VM_PROT_READ : 0) |
-           (ISSET(prot, PROT_WRITE)? VM_PROT_WRITE : 0));
-       KASSERT(vm_prot == (vm_prot & vm_maxprot));
-       uvmflag = UVM_MAPFLAG(vm_prot, vm_maxprot, UVM_INH_COPY,
-           UVM_ADV_RANDOM, 0);
-
-       align = 0;              /* XXX */
-       vaddr = (*curproc->p_emul->e_vm_default_addr)(curproc,
-           (vaddr_t)curproc->p_vmspace->vm_daddr, size);
-       /* XXX errno NetBSD->Linux */
-       ret = -uvm_map(&curproc->p_vmspace->vm_map, &vaddr, size, uobj,
-           uoffset, align, uvmflag);
-       if (ret) {
-               (*uobj->pgops->pgo_detach)(uobj);
-               return ret;
-       }
-
-       /* Success!  */
-       args->dnm_addr = (void *)vaddr;
-       return 0;
-}
-
static const struct drm_agp_hooks *volatile drm_current_agp_hooks;

int
Index: sys/external/bsd/drm2/drm/drm_vm.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/external/bsd/drm2/drm/drm_vm.c,v
retrieving revision 1.5
diff -u -p -r1.5 drm_vm.c
--- sys/external/bsd/drm2/drm/drm_vm.c  26 Jul 2014 21:15:45 -0000      1.5
+++ sys/external/bsd/drm2/drm/drm_vm.c  19 Nov 2014 16:30:51 -0000
@@ -59,7 +59,7 @@ drm_mmap_object(struct drm_device *dev,
        * access checks; offset does not become a base address for the
        * subsequent uvm_map, hence we set *uoffsetp to offset, not 0.
        */
-       uobj = udv_attach(&devno, prot, offset, size);
+       uobj = udv_attach(devno, prot, offset, size);
       if (uobj == NULL)
               return -EINVAL;

Index: sys/external/bsd/drm2/include/linux/mm.h
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/external/bsd/drm2/include/linux/mm.h,v
retrieving revision 1.3
diff -u -p -r1.3 mm.h
--- sys/external/bsd/drm2/include/linux/mm.h    16 Jul 2014 20:59:58 -0000      1.3
+++ sys/external/bsd/drm2/include/linux/mm.h    21 Nov 2014 02:45:41 -0000
@@ -38,8 +38,9 @@
#include <sys/proc.h>
#include <sys/vnode.h>

+#include <miscfs/specfs/specdev.h>
+
#include <uvm/uvm_extern.h>
-#include <uvm/uvm_map.h>

#include <asm/page.h>

@@ -82,8 +83,8 @@ static inline unsigned long
vm_mmap(struct file *file, unsigned long base, unsigned long size,
    unsigned long prot, unsigned long flags, unsigned long token)
{
-       struct vnode *vnode;
-       vaddr_t addr;
+       struct vnode *vp;
+       void *addr;
       int error;

       /*
@@ -96,38 +97,19 @@ vm_mmap(struct file *file, unsigned long
       KASSERT(flags == MAP_SHARED);

       KASSERT(file->f_type == DTYPE_VNODE);
-       vnode = file->f_data;
+       vp = file->f_data;

-       KASSERT(vnode->v_type == VCHR);
+       KASSERT(vp->v_type == VCHR);
       KASSERT((file->f_flag & (FREAD | FWRITE)) == (FREAD | FWRITE));

-       {
-               struct vattr va;
-
-               vn_lock(vnode, (LK_SHARED | LK_RETRY));
-               error = VOP_GETATTR(vnode, &va, kauth_cred_get());
-               VOP_UNLOCK(vnode);
-               if (error)
-                       goto out;
-               /* XXX kassert?  */
-               if ((va.va_flags & (SF_SNAPSHOT | IMMUTABLE | APPEND)) != 0) {
-                       error = EACCES;
-                       goto out;
-               }
-       }
-
       /* XXX pax_mprotect?  pax_aslr?  */

-       addr = (*curproc->p_emul->e_vm_default_addr)(curproc,
-           (vaddr_t)curproc->p_vmspace->vm_daddr, size);
-       error = uvm_mmap(&curproc->p_vmspace->vm_map, &addr, size,
-           (VM_PROT_READ | VM_PROT_WRITE), (VM_PROT_READ | VM_PROT_WRITE),
-           MAP_SHARED, vnode, base,
-           curproc->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+       addr = NULL;
+       error = uvm_mmap_dev(curproc, &addr, size, vp->v_rdev, (off_t)base);
       if (error)
               goto out;

-       KASSERT(addr <= -1024UL); /* XXX Kludgerosity!  */
+       KASSERT((uintptr_t)addr <= -1024UL); /* XXX Kludgerosity!  */

out:   /* XXX errno NetBSD->Linux (kludgerific) */
       return (error? (-error) : (unsigned long)addr);