Module Name:    src
Committed By:   chs
Date:           Sun Dec 14 23:48:59 UTC 2014

Modified Files:
        src/common/lib/libprop: prop_kern.c
        src/sys/arch/mac68k/dev: grf_compat.c
        src/sys/arch/x68k/dev: grf.c
        src/sys/external/bsd/drm/dist/bsd-core: drm_bufs.c
        src/sys/external/bsd/drm2/drm: drm_drv.c drm_vm.c
        src/sys/external/bsd/drm2/include/linux: mm.h
        src/sys/kern: vfs_vnops.c
        src/sys/rump/librump/rumpkern: vm.c
        src/sys/sys: file.h
        src/sys/uvm: uvm_device.c uvm_device.h uvm_extern.h uvm_mmap.c

Log Message:
add a new "fo_mmap" fileops method to allow use of arbitrary uvm_objects for
mappings of file objects.  move vnode-specific details of mmap()ing a vnode
from uvm_mmap() to the new vnode-specific vn_mmap().  add new uvm_mmap_dev()
and uvm_mmap_anon() convenience functions for mapping character devices
and anonymous memory, and replace all other calls to uvm_mmap() with those.
use the new fileop in drm2 so that libdrm can use mmap() to map things
like on other platforms (instead of the ioctl that we have used so far).


To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/common/lib/libprop/prop_kern.c
cvs rdiff -u -r1.26 -r1.27 src/sys/arch/mac68k/dev/grf_compat.c
cvs rdiff -u -r1.44 -r1.45 src/sys/arch/x68k/dev/grf.c
cvs rdiff -u -r1.11 -r1.12 src/sys/external/bsd/drm/dist/bsd-core/drm_bufs.c
cvs rdiff -u -r1.11 -r1.12 src/sys/external/bsd/drm2/drm/drm_drv.c
cvs rdiff -u -r1.5 -r1.6 src/sys/external/bsd/drm2/drm/drm_vm.c
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/include/linux/mm.h
cvs rdiff -u -r1.191 -r1.192 src/sys/kern/vfs_vnops.c
cvs rdiff -u -r1.159 -r1.160 src/sys/rump/librump/rumpkern/vm.c
cvs rdiff -u -r1.77 -r1.78 src/sys/sys/file.h
cvs rdiff -u -r1.63 -r1.64 src/sys/uvm/uvm_device.c
cvs rdiff -u -r1.12 -r1.13 src/sys/uvm/uvm_device.h
cvs rdiff -u -r1.191 -r1.192 src/sys/uvm/uvm_extern.h
cvs rdiff -u -r1.149 -r1.150 src/sys/uvm/uvm_mmap.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/common/lib/libprop/prop_kern.c
diff -u src/common/lib/libprop/prop_kern.c:1.17 src/common/lib/libprop/prop_kern.c:1.18
--- src/common/lib/libprop/prop_kern.c:1.17	Fri Sep 30 22:08:18 2011
+++ src/common/lib/libprop/prop_kern.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: prop_kern.c,v 1.17 2011/09/30 22:08:18 jym Exp $	*/
+/*	$NetBSD: prop_kern.c,v 1.18 2014/12/14 23:48:58 chs Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
@@ -380,7 +380,7 @@ prop_dictionary_sendrecv_ioctl(prop_dict
 #include <sys/resource.h>
 #include <sys/pool.h>
 
-#include <uvm/uvm.h>
+#include <uvm/uvm_extern.h>
 
 #include "prop_object_impl.h"
 
@@ -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: src/sys/arch/mac68k/dev/grf_compat.c
diff -u src/sys/arch/mac68k/dev/grf_compat.c:1.26 src/sys/arch/mac68k/dev/grf_compat.c:1.27
--- src/sys/arch/mac68k/dev/grf_compat.c:1.26	Fri Jul 25 08:10:33 2014
+++ src/sys/arch/mac68k/dev/grf_compat.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: grf_compat.c,v 1.26 2014/07/25 08:10:33 dholland Exp $	*/
+/*	$NetBSD: grf_compat.c,v 1.27 2014/12/14 23:48:58 chs Exp $	*/
 
 /*
  * Copyright (C) 1999 Scott Reynolds
@@ -34,7 +34,7 @@
 #include "opt_grf_compat.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: grf_compat.c,v 1.26 2014/07/25 08:10:33 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: grf_compat.c,v 1.27 2014/12/14 23:48:58 chs Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -43,12 +43,9 @@ __KERNEL_RCSID(0, "$NetBSD: grf_compat.c
 #include <sys/errno.h>
 #include <sys/ioctl.h>
 #include <sys/malloc.h>
-#include <sys/mman.h>
 #include <sys/proc.h>
 #include <sys/resourcevar.h>
-#include <sys/vnode.h>
 
-#include <machine/autoconf.h>
 #include <machine/bus.h>
 #include <machine/grfioctl.h>
 
@@ -59,7 +56,6 @@ __KERNEL_RCSID(0, "$NetBSD: grf_compat.c
 #include <miscfs/specfs/specdev.h>
 
 #include <uvm/uvm_extern.h>
-#include <uvm/uvm_map.h>
 
 dev_type_open(grfopen);
 dev_type_close(grfclose);
@@ -320,24 +316,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 +331,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: src/sys/arch/x68k/dev/grf.c
diff -u src/sys/arch/x68k/dev/grf.c:1.44 src/sys/arch/x68k/dev/grf.c:1.45
--- src/sys/arch/x68k/dev/grf.c:1.44	Fri Jul 25 08:10:35 2014
+++ src/sys/arch/x68k/dev/grf.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: grf.c,v 1.44 2014/07/25 08:10:35 dholland Exp $	*/
+/*	$NetBSD: grf.c,v 1.45 2014/12/14 23:48:58 chs Exp $	*/
 
 /*
  * Copyright (c) 1988 University of Utah.
@@ -45,7 +45,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: grf.c,v 1.44 2014/07/25 08:10:35 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: grf.c,v 1.45 2014/12/14 23:48:58 chs Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -53,10 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: grf.c,v 1.44
 #include <sys/proc.h>
 #include <sys/resourcevar.h>
 #include <sys/ioctl.h>
-#include <sys/file.h>
 #include <sys/malloc.h>
-#include <sys/vnode.h>
-#include <sys/mman.h>
 #include <sys/conf.h>
 
 #include <machine/cpu.h>
@@ -66,7 +63,6 @@ __KERNEL_RCSID(0, "$NetBSD: grf.c,v 1.44
 #include <x68k/dev/itevar.h>
 
 #include <uvm/uvm_extern.h>
-#include <uvm/uvm_map.h>
 
 #include <miscfs/specfs/specdev.h>
 
@@ -266,9 +262,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 +271,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: src/sys/external/bsd/drm/dist/bsd-core/drm_bufs.c
diff -u src/sys/external/bsd/drm/dist/bsd-core/drm_bufs.c:1.11 src/sys/external/bsd/drm/dist/bsd-core/drm_bufs.c:1.12
--- src/sys/external/bsd/drm/dist/bsd-core/drm_bufs.c:1.11	Sun Jun 17 15:15:34 2012
+++ src/sys/external/bsd/drm/dist/bsd-core/drm_bufs.c	Sun Dec 14 23:48:59 2014
@@ -1068,29 +1068,22 @@ int drm_mapbufs(struct drm_device *dev, 
 	int retcode = 0;
 	const int zero = 0;
 	vm_offset_t address;
-	struct vmspace *vms;
 #if defined(__FreeBSD__)
+	struct vmspace *vms;
 	vm_ooffset_t foff;
 	vm_size_t size;
 	vm_offset_t vaddr;
 #elif   defined(__NetBSD__)
-	struct vnode *vn;
 	voff_t foff;
 	vsize_t size, rsize;
+	void *addr;
 	vaddr_t vaddr;
 #endif
 	struct drm_buf_map *request = data;
 	int i;
 
-#if defined(__NetBSD__)
-	if (!vfinddev(dev->kdev, VCHR, &vn))
-		return 0;	/* FIXME: Shouldn't this be EINVAL or something? */
-#endif /* __NetBSD__ || __OpenBSD */
-
 #if defined(__FreeBSD__)
 	vms = DRM_CURPROC->td_proc->p_vmspace;
-#elif   defined(__NetBSD__)
-	vms = DRM_CURPROC->p_vmspace;
 #endif
 
 	DRM_SPINLOCK(&dev->dma_lock);
@@ -1128,13 +1121,10 @@ int drm_mapbufs(struct drm_device *dev, 
 #endif
 #elif   defined(__NetBSD__)
 	/* XXXNETBSD */
-	vaddr = curlwp->l_proc->p_emul->e_vm_default_addr(curlwp->l_proc,
-	    (vaddr_t)vms->vm_daddr, size);
 	rsize = round_page(size);
+	retcode = uvm_mmap_dev(curproc, &addr, rsize, dev->kdev, foff);
+	vaddr = (vaddr_t)addr;
 	DRM_DEBUG("mmap %#lx/%#lx foff %#llx\n", vaddr, rsize, (long long)foff);
-	retcode = uvm_mmap(&vms->vm_map, &vaddr, rsize,
-	    UVM_PROT_READ | UVM_PROT_WRITE, UVM_PROT_ALL, MAP_SHARED,
-	    &vn->v_uobj, foff, curproc->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
 #endif
 	if (retcode)
 		goto done;
@@ -1167,10 +1157,6 @@ int drm_mapbufs(struct drm_device *dev, 
 
  done:
 	request->count = dma->buf_count;
-#if defined(__NetBSD__)
-	vrele(vn);
-#endif
-
 	DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);
 
 	return retcode;

Index: src/sys/external/bsd/drm2/drm/drm_drv.c
diff -u src/sys/external/bsd/drm2/drm/drm_drv.c:1.11 src/sys/external/bsd/drm2/drm/drm_drv.c:1.12
--- src/sys/external/bsd/drm2/drm/drm_drv.c:1.11	Sat Nov 22 19:18:07 2014
+++ src/sys/external/bsd/drm2/drm/drm_drv.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_drv.c,v 1.11 2014/11/22 19:18:07 riastradh Exp $	*/
+/*	$NetBSD: drm_drv.c,v 1.12 2014/12/14 23:48:58 chs Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.11 2014/11/22 19:18:07 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.12 2014/12/14 23:48:58 chs Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -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: src/sys/external/bsd/drm2/drm/drm_vm.c
diff -u src/sys/external/bsd/drm2/drm/drm_vm.c:1.5 src/sys/external/bsd/drm2/drm/drm_vm.c:1.6
--- src/sys/external/bsd/drm2/drm/drm_vm.c:1.5	Sat Jul 26 21:15:45 2014
+++ src/sys/external/bsd/drm2/drm/drm_vm.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_vm.c,v 1.5 2014/07/26 21:15:45 riastradh Exp $	*/
+/*	$NetBSD: drm_vm.c,v 1.6 2014/12/14 23:48:58 chs Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_vm.c,v 1.5 2014/07/26 21:15:45 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_vm.c,v 1.6 2014/12/14 23:48:58 chs Exp $");
 
 #include <sys/types.h>
 #include <sys/conf.h>
@@ -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: src/sys/external/bsd/drm2/include/linux/mm.h
diff -u src/sys/external/bsd/drm2/include/linux/mm.h:1.3 src/sys/external/bsd/drm2/include/linux/mm.h:1.4
--- src/sys/external/bsd/drm2/include/linux/mm.h:1.3	Wed Jul 16 20:59:58 2014
+++ src/sys/external/bsd/drm2/include/linux/mm.h	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mm.h,v 1.3 2014/07/16 20:59:58 riastradh Exp $	*/
+/*	$NetBSD: mm.h,v 1.4 2014/12/14 23:48:58 chs Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -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);

Index: src/sys/kern/vfs_vnops.c
diff -u src/sys/kern/vfs_vnops.c:1.191 src/sys/kern/vfs_vnops.c:1.192
--- src/sys/kern/vfs_vnops.c:1.191	Fri Sep  5 09:20:59 2014
+++ src/sys/kern/vfs_vnops.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_vnops.c,v 1.191 2014/09/05 09:20:59 matt Exp $	*/
+/*	$NetBSD: vfs_vnops.c,v 1.192 2014/12/14 23:48:58 chs Exp $	*/
 
 /*-
  * Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.191 2014/09/05 09:20:59 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.192 2014/12/14 23:48:58 chs Exp $");
 
 #include "veriexec.h"
 
@@ -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: src/sys/rump/librump/rumpkern/vm.c
diff -u src/sys/rump/librump/rumpkern/vm.c:1.159 src/sys/rump/librump/rumpkern/vm.c:1.160
--- src/sys/rump/librump/rumpkern/vm.c:1.159	Sun Jun 15 12:58:01 2014
+++ src/sys/rump/librump/rumpkern/vm.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: vm.c,v 1.159 2014/06/15 12:58:01 pooka Exp $	*/
+/*	$NetBSD: vm.c,v 1.160 2014/12/14 23:48:58 chs Exp $	*/
 
 /*
  * Copyright (c) 2007-2011 Antti Kantee.  All Rights Reserved.
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vm.c,v 1.159 2014/06/15 12:58:01 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vm.c,v 1.160 2014/12/14 23:48:58 chs Exp $");
 
 #include <sys/param.h>
 #include <sys/atomic.h>
@@ -62,6 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: vm.c,v 1.159
 #include <uvm/uvm_pdpolicy.h>
 #include <uvm/uvm_prot.h>
 #include <uvm/uvm_readahead.h>
+#include <uvm/uvm_device.h>
 
 #include "rump_private.h"
 #include "rump_vfs_private.h"
@@ -434,36 +435,34 @@ uvm_init_limits(struct proc *p)
 
 /*
  * This satisfies the "disgusting mmap hack" used by proplib.
- * We probably should grow some more assertables to make sure we're
- * not satisfying anything we shouldn't be satisfying.
  */
 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 off, vsize_t locklim)
+uvm_mmap_anon(struct proc *p, void **addrp, size_t size)
 {
-	void *uaddr;
 	int error;
 
-	if (prot != (VM_PROT_READ | VM_PROT_WRITE))
-		panic("uvm_mmap() variant unsupported");
-	if (flags != (MAP_PRIVATE | MAP_ANON))
-		panic("uvm_mmap() variant unsupported");
-
 	/* no reason in particular, but cf. uvm_default_mapaddr() */
-	if (*addr != 0)
+	if (*addrp != NULL)
 		panic("uvm_mmap() variant unsupported");
 
 	if (RUMP_LOCALPROC_P(curproc)) {
-		error = rumpuser_anonmmap(NULL, size, 0, 0, &uaddr);
+		error = rumpuser_anonmmap(NULL, size, 0, 0, addrp);
 	} else {
-		error = rumpuser_sp_anonmmap(curproc->p_vmspace->vm_map.pmap,
-		    size, &uaddr);
+		error = rumpuser_sp_anonmmap(p->p_vmspace->vm_map.pmap,
+		    size, addrp);
 	}
-	if (error)
-		return error;
+	return error;
+}
 
-	*addr = (vaddr_t)uaddr;
-	return 0;
+/*
+ * Stubs for things referenced from vfs_vnode.c but not used.
+ */
+const dev_t zerodev;
+
+struct uvm_object *
+udv_attach(dev_t device, vm_prot_t accessprot, voff_t off, vsize_t size)
+{
+	return NULL;
 }
 
 struct pagerinfo {

Index: src/sys/sys/file.h
diff -u src/sys/sys/file.h:1.77 src/sys/sys/file.h:1.78
--- src/sys/sys/file.h:1.77	Fri Sep  5 09:17:04 2014
+++ src/sys/sys/file.h	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: file.h,v 1.77 2014/09/05 09:17:04 matt Exp $	*/
+/*	$NetBSD: file.h,v 1.78 2014/12/14 23:48:58 chs Exp $	*/
 
 /*-
  * Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -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: src/sys/uvm/uvm_device.c
diff -u src/sys/uvm/uvm_device.c:1.63 src/sys/uvm/uvm_device.c:1.64
--- src/sys/uvm/uvm_device.c:1.63	Fri Jan 27 19:48:41 2012
+++ src/sys/uvm/uvm_device.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_device.c,v 1.63 2012/01/27 19:48:41 para Exp $	*/
+/*	$NetBSD: uvm_device.c,v 1.64 2014/12/14 23:48:58 chs Exp $	*/
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_device.c,v 1.63 2012/01/27 19:48:41 para Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_device.c,v 1.64 2014/12/14 23:48:58 chs Exp $");
 
 #include "opt_uvmhist.h"
 
@@ -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: src/sys/uvm/uvm_device.h
diff -u src/sys/uvm/uvm_device.h:1.12 src/sys/uvm/uvm_device.h:1.13
--- src/sys/uvm/uvm_device.h:1.12	Wed Feb  2 15:13:34 2011
+++ src/sys/uvm/uvm_device.h	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_device.h,v 1.12 2011/02/02 15:13:34 chuck Exp $	*/
+/*	$NetBSD: uvm_device.h,v 1.13 2014/12/14 23:48:58 chs Exp $	*/
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -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: src/sys/uvm/uvm_extern.h
diff -u src/sys/uvm/uvm_extern.h:1.191 src/sys/uvm/uvm_extern.h:1.192
--- src/sys/uvm/uvm_extern.h:1.191	Mon Jul  7 20:14:43 2014
+++ src/sys/uvm/uvm_extern.h	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_extern.h,v 1.191 2014/07/07 20:14:43 riastradh Exp $	*/
+/*	$NetBSD: uvm_extern.h,v 1.192 2014/12/14 23:48:58 chs Exp $	*/
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -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: src/sys/uvm/uvm_mmap.c
diff -u src/sys/uvm/uvm_mmap.c:1.149 src/sys/uvm/uvm_mmap.c:1.150
--- src/sys/uvm/uvm_mmap.c:1.149	Fri Sep  5 09:24:48 2014
+++ src/sys/uvm/uvm_mmap.c	Sun Dec 14 23:48:58 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_mmap.c,v 1.149 2014/09/05 09:24:48 matt Exp $	*/
+/*	$NetBSD: uvm_mmap.c,v 1.150 2014/12/14 23:48:58 chs Exp $	*/
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -46,41 +46,28 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_mmap.c,v 1.149 2014/09/05 09:24:48 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_mmap.c,v 1.150 2014/12/14 23:48:58 chs Exp $");
 
 #include "opt_compat_netbsd.h"
 #include "opt_pax.h"
-#include "veriexec.h"
 
-#include <sys/param.h>
-#include <sys/systm.h>
+#include <sys/types.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
 #include <sys/resourcevar.h>
 #include <sys/mman.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
-#include <sys/conf.h>
-#include <sys/stat.h>
-
-#if NVERIEXEC > 0
-#include <sys/verified_exec.h>
-#endif /* NVERIEXEC > 0 */
- 
+
 #if defined(PAX_ASLR) || defined(PAX_MPROTECT)
 #include <sys/pax.h>
 #endif /* PAX_ASLR || PAX_MPROTECT */
 
-#include <miscfs/specfs/specdev.h>
-
 #include <sys/syscallargs.h>
 
 #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 +288,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 +353,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 +380,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 +408,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 +426,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 +915,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 +992,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 +1002,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 +1068,47 @@ 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;
+}

Reply via email to