tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: drivers customizing mmap(2)



On Tue, Mar 05, 2013 at 12:31:37AM +0000, Taylor R Campbell wrote:
> I'd like to add a member fo_mmap to struct fileops so that cloning
> devices can support mmap and use other kinds of uvm objects than just
> uvm_deviceops and uvm_vnodeops.

the first attached patch implements this, and also cleans up the interface
between UVM and various other things that want to map devices or anon memory.

the second attached patch converts libdrm to use mmap() instead of ioctl().

comments?

-Chuck
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);
Index: xsrc/external/mit/libdrm/dist/xf86drm.c
===================================================================
RCS file: /home/chs/netbsd/cvs/xsrc/external/mit/libdrm/dist/xf86drm.c,v
retrieving revision 1.8
diff -u -p -r1.8 xf86drm.c
--- xsrc/external/mit/libdrm/dist/xf86drm.c	11 Jul 2014 19:57:33 -0000	1.8
+++ xsrc/external/mit/libdrm/dist/xf86drm.c	21 Nov 2014 07:50:52 -0000
@@ -1142,9 +1142,6 @@ int drmClose(int fd)
 int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
 {
     static unsigned long pagesize_mask = 0;
-#ifdef DRM_IOCTL_MMAP
-    struct drm_mmap mmap_req = {0};
-#endif
 
     if (fd < 0)
 	return -EINVAL;
@@ -1154,17 +1151,6 @@ int drmMap(int fd, drm_handle_t handle, 
 
     size = (size + pagesize_mask) & ~pagesize_mask;
 
-#ifdef DRM_IOCTL_MMAP
-    mmap_req.dnm_addr = NULL;
-    mmap_req.dnm_size = size;
-    mmap_req.dnm_prot = (PROT_READ | PROT_WRITE);
-    mmap_req.dnm_flags = MAP_SHARED;
-    mmap_req.dnm_offset = handle;
-    if (drmIoctl(fd, DRM_IOCTL_MMAP, &mmap_req) == 0) {
-	*address = mmap_req.dnm_addr;
-	return 0;
-    }
-#endif
     *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
     if (*address == MAP_FAILED)
 	return -errno;
@@ -2598,4 +2584,3 @@ int drmPrimeFDToHandle(int fd, int prime
 	*handle = args.handle;
 	return 0;
 }
-
Index: xsrc/external/mit/libdrm/dist/include/drm/drm.h
===================================================================
RCS file: /home/chs/netbsd/cvs/xsrc/external/mit/libdrm/dist/include/drm/drm.h,v
retrieving revision 1.2
diff -u -p -r1.2 drm.h
--- xsrc/external/mit/libdrm/dist/include/drm/drm.h	21 Mar 2014 18:09:49 -0000	1.2
+++ xsrc/external/mit/libdrm/dist/include/drm/drm.h	21 Nov 2014 07:50:04 -0000
@@ -751,20 +751,6 @@ struct drm_prime_handle {
 #define DRM_IOCTL_MODE_OBJ_SETPROPERTY	DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
 #define DRM_IOCTL_MODE_CURSOR2		DRM_IOWR(0xBB, struct drm_mode_cursor2)
 
-#ifdef __NetBSD__
-/*
- * Instrumenting mmap is trickier than just making an ioctl to do it.
- */
-struct drm_mmap {
-	void		*dnm_addr;  /* in/out */
-	size_t		dnm_size;   /* in */
-	int		dnm_prot;   /* in */
-	int		dnm_flags;  /* in */
-	off_t		dnm_offset; /* in */
-};
-#define	DRM_IOCTL_MMAP	DRM_IOWR(0xff, struct drm_mmap)
-#endif
-
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x99.


Home | Main Index | Thread Index | Old Index