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);