drm/tegra: Correct copying of waitchecks and disable them in the 'submit' IOCTL
authorDmitry Osipenko <digetx@gmail.com>
Wed, 14 Jun 2017 23:18:27 +0000 (02:18 +0300)
committerThierry Reding <treding@nvidia.com>
Thu, 15 Jun 2017 12:16:37 +0000 (14:16 +0200)
The waitchecks along with multiple syncpoints per submit are not ready
for use yet, let's forbid them for now.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/tegra/drm.c
drivers/gpu/host1x/job.h
include/linux/host1x.h

index 51e20e0..0928f2b 100644 (file)
@@ -349,6 +349,36 @@ static int host1x_reloc_copy_from_user(struct host1x_reloc *dest,
        return 0;
 }
 
+static int host1x_waitchk_copy_from_user(struct host1x_waitchk *dest,
+                                        struct drm_tegra_waitchk __user *src,
+                                        struct drm_file *file)
+{
+       u32 cmdbuf;
+       int err;
+
+       err = get_user(cmdbuf, &src->handle);
+       if (err < 0)
+               return err;
+
+       err = get_user(dest->offset, &src->offset);
+       if (err < 0)
+               return err;
+
+       err = get_user(dest->syncpt_id, &src->syncpt);
+       if (err < 0)
+               return err;
+
+       err = get_user(dest->thresh, &src->thresh);
+       if (err < 0)
+               return err;
+
+       dest->bo = host1x_bo_lookup(file, cmdbuf);
+       if (!dest->bo)
+               return -ENOENT;
+
+       return 0;
+}
+
 int tegra_drm_submit(struct tegra_drm_context *context,
                     struct drm_tegra_submit *args, struct drm_device *drm,
                     struct drm_file *file)
@@ -370,6 +400,10 @@ int tegra_drm_submit(struct tegra_drm_context *context,
        if (args->num_syncpts != 1)
                return -EINVAL;
 
+       /* We don't yet support waitchks */
+       if (args->num_waitchks != 0)
+               return -EINVAL;
+
        job = host1x_job_alloc(context->channel, args->num_cmdbufs,
                               args->num_relocs, args->num_waitchks);
        if (!job)
@@ -458,10 +492,28 @@ int tegra_drm_submit(struct tegra_drm_context *context,
                }
        }
 
-       if (copy_from_user(job->waitchk, waitchks,
-                          sizeof(*waitchks) * num_waitchks)) {
-               err = -EFAULT;
-               goto fail;
+       /* copy and resolve waitchks from submit */
+       while (num_waitchks--) {
+               struct host1x_waitchk *wait = &job->waitchk[num_waitchks];
+               struct tegra_bo *obj;
+
+               err = host1x_waitchk_copy_from_user(wait,
+                                                   &waitchks[num_waitchks],
+                                                   file);
+               if (err < 0)
+                       goto fail;
+
+               obj = host1x_to_tegra_bo(wait->bo);
+
+               /*
+                * The unaligned offset will cause an unaligned write during
+                * of the waitchks patching, corrupting the commands stream.
+                */
+               if (wait->offset & 3 ||
+                   wait->offset >= obj->gem.size) {
+                       err = -EINVAL;
+                       goto fail;
+               }
        }
 
        if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts,
index 878239c..0debd93 100644 (file)
@@ -34,13 +34,6 @@ struct host1x_cmdbuf {
        u32 pad;
 };
 
-struct host1x_waitchk {
-       struct host1x_bo *bo;
-       u32 offset;
-       u32 syncpt_id;
-       u32 thresh;
-};
-
 struct host1x_job_unpin_data {
        struct host1x_bo *bo;
        struct sg_table *sgt;
index 840a8ad..ba0b245 100644 (file)
@@ -193,6 +193,13 @@ struct host1x_reloc {
        unsigned long shift;
 };
 
+struct host1x_waitchk {
+       struct host1x_bo *bo;
+       u32 offset;
+       u32 syncpt_id;
+       u32 thresh;
+};
+
 struct host1x_job {
        /* When refcount goes to zero, job can be freed */
        struct kref ref;