diff options
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_bo.c | 109 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_validate.c | 2 | ||||
-rw-r--r-- | include/uapi/drm/vc4_drm.h | 25 |
5 files changed, 147 insertions, 5 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 8d496b32db1b..7480ae12ca31 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -387,6 +387,56 @@ vc4_create_bo_ioctl(struct drm_device *dev, void *data, } int +vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vc4_create_shader_bo *args = data; + struct vc4_bo *bo = NULL; + int ret; + + if (args->size == 0) + return -EINVAL; + + if (args->size % sizeof(u64) != 0) + return -EINVAL; + + if (args->flags != 0) { + DRM_INFO("Unknown flags set: 0x%08x\n", args->flags); + return -EINVAL; + } + + if (args->pad != 0) { + DRM_INFO("Pad set: 0x%08x\n", args->pad); + return -EINVAL; + } + + mutex_lock(&dev->struct_mutex); + bo = vc4_bo_create(dev, roundup(args->size, PAGE_SIZE)); + mutex_unlock(&dev->struct_mutex); + if (!bo) + return -ENOMEM; + + ret = copy_from_user(bo->base.vaddr, + (void __user *)(uintptr_t)args->data, + args->size); + if (ret != 0) + goto fail; + + bo->validated_shader = vc4_validate_shader(&bo->base); + if (!bo->validated_shader) { + ret = -EINVAL; + goto fail; + } + + ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle); + + fail: + drm_gem_object_unreference_unlocked(&bo->base.base); + + return ret; +} + +int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -406,6 +456,65 @@ vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, return 0; } +int vc4_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_gem_object *gem_obj; + struct vc4_bo *bo; + int ret; + + ret = drm_gem_mmap(filp, vma); + if (ret) + return ret; + + gem_obj = vma->vm_private_data; + bo = to_vc4_bo(gem_obj); + + if (bo->validated_shader) { + DRM_ERROR("mmaping of shader BOs not allowed.\n"); + return -EINVAL; + } + + /* + * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the + * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map + * the whole buffer. + */ + vma->vm_flags &= ~VM_PFNMAP; + vma->vm_pgoff = 0; + + ret = dma_mmap_writecombine(bo->base.base.dev->dev, vma, + bo->base.vaddr, bo->base.paddr, + vma->vm_end - vma->vm_start); + if (ret) + drm_gem_vm_close(vma); + + return ret; +} + +int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) +{ + struct vc4_bo *bo = to_vc4_bo(obj); + + if (bo->validated_shader) { + DRM_ERROR("mmaping of shader BOs not allowed.\n"); + return -EINVAL; + } + + return drm_gem_cma_prime_mmap(obj, vma); +} + +void *vc4_prime_vmap(struct drm_gem_object *obj) +{ + struct vc4_bo *bo = to_vc4_bo(obj); + + if (bo->validated_shader) { + DRM_ERROR("mmaping of shader BOs not allowed.\n"); + return ERR_PTR(-EINVAL); + } + + return drm_gem_cma_prime_vmap(obj); +} + #ifdef CONFIG_DEBUG_FS int vc4_bo_stats_debugfs(struct seq_file *m, void *unused) { diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 5c023ba4f6ad..fae784817422 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -98,7 +98,7 @@ static const struct file_operations vc4_drm_fops = { .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, - .mmap = drm_gem_cma_mmap, + .mmap = vc4_mmap, .poll = drm_poll, .read = drm_read, #ifdef CONFIG_COMPAT @@ -113,6 +113,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(VC4_WAIT_BO, vc4_wait_bo_ioctl, 0), DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, 0), DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, 0), + DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, 0), }; static struct drm_driver vc4_drm_driver = { @@ -149,9 +150,9 @@ static struct drm_driver vc4_drm_driver = { .gem_prime_export = vc4_prime_export, .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, - .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vmap = vc4_prime_vmap, .gem_prime_vunmap = drm_gem_cma_prime_vunmap, - .gem_prime_mmap = drm_gem_cma_prime_mmap, + .gem_prime_mmap = vc4_prime_mmap, .dumb_create = vc4_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index c2db6bd57352..c99ef1ce5bc0 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -105,7 +105,9 @@ struct vc4_bo { /* List entry for the BO's position in vc4_dev->bo_cache.size_list */ struct list_head size_head; - /* Cached state from validation of the shader code. */ + /* Struct for shader validation state, if created by + * DRM_IOCTL_VC4_CREATE_SHADER_BO. + */ struct vc4_validated_shader_info *validated_shader; /* Set if the buffer has been either imported or exported via @@ -374,9 +376,14 @@ struct dma_buf *vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags); int vc4_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int vc4_bo_stats_debugfs(struct seq_file *m, void *unused); +int vc4_mmap(struct file *filp, struct vm_area_struct *vma); +int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); +void *vc4_prime_vmap(struct drm_gem_object *obj); /* vc4_debugfs.c */ int vc4_debugfs_init(struct drm_minor *minor); diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 620b04781286..ff3b62fbc920 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c @@ -863,7 +863,7 @@ validate_shader_rec(struct drm_device *dev, goto fail; } - validated_shader = vc4_validate_shader(bo[i]); + validated_shader = to_vc4_bo(&bo[i]->base)->validated_shader; if (!validated_shader) goto fail; diff --git a/include/uapi/drm/vc4_drm.h b/include/uapi/drm/vc4_drm.h index 4d55307c5107..499daae549a5 100644 --- a/include/uapi/drm/vc4_drm.h +++ b/include/uapi/drm/vc4_drm.h @@ -31,12 +31,14 @@ #define DRM_VC4_WAIT_BO 0x02 #define DRM_VC4_CREATE_BO 0x03 #define DRM_VC4_MMAP_BO 0x04 +#define DRM_VC4_CREATE_SHADER_BO 0x05 #define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl) #define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno) #define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo) #define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo) #define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo) +#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR( DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo) struct drm_vc4_submit_rcl_surface { uint32_t hindex; /* Handle index, or ~0 if not present. */ @@ -183,6 +185,29 @@ struct drm_vc4_create_bo { }; /** + * struct drm_vc4_create_shader_bo - ioctl argument for creating VC4 + * shader BOs. + * + * Since allowing a shader to be overwritten while it's also being + * executed from would allow privlege escalation, shaders must be + * created using this ioctl, and they can't be mmapped later. + */ +struct drm_vc4_create_shader_bo { + /* Size of the data argument. */ + uint32_t size; + /* Flags, currently must be 0. */ + uint32_t flags; + + /* Pointer to the data. */ + uint64_t data; + + /** Returned GEM handle for the BO. */ + uint32_t handle; + /* Pad, must be 0. */ + uint32_t pad; +}; + +/** * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs. * * This doesn't actually perform an mmap. Instead, it returns the |