cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

virtgpu_ioctl.c (21901B)


      1/*
      2 * Copyright (C) 2015 Red Hat, Inc.
      3 * All Rights Reserved.
      4 *
      5 * Authors:
      6 *    Dave Airlie
      7 *    Alon Levy
      8 *
      9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
     15 *
     16 * The above copyright notice and this permission notice shall be included in
     17 * all copies or substantial portions of the Software.
     18 *
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     22 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     25 * OTHER DEALINGS IN THE SOFTWARE.
     26 */
     27
     28#include <linux/file.h>
     29#include <linux/sync_file.h>
     30#include <linux/uaccess.h>
     31
     32#include <drm/drm_file.h>
     33#include <drm/virtgpu_drm.h>
     34
     35#include "virtgpu_drv.h"
     36
     37#define VIRTGPU_BLOB_FLAG_USE_MASK (VIRTGPU_BLOB_FLAG_USE_MAPPABLE | \
     38				    VIRTGPU_BLOB_FLAG_USE_SHAREABLE | \
     39				    VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE)
     40
     41static int virtio_gpu_fence_event_create(struct drm_device *dev,
     42					 struct drm_file *file,
     43					 struct virtio_gpu_fence *fence,
     44					 uint32_t ring_idx)
     45{
     46	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
     47	struct virtio_gpu_fence_event *e = NULL;
     48	int ret;
     49
     50	if (!(vfpriv->ring_idx_mask & (1 << ring_idx)))
     51		return 0;
     52
     53	e = kzalloc(sizeof(*e), GFP_KERNEL);
     54	if (!e)
     55		return -ENOMEM;
     56
     57	e->event.type = VIRTGPU_EVENT_FENCE_SIGNALED;
     58	e->event.length = sizeof(e->event);
     59
     60	ret = drm_event_reserve_init(dev, file, &e->base, &e->event);
     61	if (ret)
     62		goto free;
     63
     64	fence->e = e;
     65	return 0;
     66free:
     67	kfree(e);
     68	return ret;
     69}
     70
     71/* Must be called with &virtio_gpu_fpriv.struct_mutex held. */
     72static void virtio_gpu_create_context_locked(struct virtio_gpu_device *vgdev,
     73					     struct virtio_gpu_fpriv *vfpriv)
     74{
     75	char dbgname[TASK_COMM_LEN];
     76
     77	get_task_comm(dbgname, current);
     78	virtio_gpu_cmd_context_create(vgdev, vfpriv->ctx_id,
     79				      vfpriv->context_init, strlen(dbgname),
     80				      dbgname);
     81
     82	vfpriv->context_created = true;
     83}
     84
     85void virtio_gpu_create_context(struct drm_device *dev, struct drm_file *file)
     86{
     87	struct virtio_gpu_device *vgdev = dev->dev_private;
     88	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
     89
     90	mutex_lock(&vfpriv->context_lock);
     91	if (vfpriv->context_created)
     92		goto out_unlock;
     93
     94	virtio_gpu_create_context_locked(vgdev, vfpriv);
     95
     96out_unlock:
     97	mutex_unlock(&vfpriv->context_lock);
     98}
     99
    100static int virtio_gpu_map_ioctl(struct drm_device *dev, void *data,
    101				struct drm_file *file)
    102{
    103	struct virtio_gpu_device *vgdev = dev->dev_private;
    104	struct drm_virtgpu_map *virtio_gpu_map = data;
    105
    106	return virtio_gpu_mode_dumb_mmap(file, vgdev->ddev,
    107					 virtio_gpu_map->handle,
    108					 &virtio_gpu_map->offset);
    109}
    110
    111/*
    112 * Usage of execbuffer:
    113 * Relocations need to take into account the full VIRTIO_GPUDrawable size.
    114 * However, the command as passed from user space must *not* contain the initial
    115 * VIRTIO_GPUReleaseInfo struct (first XXX bytes)
    116 */
    117static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
    118				 struct drm_file *file)
    119{
    120	struct drm_virtgpu_execbuffer *exbuf = data;
    121	struct virtio_gpu_device *vgdev = dev->dev_private;
    122	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
    123	struct virtio_gpu_fence *out_fence;
    124	int ret;
    125	uint32_t *bo_handles = NULL;
    126	void __user *user_bo_handles = NULL;
    127	struct virtio_gpu_object_array *buflist = NULL;
    128	struct sync_file *sync_file;
    129	int in_fence_fd = exbuf->fence_fd;
    130	int out_fence_fd = -1;
    131	void *buf;
    132	uint64_t fence_ctx;
    133	uint32_t ring_idx;
    134
    135	fence_ctx = vgdev->fence_drv.context;
    136	ring_idx = 0;
    137
    138	if (vgdev->has_virgl_3d == false)
    139		return -ENOSYS;
    140
    141	if ((exbuf->flags & ~VIRTGPU_EXECBUF_FLAGS))
    142		return -EINVAL;
    143
    144	if ((exbuf->flags & VIRTGPU_EXECBUF_RING_IDX)) {
    145		if (exbuf->ring_idx >= vfpriv->num_rings)
    146			return -EINVAL;
    147
    148		if (!vfpriv->base_fence_ctx)
    149			return -EINVAL;
    150
    151		fence_ctx = vfpriv->base_fence_ctx;
    152		ring_idx = exbuf->ring_idx;
    153	}
    154
    155	exbuf->fence_fd = -1;
    156
    157	virtio_gpu_create_context(dev, file);
    158	if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_IN) {
    159		struct dma_fence *in_fence;
    160
    161		in_fence = sync_file_get_fence(in_fence_fd);
    162
    163		if (!in_fence)
    164			return -EINVAL;
    165
    166		/*
    167		 * Wait if the fence is from a foreign context, or if the fence
    168		 * array contains any fence from a foreign context.
    169		 */
    170		ret = 0;
    171		if (!dma_fence_match_context(in_fence, vgdev->fence_drv.context))
    172			ret = dma_fence_wait(in_fence, true);
    173
    174		dma_fence_put(in_fence);
    175		if (ret)
    176			return ret;
    177	}
    178
    179	if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) {
    180		out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
    181		if (out_fence_fd < 0)
    182			return out_fence_fd;
    183	}
    184
    185	if (exbuf->num_bo_handles) {
    186		bo_handles = kvmalloc_array(exbuf->num_bo_handles,
    187					    sizeof(uint32_t), GFP_KERNEL);
    188		if (!bo_handles) {
    189			ret = -ENOMEM;
    190			goto out_unused_fd;
    191		}
    192
    193		user_bo_handles = u64_to_user_ptr(exbuf->bo_handles);
    194		if (copy_from_user(bo_handles, user_bo_handles,
    195				   exbuf->num_bo_handles * sizeof(uint32_t))) {
    196			ret = -EFAULT;
    197			goto out_unused_fd;
    198		}
    199
    200		buflist = virtio_gpu_array_from_handles(file, bo_handles,
    201							exbuf->num_bo_handles);
    202		if (!buflist) {
    203			ret = -ENOENT;
    204			goto out_unused_fd;
    205		}
    206		kvfree(bo_handles);
    207		bo_handles = NULL;
    208	}
    209
    210	buf = vmemdup_user(u64_to_user_ptr(exbuf->command), exbuf->size);
    211	if (IS_ERR(buf)) {
    212		ret = PTR_ERR(buf);
    213		goto out_unused_fd;
    214	}
    215
    216	if (buflist) {
    217		ret = virtio_gpu_array_lock_resv(buflist);
    218		if (ret)
    219			goto out_memdup;
    220	}
    221
    222	out_fence = virtio_gpu_fence_alloc(vgdev, fence_ctx, ring_idx);
    223	if(!out_fence) {
    224		ret = -ENOMEM;
    225		goto out_unresv;
    226	}
    227
    228	ret = virtio_gpu_fence_event_create(dev, file, out_fence, ring_idx);
    229	if (ret)
    230		goto out_unresv;
    231
    232	if (out_fence_fd >= 0) {
    233		sync_file = sync_file_create(&out_fence->f);
    234		if (!sync_file) {
    235			dma_fence_put(&out_fence->f);
    236			ret = -ENOMEM;
    237			goto out_unresv;
    238		}
    239
    240		exbuf->fence_fd = out_fence_fd;
    241		fd_install(out_fence_fd, sync_file->file);
    242	}
    243
    244	virtio_gpu_cmd_submit(vgdev, buf, exbuf->size,
    245			      vfpriv->ctx_id, buflist, out_fence);
    246	dma_fence_put(&out_fence->f);
    247	virtio_gpu_notify(vgdev);
    248	return 0;
    249
    250out_unresv:
    251	if (buflist)
    252		virtio_gpu_array_unlock_resv(buflist);
    253out_memdup:
    254	kvfree(buf);
    255out_unused_fd:
    256	kvfree(bo_handles);
    257	if (buflist)
    258		virtio_gpu_array_put_free(buflist);
    259
    260	if (out_fence_fd >= 0)
    261		put_unused_fd(out_fence_fd);
    262
    263	return ret;
    264}
    265
    266static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data,
    267				     struct drm_file *file)
    268{
    269	struct virtio_gpu_device *vgdev = dev->dev_private;
    270	struct drm_virtgpu_getparam *param = data;
    271	int value;
    272
    273	switch (param->param) {
    274	case VIRTGPU_PARAM_3D_FEATURES:
    275		value = vgdev->has_virgl_3d ? 1 : 0;
    276		break;
    277	case VIRTGPU_PARAM_CAPSET_QUERY_FIX:
    278		value = 1;
    279		break;
    280	case VIRTGPU_PARAM_RESOURCE_BLOB:
    281		value = vgdev->has_resource_blob ? 1 : 0;
    282		break;
    283	case VIRTGPU_PARAM_HOST_VISIBLE:
    284		value = vgdev->has_host_visible ? 1 : 0;
    285		break;
    286	case VIRTGPU_PARAM_CROSS_DEVICE:
    287		value = vgdev->has_resource_assign_uuid ? 1 : 0;
    288		break;
    289	case VIRTGPU_PARAM_CONTEXT_INIT:
    290		value = vgdev->has_context_init ? 1 : 0;
    291		break;
    292	case VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs:
    293		value = vgdev->capset_id_mask;
    294		break;
    295	default:
    296		return -EINVAL;
    297	}
    298	if (copy_to_user(u64_to_user_ptr(param->value), &value, sizeof(int)))
    299		return -EFAULT;
    300
    301	return 0;
    302}
    303
    304static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
    305					    struct drm_file *file)
    306{
    307	struct virtio_gpu_device *vgdev = dev->dev_private;
    308	struct drm_virtgpu_resource_create *rc = data;
    309	struct virtio_gpu_fence *fence;
    310	int ret;
    311	struct virtio_gpu_object *qobj;
    312	struct drm_gem_object *obj;
    313	uint32_t handle = 0;
    314	struct virtio_gpu_object_params params = { 0 };
    315
    316	if (vgdev->has_virgl_3d) {
    317		virtio_gpu_create_context(dev, file);
    318		params.virgl = true;
    319		params.target = rc->target;
    320		params.bind = rc->bind;
    321		params.depth = rc->depth;
    322		params.array_size = rc->array_size;
    323		params.last_level = rc->last_level;
    324		params.nr_samples = rc->nr_samples;
    325		params.flags = rc->flags;
    326	} else {
    327		if (rc->depth > 1)
    328			return -EINVAL;
    329		if (rc->nr_samples > 1)
    330			return -EINVAL;
    331		if (rc->last_level > 1)
    332			return -EINVAL;
    333		if (rc->target != 2)
    334			return -EINVAL;
    335		if (rc->array_size > 1)
    336			return -EINVAL;
    337	}
    338
    339	params.format = rc->format;
    340	params.width = rc->width;
    341	params.height = rc->height;
    342	params.size = rc->size;
    343	/* allocate a single page size object */
    344	if (params.size == 0)
    345		params.size = PAGE_SIZE;
    346
    347	fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context, 0);
    348	if (!fence)
    349		return -ENOMEM;
    350	ret = virtio_gpu_object_create(vgdev, &params, &qobj, fence);
    351	dma_fence_put(&fence->f);
    352	if (ret < 0)
    353		return ret;
    354	obj = &qobj->base.base;
    355
    356	ret = drm_gem_handle_create(file, obj, &handle);
    357	if (ret) {
    358		drm_gem_object_release(obj);
    359		return ret;
    360	}
    361	drm_gem_object_put(obj);
    362
    363	rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */
    364	rc->bo_handle = handle;
    365	return 0;
    366}
    367
    368static int virtio_gpu_resource_info_ioctl(struct drm_device *dev, void *data,
    369					  struct drm_file *file)
    370{
    371	struct drm_virtgpu_resource_info *ri = data;
    372	struct drm_gem_object *gobj = NULL;
    373	struct virtio_gpu_object *qobj = NULL;
    374
    375	gobj = drm_gem_object_lookup(file, ri->bo_handle);
    376	if (gobj == NULL)
    377		return -ENOENT;
    378
    379	qobj = gem_to_virtio_gpu_obj(gobj);
    380
    381	ri->size = qobj->base.base.size;
    382	ri->res_handle = qobj->hw_res_handle;
    383	if (qobj->host3d_blob || qobj->guest_blob)
    384		ri->blob_mem = qobj->blob_mem;
    385
    386	drm_gem_object_put(gobj);
    387	return 0;
    388}
    389
    390static int virtio_gpu_transfer_from_host_ioctl(struct drm_device *dev,
    391					       void *data,
    392					       struct drm_file *file)
    393{
    394	struct virtio_gpu_device *vgdev = dev->dev_private;
    395	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
    396	struct drm_virtgpu_3d_transfer_from_host *args = data;
    397	struct virtio_gpu_object *bo;
    398	struct virtio_gpu_object_array *objs;
    399	struct virtio_gpu_fence *fence;
    400	int ret;
    401	u32 offset = args->offset;
    402
    403	if (vgdev->has_virgl_3d == false)
    404		return -ENOSYS;
    405
    406	virtio_gpu_create_context(dev, file);
    407	objs = virtio_gpu_array_from_handles(file, &args->bo_handle, 1);
    408	if (objs == NULL)
    409		return -ENOENT;
    410
    411	bo = gem_to_virtio_gpu_obj(objs->objs[0]);
    412	if (bo->guest_blob && !bo->host3d_blob) {
    413		ret = -EINVAL;
    414		goto err_put_free;
    415	}
    416
    417	if (!bo->host3d_blob && (args->stride || args->layer_stride)) {
    418		ret = -EINVAL;
    419		goto err_put_free;
    420	}
    421
    422	ret = virtio_gpu_array_lock_resv(objs);
    423	if (ret != 0)
    424		goto err_put_free;
    425
    426	fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context, 0);
    427	if (!fence) {
    428		ret = -ENOMEM;
    429		goto err_unlock;
    430	}
    431
    432	virtio_gpu_cmd_transfer_from_host_3d
    433		(vgdev, vfpriv->ctx_id, offset, args->level, args->stride,
    434		 args->layer_stride, &args->box, objs, fence);
    435	dma_fence_put(&fence->f);
    436	virtio_gpu_notify(vgdev);
    437	return 0;
    438
    439err_unlock:
    440	virtio_gpu_array_unlock_resv(objs);
    441err_put_free:
    442	virtio_gpu_array_put_free(objs);
    443	return ret;
    444}
    445
    446static int virtio_gpu_transfer_to_host_ioctl(struct drm_device *dev, void *data,
    447					     struct drm_file *file)
    448{
    449	struct virtio_gpu_device *vgdev = dev->dev_private;
    450	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
    451	struct drm_virtgpu_3d_transfer_to_host *args = data;
    452	struct virtio_gpu_object *bo;
    453	struct virtio_gpu_object_array *objs;
    454	struct virtio_gpu_fence *fence;
    455	int ret;
    456	u32 offset = args->offset;
    457
    458	objs = virtio_gpu_array_from_handles(file, &args->bo_handle, 1);
    459	if (objs == NULL)
    460		return -ENOENT;
    461
    462	bo = gem_to_virtio_gpu_obj(objs->objs[0]);
    463	if (bo->guest_blob && !bo->host3d_blob) {
    464		ret = -EINVAL;
    465		goto err_put_free;
    466	}
    467
    468	if (!vgdev->has_virgl_3d) {
    469		virtio_gpu_cmd_transfer_to_host_2d
    470			(vgdev, offset,
    471			 args->box.w, args->box.h, args->box.x, args->box.y,
    472			 objs, NULL);
    473	} else {
    474		virtio_gpu_create_context(dev, file);
    475
    476		if (!bo->host3d_blob && (args->stride || args->layer_stride)) {
    477			ret = -EINVAL;
    478			goto err_put_free;
    479		}
    480
    481		ret = virtio_gpu_array_lock_resv(objs);
    482		if (ret != 0)
    483			goto err_put_free;
    484
    485		ret = -ENOMEM;
    486		fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context,
    487					       0);
    488		if (!fence)
    489			goto err_unlock;
    490
    491		virtio_gpu_cmd_transfer_to_host_3d
    492			(vgdev,
    493			 vfpriv ? vfpriv->ctx_id : 0, offset, args->level,
    494			 args->stride, args->layer_stride, &args->box, objs,
    495			 fence);
    496		dma_fence_put(&fence->f);
    497	}
    498	virtio_gpu_notify(vgdev);
    499	return 0;
    500
    501err_unlock:
    502	virtio_gpu_array_unlock_resv(objs);
    503err_put_free:
    504	virtio_gpu_array_put_free(objs);
    505	return ret;
    506}
    507
    508static int virtio_gpu_wait_ioctl(struct drm_device *dev, void *data,
    509				 struct drm_file *file)
    510{
    511	struct drm_virtgpu_3d_wait *args = data;
    512	struct drm_gem_object *obj;
    513	long timeout = 15 * HZ;
    514	int ret;
    515
    516	obj = drm_gem_object_lookup(file, args->handle);
    517	if (obj == NULL)
    518		return -ENOENT;
    519
    520	if (args->flags & VIRTGPU_WAIT_NOWAIT) {
    521		ret = dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ);
    522	} else {
    523		ret = dma_resv_wait_timeout(obj->resv, DMA_RESV_USAGE_READ,
    524					    true, timeout);
    525	}
    526	if (ret == 0)
    527		ret = -EBUSY;
    528	else if (ret > 0)
    529		ret = 0;
    530
    531	drm_gem_object_put(obj);
    532	return ret;
    533}
    534
    535static int virtio_gpu_get_caps_ioctl(struct drm_device *dev,
    536				void *data, struct drm_file *file)
    537{
    538	struct virtio_gpu_device *vgdev = dev->dev_private;
    539	struct drm_virtgpu_get_caps *args = data;
    540	unsigned size, host_caps_size;
    541	int i;
    542	int found_valid = -1;
    543	int ret;
    544	struct virtio_gpu_drv_cap_cache *cache_ent;
    545	void *ptr;
    546
    547	if (vgdev->num_capsets == 0)
    548		return -ENOSYS;
    549
    550	/* don't allow userspace to pass 0 */
    551	if (args->size == 0)
    552		return -EINVAL;
    553
    554	spin_lock(&vgdev->display_info_lock);
    555	for (i = 0; i < vgdev->num_capsets; i++) {
    556		if (vgdev->capsets[i].id == args->cap_set_id) {
    557			if (vgdev->capsets[i].max_version >= args->cap_set_ver) {
    558				found_valid = i;
    559				break;
    560			}
    561		}
    562	}
    563
    564	if (found_valid == -1) {
    565		spin_unlock(&vgdev->display_info_lock);
    566		return -EINVAL;
    567	}
    568
    569	host_caps_size = vgdev->capsets[found_valid].max_size;
    570	/* only copy to user the minimum of the host caps size or the guest caps size */
    571	size = min(args->size, host_caps_size);
    572
    573	list_for_each_entry(cache_ent, &vgdev->cap_cache, head) {
    574		if (cache_ent->id == args->cap_set_id &&
    575		    cache_ent->version == args->cap_set_ver) {
    576			spin_unlock(&vgdev->display_info_lock);
    577			goto copy_exit;
    578		}
    579	}
    580	spin_unlock(&vgdev->display_info_lock);
    581
    582	/* not in cache - need to talk to hw */
    583	virtio_gpu_cmd_get_capset(vgdev, found_valid, args->cap_set_ver,
    584				  &cache_ent);
    585	virtio_gpu_notify(vgdev);
    586
    587copy_exit:
    588	ret = wait_event_timeout(vgdev->resp_wq,
    589				 atomic_read(&cache_ent->is_valid), 5 * HZ);
    590	if (!ret)
    591		return -EBUSY;
    592
    593	/* is_valid check must proceed before copy of the cache entry. */
    594	smp_rmb();
    595
    596	ptr = cache_ent->caps_cache;
    597
    598	if (copy_to_user(u64_to_user_ptr(args->addr), ptr, size))
    599		return -EFAULT;
    600
    601	return 0;
    602}
    603
    604static int verify_blob(struct virtio_gpu_device *vgdev,
    605		       struct virtio_gpu_fpriv *vfpriv,
    606		       struct virtio_gpu_object_params *params,
    607		       struct drm_virtgpu_resource_create_blob *rc_blob,
    608		       bool *guest_blob, bool *host3d_blob)
    609{
    610	if (!vgdev->has_resource_blob)
    611		return -EINVAL;
    612
    613	if (rc_blob->blob_flags & ~VIRTGPU_BLOB_FLAG_USE_MASK)
    614		return -EINVAL;
    615
    616	if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) {
    617		if (!vgdev->has_resource_assign_uuid)
    618			return -EINVAL;
    619	}
    620
    621	switch (rc_blob->blob_mem) {
    622	case VIRTGPU_BLOB_MEM_GUEST:
    623		*guest_blob = true;
    624		break;
    625	case VIRTGPU_BLOB_MEM_HOST3D_GUEST:
    626		*guest_blob = true;
    627		fallthrough;
    628	case VIRTGPU_BLOB_MEM_HOST3D:
    629		*host3d_blob = true;
    630		break;
    631	default:
    632		return -EINVAL;
    633	}
    634
    635	if (*host3d_blob) {
    636		if (!vgdev->has_virgl_3d)
    637			return -EINVAL;
    638
    639		/* Must be dword aligned. */
    640		if (rc_blob->cmd_size % 4 != 0)
    641			return -EINVAL;
    642
    643		params->ctx_id = vfpriv->ctx_id;
    644		params->blob_id = rc_blob->blob_id;
    645	} else {
    646		if (rc_blob->blob_id != 0)
    647			return -EINVAL;
    648
    649		if (rc_blob->cmd_size != 0)
    650			return -EINVAL;
    651	}
    652
    653	params->blob_mem = rc_blob->blob_mem;
    654	params->size = rc_blob->size;
    655	params->blob = true;
    656	params->blob_flags = rc_blob->blob_flags;
    657	return 0;
    658}
    659
    660static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
    661						 void *data,
    662						 struct drm_file *file)
    663{
    664	int ret = 0;
    665	uint32_t handle = 0;
    666	bool guest_blob = false;
    667	bool host3d_blob = false;
    668	struct drm_gem_object *obj;
    669	struct virtio_gpu_object *bo;
    670	struct virtio_gpu_object_params params = { 0 };
    671	struct virtio_gpu_device *vgdev = dev->dev_private;
    672	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
    673	struct drm_virtgpu_resource_create_blob *rc_blob = data;
    674
    675	if (verify_blob(vgdev, vfpriv, &params, rc_blob,
    676			&guest_blob, &host3d_blob))
    677		return -EINVAL;
    678
    679	if (vgdev->has_virgl_3d)
    680		virtio_gpu_create_context(dev, file);
    681
    682	if (rc_blob->cmd_size) {
    683		void *buf;
    684
    685		buf = memdup_user(u64_to_user_ptr(rc_blob->cmd),
    686				  rc_blob->cmd_size);
    687
    688		if (IS_ERR(buf))
    689			return PTR_ERR(buf);
    690
    691		virtio_gpu_cmd_submit(vgdev, buf, rc_blob->cmd_size,
    692				      vfpriv->ctx_id, NULL, NULL);
    693	}
    694
    695	if (guest_blob)
    696		ret = virtio_gpu_object_create(vgdev, &params, &bo, NULL);
    697	else if (!guest_blob && host3d_blob)
    698		ret = virtio_gpu_vram_create(vgdev, &params, &bo);
    699	else
    700		return -EINVAL;
    701
    702	if (ret < 0)
    703		return ret;
    704
    705	bo->guest_blob = guest_blob;
    706	bo->host3d_blob = host3d_blob;
    707	bo->blob_mem = rc_blob->blob_mem;
    708	bo->blob_flags = rc_blob->blob_flags;
    709
    710	obj = &bo->base.base;
    711	if (params.blob_flags & VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) {
    712		ret = virtio_gpu_resource_assign_uuid(vgdev, bo);
    713		if (ret) {
    714			drm_gem_object_release(obj);
    715			return ret;
    716		}
    717	}
    718
    719	ret = drm_gem_handle_create(file, obj, &handle);
    720	if (ret) {
    721		drm_gem_object_release(obj);
    722		return ret;
    723	}
    724	drm_gem_object_put(obj);
    725
    726	rc_blob->res_handle = bo->hw_res_handle;
    727	rc_blob->bo_handle = handle;
    728
    729	return 0;
    730}
    731
    732static int virtio_gpu_context_init_ioctl(struct drm_device *dev,
    733					 void *data, struct drm_file *file)
    734{
    735	int ret = 0;
    736	uint32_t num_params, i, param, value;
    737	uint64_t valid_ring_mask;
    738	size_t len;
    739	struct drm_virtgpu_context_set_param *ctx_set_params = NULL;
    740	struct virtio_gpu_device *vgdev = dev->dev_private;
    741	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
    742	struct drm_virtgpu_context_init *args = data;
    743
    744	num_params = args->num_params;
    745	len = num_params * sizeof(struct drm_virtgpu_context_set_param);
    746
    747	if (!vgdev->has_context_init || !vgdev->has_virgl_3d)
    748		return -EINVAL;
    749
    750	/* Number of unique parameters supported at this time. */
    751	if (num_params > 3)
    752		return -EINVAL;
    753
    754	ctx_set_params = memdup_user(u64_to_user_ptr(args->ctx_set_params),
    755				     len);
    756
    757	if (IS_ERR(ctx_set_params))
    758		return PTR_ERR(ctx_set_params);
    759
    760	mutex_lock(&vfpriv->context_lock);
    761	if (vfpriv->context_created) {
    762		ret = -EEXIST;
    763		goto out_unlock;
    764	}
    765
    766	for (i = 0; i < num_params; i++) {
    767		param = ctx_set_params[i].param;
    768		value = ctx_set_params[i].value;
    769
    770		switch (param) {
    771		case VIRTGPU_CONTEXT_PARAM_CAPSET_ID:
    772			if (value > MAX_CAPSET_ID) {
    773				ret = -EINVAL;
    774				goto out_unlock;
    775			}
    776
    777			if ((vgdev->capset_id_mask & (1ULL << value)) == 0) {
    778				ret = -EINVAL;
    779				goto out_unlock;
    780			}
    781
    782			/* Context capset ID already set */
    783			if (vfpriv->context_init &
    784			    VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK) {
    785				ret = -EINVAL;
    786				goto out_unlock;
    787			}
    788
    789			vfpriv->context_init |= value;
    790			break;
    791		case VIRTGPU_CONTEXT_PARAM_NUM_RINGS:
    792			if (vfpriv->base_fence_ctx) {
    793				ret = -EINVAL;
    794				goto out_unlock;
    795			}
    796
    797			if (value > MAX_RINGS) {
    798				ret = -EINVAL;
    799				goto out_unlock;
    800			}
    801
    802			vfpriv->base_fence_ctx = dma_fence_context_alloc(value);
    803			vfpriv->num_rings = value;
    804			break;
    805		case VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK:
    806			if (vfpriv->ring_idx_mask) {
    807				ret = -EINVAL;
    808				goto out_unlock;
    809			}
    810
    811			vfpriv->ring_idx_mask = value;
    812			break;
    813		default:
    814			ret = -EINVAL;
    815			goto out_unlock;
    816		}
    817	}
    818
    819	if (vfpriv->ring_idx_mask) {
    820		valid_ring_mask = 0;
    821		for (i = 0; i < vfpriv->num_rings; i++)
    822			valid_ring_mask |= 1ULL << i;
    823
    824		if (~valid_ring_mask & vfpriv->ring_idx_mask) {
    825			ret = -EINVAL;
    826			goto out_unlock;
    827		}
    828	}
    829
    830	virtio_gpu_create_context_locked(vgdev, vfpriv);
    831	virtio_gpu_notify(vgdev);
    832
    833out_unlock:
    834	mutex_unlock(&vfpriv->context_lock);
    835	kfree(ctx_set_params);
    836	return ret;
    837}
    838
    839struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = {
    840	DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl,
    841			  DRM_RENDER_ALLOW),
    842
    843	DRM_IOCTL_DEF_DRV(VIRTGPU_EXECBUFFER, virtio_gpu_execbuffer_ioctl,
    844			  DRM_RENDER_ALLOW),
    845
    846	DRM_IOCTL_DEF_DRV(VIRTGPU_GETPARAM, virtio_gpu_getparam_ioctl,
    847			  DRM_RENDER_ALLOW),
    848
    849	DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE,
    850			  virtio_gpu_resource_create_ioctl,
    851			  DRM_RENDER_ALLOW),
    852
    853	DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_INFO, virtio_gpu_resource_info_ioctl,
    854			  DRM_RENDER_ALLOW),
    855
    856	/* make transfer async to the main ring? - no sure, can we
    857	 * thread these in the underlying GL
    858	 */
    859	DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_FROM_HOST,
    860			  virtio_gpu_transfer_from_host_ioctl,
    861			  DRM_RENDER_ALLOW),
    862	DRM_IOCTL_DEF_DRV(VIRTGPU_TRANSFER_TO_HOST,
    863			  virtio_gpu_transfer_to_host_ioctl,
    864			  DRM_RENDER_ALLOW),
    865
    866	DRM_IOCTL_DEF_DRV(VIRTGPU_WAIT, virtio_gpu_wait_ioctl,
    867			  DRM_RENDER_ALLOW),
    868
    869	DRM_IOCTL_DEF_DRV(VIRTGPU_GET_CAPS, virtio_gpu_get_caps_ioctl,
    870			  DRM_RENDER_ALLOW),
    871
    872	DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE_BLOB,
    873			  virtio_gpu_resource_create_blob_ioctl,
    874			  DRM_RENDER_ALLOW),
    875
    876	DRM_IOCTL_DEF_DRV(VIRTGPU_CONTEXT_INIT, virtio_gpu_context_init_ioctl,
    877			  DRM_RENDER_ALLOW),
    878};