OSDN Git Service

Merge android-4.4-p.201 (ef0b39d) into msm-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / gpu / drm / i915 / i915_gem_execbuffer.c
index c66307c..56f6f5c 100644 (file)
@@ -513,9 +513,7 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
                                return ret;
 
                        if (r->presumed_offset != offset &&
-                           __copy_to_user_inatomic(&user_relocs->presumed_offset,
-                                                   &r->presumed_offset,
-                                                   sizeof(r->presumed_offset))) {
+                           __put_user(r->presumed_offset, &user_relocs->presumed_offset)) {
                                return -EFAULT;
                        }
 
@@ -1123,17 +1121,52 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
        return 0;
 }
 
+static struct i915_vma*
+shadow_batch_pin(struct drm_i915_gem_object *obj, struct i915_address_space *vm)
+{
+       struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
+       struct i915_address_space *pin_vm = vm;
+       u64 flags;
+       int ret;
+
+       /*
+        * PPGTT backed shadow buffers must be mapped RO, to prevent
+        * post-scan tampering
+        */
+       if (CMDPARSER_USES_GGTT(dev_priv)) {
+               flags = PIN_GLOBAL;
+               pin_vm = &dev_priv->gtt.base;
+       } else if (vm->has_read_only) {
+               flags = PIN_USER;
+               obj->gt_ro = 1;
+       } else {
+               DRM_DEBUG("Cannot prevent post-scan tampering without RO capable vm\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       ret = i915_gem_object_pin(obj, pin_vm, 0, flags);
+       if (ret)
+               return ERR_PTR(ret);
+       else
+               return i915_gem_obj_to_vma(obj, pin_vm);
+}
+
 static struct drm_i915_gem_object*
-i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
+i915_gem_execbuffer_parse(struct intel_context *ctx,
+                         struct intel_engine_cs *ring,
                          struct drm_i915_gem_exec_object2 *shadow_exec_entry,
                          struct eb_vmas *eb,
+                         struct i915_address_space *vm,
                          struct drm_i915_gem_object *batch_obj,
                          u32 batch_start_offset,
-                         u32 batch_len,
-                         bool is_master)
+                         u32 batch_len)
 {
        struct drm_i915_gem_object *shadow_batch_obj;
        struct i915_vma *vma;
+       struct i915_vma *user_vma = list_entry(eb->vmas.prev,
+                                       typeof(*user_vma), exec_list);
+       u64 batch_start;
+       u64 shadow_batch_start;
        int ret;
 
        shadow_batch_obj = i915_gem_batch_pool_get(&ring->batch_pool,
@@ -1141,24 +1174,34 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
        if (IS_ERR(shadow_batch_obj))
                return shadow_batch_obj;
 
-       ret = i915_parse_cmds(ring,
+       vma = shadow_batch_pin(shadow_batch_obj, vm);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto err;
+       }
+
+       batch_start = user_vma->node.start + batch_start_offset;
+
+       shadow_batch_start = vma->node.start;
+
+       ret = i915_parse_cmds(ctx,
+                             ring,
                              batch_obj,
-                             shadow_batch_obj,
+                             batch_start,
                              batch_start_offset,
                              batch_len,
-                             is_master);
-       if (ret)
-               goto err;
-
-       ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 0, 0);
-       if (ret)
+                             shadow_batch_obj,
+                             shadow_batch_start);
+       if (ret) {
+               WARN_ON(vma->pin_count == 0);
+               vma->pin_count--;
                goto err;
+       }
 
        i915_gem_object_unpin_pages(shadow_batch_obj);
 
        memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
 
-       vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
        vma->exec_entry = shadow_exec_entry;
        vma->exec_entry->flags = __EXEC_OBJECT_HAS_PIN;
        drm_gem_object_reference(&shadow_batch_obj->base);
@@ -1170,7 +1213,14 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
 
 err:
        i915_gem_object_unpin_pages(shadow_batch_obj);
-       if (ret == -EACCES) /* unhandled chained batch */
+
+       /*
+        * Unsafe GGTT-backed buffers can still be submitted safely
+        * as non-secure.
+        * For PPGTT backing however, we have no choice but to forcibly
+        * reject unsafe buffers
+        */
+       if (CMDPARSER_USES_GGTT(batch_obj->base.dev) && (ret == -EACCES))
                return batch_obj;
        else
                return ERR_PTR(ret);
@@ -1322,6 +1372,13 @@ eb_get_batch(struct eb_vmas *eb)
        return vma->obj;
 }
 
+static inline bool use_cmdparser(const struct intel_engine_cs *ring,
+                                u32 batch_len)
+{
+       return ring->requires_cmd_parser ||
+               (ring->using_cmd_parser && batch_len && USES_PPGTT(ring->dev));
+}
+
 static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                       struct drm_file *file,
@@ -1351,6 +1408,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        dispatch_flags = 0;
        if (args->flags & I915_EXEC_SECURE) {
+               /* Return -EPERM to trigger fallback code on old binaries. */
+               if (!HAS_SECURE_BATCHES(dev_priv))
+                       return -EPERM;
+
                if (!file->is_master || !capable(CAP_SYS_ADMIN))
                    return -EPERM;
 
@@ -1489,16 +1550,20 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        }
 
        params->args_batch_start_offset = args->batch_start_offset;
-       if (i915_needs_cmd_parser(ring) && args->batch_len) {
+       if (use_cmdparser(ring, args->batch_len)) {
                struct drm_i915_gem_object *parsed_batch_obj;
 
-               parsed_batch_obj = i915_gem_execbuffer_parse(ring,
+               u32 batch_off = args->batch_start_offset;
+               u32 batch_len = args->batch_len;
+               if (batch_len == 0)
+                       batch_len = batch_obj->base.size - batch_off;
+
+               parsed_batch_obj = i915_gem_execbuffer_parse(ctx, ring,
                                                      &shadow_exec_entry,
-                                                     eb,
+                                                     eb, vm,
                                                      batch_obj,
-                                                     args->batch_start_offset,
-                                                     args->batch_len,
-                                                     file->is_master);
+                                                     batch_off,
+                                                     batch_len);
                if (IS_ERR(parsed_batch_obj)) {
                        ret = PTR_ERR(parsed_batch_obj);
                        goto err;
@@ -1508,18 +1573,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                 * parsed_batch_obj == batch_obj means batch not fully parsed:
                 * Accept, but don't promote to secure.
                 */
-
                if (parsed_batch_obj != batch_obj) {
-                       /*
-                        * Batch parsed and accepted:
-                        *
-                        * Set the DISPATCH_SECURE bit to remove the NON_SECURE
-                        * bit from MI_BATCH_BUFFER_START commands issued in
-                        * the dispatch_execbuffer implementations. We
-                        * specifically don't want that set on batches the
-                        * command parser has accepted.
-                        */
-                       dispatch_flags |= I915_DISPATCH_SECURE;
+                       if (CMDPARSER_USES_GGTT(dev_priv))
+                               dispatch_flags |= I915_DISPATCH_SECURE;
                        params->args_batch_start_offset = 0;
                        batch_obj = parsed_batch_obj;
                }