Source-Changes-HG archive

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

[src/riastradh-drm2]: src/sys/external/bsd/drm2 Implement mmap on a drm devic...



details:   https://anonhg.NetBSD.org/src/rev/fcea01fddaee
branches:  riastradh-drm2
changeset: 788624:fcea01fddaee
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Wed Jan 22 14:58:47 2014 +0000

description:
Implement mmap on a drm device by a new kludgey ioctl.

There is currently no way to set up a custom choice of uvm object and
uvm pager ops for mmap: struct fileops has no fo_mmap, and device
nodes get to say only what paddr each offset maps to, not what uvm
object to use.  For now, to avoid kernel changes outside the drm2
tree, we'll use a non-standard drm ioctl that calls uvm_map.  This
requires source patches to userland programs, but for the most part
they can simply be converted from calling mmap to drmMap, which will
be adapted to use the ioctl.

This is not necessarily a permanent solution.

diffstat:

 sys/external/bsd/drm2/dist/uapi/drm/drm.h |   14 ++
 sys/external/bsd/drm2/drm/drm_drv.c       |  141 +++++++++++++++++++++++++++++-
 sys/external/bsd/drm2/drm/drm_vm.c        |   45 +++++----
 3 files changed, 177 insertions(+), 23 deletions(-)

diffs (truncated from 317 to 300 lines):

diff -r 98ea7f142a4c -r fcea01fddaee sys/external/bsd/drm2/dist/uapi/drm/drm.h
--- a/sys/external/bsd/drm2/dist/uapi/drm/drm.h Wed Jan 22 14:58:39 2014 +0000
+++ b/sys/external/bsd/drm2/dist/uapi/drm/drm.h Wed Jan 22 14:58:47 2014 +0000
@@ -739,6 +739,20 @@
 #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES       DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
 #define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
 
+#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.
diff -r 98ea7f142a4c -r fcea01fddaee sys/external/bsd/drm2/drm/drm_drv.c
--- a/sys/external/bsd/drm2/drm/drm_drv.c       Wed Jan 22 14:58:39 2014 +0000
+++ b/sys/external/bsd/drm2/drm/drm_drv.c       Wed Jan 22 14:58:47 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: drm_drv.c,v 1.1.2.31 2014/01/21 20:56:40 riastradh Exp $       */
+/*     $NetBSD: drm_drv.c,v 1.1.2.32 2014/01/22 14:58:47 riastradh 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.1.2.31 2014/01/21 20:56:40 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.1.2.32 2014/01/22 14:58:47 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -43,6 +43,14 @@
 #include <sys/poll.h>
 #include <sys/select.h>
 
+#include <uvm/uvm.h>
+#include <uvm/uvm_device.h>
+#include <uvm/uvm_extern.h>
+#include <uvm/uvm_fault.h>
+#include <uvm/uvm_page.h>
+#include <uvm/uvm_pmap.h>
+#include <uvm/uvm_prot.h>
+
 #include <drm/drmP.h>
 
 static int drm_minor_types[] = {
@@ -95,8 +103,12 @@
 static int     drm_stat(struct file *, struct stat *);
 static int     drm_ioctl(struct file *, unsigned long, void *);
 static int     drm_version_string(char *, size_t *, const char *);
+static paddr_t drm_mmap(dev_t, off_t, int);
+static int     drm_do_mmap(struct uvm_object *, vm_prot_t, voff_t, size_t,
+                   vaddr_t *);
 
 static drm_ioctl_t     drm_version;
+static drm_ioctl_t     drm_mmap_ioctl;
 
 /* XXX Can this be pushed into struct drm_device?  */
 struct mutex drm_global_mutex;
@@ -218,6 +230,10 @@
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        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),
+
+#ifdef __NetBSD__
+       DRM_IOCTL_DEF(DRM_IOCTL_MMAP, drm_mmap_ioctl, DRM_UNLOCKED),
+#endif
 };
 
 const struct cdevsw drm_cdevsw = {
@@ -229,7 +245,7 @@
        .d_stop = nostop,
        .d_tty = notty,
        .d_poll = nopoll,
-       .d_mmap = nommap,
+       .d_mmap = drm_mmap,
        .d_kqfilter = nokqfilter,
        /* XXX was D_TTY | D_NEGOFFSAFE */
        /* XXX Add D_MPSAFE some day... */
@@ -849,3 +865,122 @@
 
        return NULL;
 }
+
+static paddr_t
+drm_mmap(dev_t d, off_t offset, int prot)
+{
+       struct drm_minor *const dminor = drm_dev_minor(d);
+
+       if (dminor == NULL)
+               return (paddr_t)-1;
+
+       return drm_mmap_paddr(dminor->dev, offset, prot);
+}
+
+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 drm_gem_mm *const mm = dev->mm_private;
+       struct drm_hash_item *hash;
+       vm_prot_t vm_prot;
+       dev_t devno;
+       struct uvm_object *uobj;
+       vaddr_t vaddr;
+       int ret;
+
+       /* XXX Copypasta from drm_gem_mmap.  */
+       if (drm_device_is_unplugged(dev))
+               return -ENODEV;
+
+       if (prot != (PROT_READ | PROT_WRITE))
+               return -EACCES;
+       if (flags != MAP_SHARED)
+               return -EINVAL;
+       (void)addr;             /* XXX ignore -- no MAP_FIXED for now */
+
+       KASSERT(prot == (PROT_READ | PROT_WRITE));
+       vm_prot = (VM_PROT_READ | VM_PROT_WRITE);
+
+       mutex_lock(&dev->struct_mutex);
+       if (drm_ht_find_item(&mm->offset_hash, atop(offset), &hash) == 0) {
+               /* GEM object.  Map the GEM shared-memory uobj.  */
+
+               struct drm_local_map *const map =
+                   drm_hash_entry(hash, struct drm_map_list, hash)->map;
+               if ((map == NULL) ||
+                   (ISSET(map->flags, _DRM_RESTRICTED) && !DRM_SUSER())) {
+                       ret = -EPERM;
+                       goto out_unlock;
+               }
+               if (map->size < size) {
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
+
+               struct drm_gem_object *const obj = map->handle;
+               if (obj->dev->driver->gem_uvm_ops == NULL) {
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
+
+               uobj = obj->gemo_shm_uao;
+               ret = drm_do_mmap(uobj, prot, offset, size, &vaddr);
+               if (ret)
+                       goto out_unlock;
+               drm_gem_object_reference(obj);
+
+out_unlock:    mutex_unlock(&dev->struct_mutex);
+       } else {
+               /*
+                * Not a GEM object.  Use the old mmap.
+                *
+                * XXX Unlocking is wrong here, but the uvm device mmap
+                * API will call cdev_mmap immediately (where we can
+                * control whether or not the device is locked) and in
+                * the fault handler (where the device is unlocked and
+                * we can't do a thing about it), so we have to unlock
+                * the device first.  The good news is that this should
+                * only enable a broken application to use paddrs that
+                * it is allowed to use anyway but that perhaps are not
+                * the ones it expected.
+                */
+               mutex_unlock(&dev->struct_mutex);
+
+               devno = file->minor->device;
+               uobj = udv_attach(&devno, prot, offset, size);
+               if (uobj == NULL) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               ret = drm_do_mmap(uobj, prot, offset, size, &vaddr);
+       }
+
+out:   if (ret == 0)
+               args->dnm_addr = (void *)vaddr;
+       return ret;
+}
+
+static int
+drm_do_mmap(struct uvm_object *uobj, vm_prot_t prot, voff_t offset,
+    size_t size, vaddr_t *vaddr)
+{
+       vaddr_t align;
+       int uvmflag;
+
+       align = 0;              /* XXX */
+       uvmflag = UVM_MAPFLAG(prot, prot, UVM_INH_COPY, UVM_ADV_RANDOM,
+           UVM_FLAG_COPYONW);
+
+       *vaddr = (*curproc->p_emul->e_vm_default_addr)(curproc,
+           (vaddr_t)curproc->p_vmspace->vm_daddr, size);
+       /* XXX errno NetBSD->Linux */
+       return -uvm_map(&curproc->p_vmspace->vm_map, vaddr, size, uobj, offset,
+           align, uvmflag);
+}
diff -r 98ea7f142a4c -r fcea01fddaee sys/external/bsd/drm2/drm/drm_vm.c
--- a/sys/external/bsd/drm2/drm/drm_vm.c        Wed Jan 22 14:58:39 2014 +0000
+++ b/sys/external/bsd/drm2/drm/drm_vm.c        Wed Jan 22 14:58:47 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: drm_vm.c,v 1.1.2.2 2013/09/08 15:44:14 riastradh Exp $ */
+/*     $NetBSD: drm_vm.c,v 1.1.2.3 2014/01/22 14:58:47 riastradh 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.1.2.2 2013/09/08 15:44:14 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_vm.c,v 1.1.2.3 2014/01/22 14:58:47 riastradh Exp $");
 
 #include <sys/types.h>
 
@@ -38,6 +38,7 @@
 
 #include <drm/drmP.h>
 
+static paddr_t drm_mmap_paddr_locked(struct drm_device *, off_t, int);
 static paddr_t drm_mmap_dma_paddr(struct drm_device *, off_t, int);
 static paddr_t drm_mmap_map_paddr(struct drm_device *, struct drm_local_map *,
                    off_t, int);
@@ -45,30 +46,38 @@
 paddr_t
 drm_mmap_paddr(struct drm_device *dev, off_t byte_offset, int prot)
 {
+       paddr_t paddr;
+
+       mutex_lock(&dev->struct_mutex);
+       paddr = drm_mmap_paddr_locked(dev, byte_offset, prot);
+       mutex_unlock(&dev->struct_mutex);
+
+       return paddr;
+}
+
+static paddr_t
+drm_mmap_paddr_locked(struct drm_device *dev, off_t byte_offset, int prot)
+{
        const off_t page_offset = (byte_offset >> PAGE_SHIFT);
        struct drm_hash_item *hash;
-       paddr_t paddr = (paddr_t)-1;
-       int error;
+
+       KASSERT(mutex_is_locked(&dev->struct_mutex));
 
        if (byte_offset != (byte_offset & ~(PAGE_SIZE-1)))
-               return (paddr_t)-1;
-
-       mutex_lock(&dev->struct_mutex);
+               return -1;
 
        if ((dev->dma != NULL) &&
            (0 <= byte_offset) &&
-           (byte_offset <= (dev->dma->page_count << PAGE_SHIFT))) {
-               paddr = drm_mmap_dma_paddr(dev, byte_offset, prot);
-               goto out;
-       }
+           (byte_offset <= (dev->dma->page_count << PAGE_SHIFT)))
+               return drm_mmap_dma_paddr(dev, byte_offset, prot);
 
        if (drm_ht_find_item(&dev->map_hash, page_offset, &hash))
-               goto out;
+               return -1;
 
        struct drm_local_map *const map = drm_hash_entry(hash,
            struct drm_map_list, hash)->map;
        if (map == NULL)
-               goto out;
+               return -1;
 
        /*
         * XXX FreeBSD drops the mutex at this point, which would be
@@ -77,16 +86,13 @@
         */
 
        if (ISSET(map->flags, _DRM_RESTRICTED) && !DRM_SUSER())
-               goto out;
+               return -1;
 
        if (byte_offset < map->offset)
-               goto out;
+               return -1;
 



Home | Main Index | Thread Index | Old Index