Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ccb69913 authored by Shrenuj Bansal's avatar Shrenuj Bansal Committed by Michael Bohan
Browse files

msm: kgsl: Add compat ioctls feature



Makes a compat ioctl counterpart of the regular ioctl function.
Required for having 32 bit user processes to use our ioctls in a
64 bit kernel.

Change-Id: Ied23ff089ed46b3cf40c3a5e3138faf9ed6bfc64
Signed-off-by: default avatarShrenuj Bansal <shrenujb@codeaurora.org>
parent b553d306
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
msm_kgsl_core-$(CONFIG_MSM_KGSL_DRM) += kgsl_drm.o
msm_kgsl_core-$(CONFIG_SYNC) += kgsl_sync.o
msm_kgsl_core-$(CONFIG_COMPAT) += kgsl_compat.o

msm_adreno-y += \
	adreno_ringbuffer.o \
@@ -32,6 +33,7 @@ msm_adreno-y += \
	adreno_cp_parser.o

msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o adreno_profile.o
msm_adreno-$(CONFIG_COMPAT) += adreno_compat.o

msm_kgsl_core-objs = $(msm_kgsl_core-y)
msm_adreno-objs = $(msm_adreno-y)
+3 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "kgsl_cffdump.h"
#include "kgsl_sharedmem.h"
#include "kgsl_iommu.h"
#include "kgsl_compat.h"
#include "kgsl_trace.h"

#include "adreno.h"
@@ -3106,10 +3107,12 @@ static const struct kgsl_functable adreno_functable = {
	.start = adreno_start,
	.stop = adreno_stop,
	.getproperty = adreno_getproperty,
	.getproperty_compat = adreno_getproperty_compat,
	.waittimestamp = adreno_waittimestamp,
	.readtimestamp = adreno_readtimestamp,
	.issueibcmds = adreno_ringbuffer_issueibcmds,
	.ioctl = adreno_ioctl,
	.compat_ioctl = adreno_compat_ioctl,
	.setup_pt = adreno_setup_pt,
	.cleanup_pt = adreno_cleanup_pt,
	.power_stats = adreno_power_stats,
+139 −0
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
#include <linux/uaccess.h>
#include <linux/ioctl.h>

#include "kgsl.h"
#include "kgsl_compat.h"

#include "adreno.h"

int adreno_getproperty_compat(struct kgsl_device *device,
				enum kgsl_property_type type,
				void __user *value,
				size_t sizebytes)
{
	int status = -EINVAL;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	switch (type) {
	case KGSL_PROP_DEVICE_INFO:
		{
			struct kgsl_devinfo_compat devinfo;

			if (sizebytes != sizeof(devinfo)) {
				status = -EINVAL;
				break;
			}

			memset(&devinfo, 0, sizeof(devinfo));
			devinfo.device_id = device->id + 1;
			devinfo.chip_id = adreno_dev->chip_id;
			devinfo.mmu_enabled = kgsl_mmu_enabled();
			devinfo.gpu_id = adreno_dev->gpurev;
			devinfo.gmem_gpubaseaddr = adreno_dev->gmem_base;
			devinfo.gmem_sizebytes = adreno_dev->gmem_size;

			if (copy_to_user(value, &devinfo, sizeof(devinfo)) !=
					0) {
				status = -EFAULT;
				break;
			}
			status = 0;
		}
		break;
	case KGSL_PROP_DEVICE_SHADOW:
		{
			struct kgsl_shadowprop_compat shadowprop;

			if (sizebytes != sizeof(shadowprop)) {
				status = -EINVAL;
				break;
			}
			memset(&shadowprop, 0, sizeof(shadowprop));
			if (device->memstore.hostptr) {
				/*
				 * NOTE: with mmu enabled, gpuaddr doesn't mean
				 * anything to mmap().
				 */
				shadowprop.gpuaddr = device->memstore.gpuaddr;
				shadowprop.size = device->memstore.size;
				/*
				 * GSL needs this to be set, even if it
				 * appears to be meaningless
				 */
				shadowprop.flags = KGSL_FLAGS_INITIALIZED |
					KGSL_FLAGS_PER_CONTEXT_TIMESTAMPS;
			}
			if (copy_to_user(value, &shadowprop,
				sizeof(shadowprop))) {
				status = -EFAULT;
				break;
			}
			status = 0;
		}
		break;
	default:
		/*
		 * Call the adreno_getproperty to check if the property type
		 * was KGSL_PROP_MMU_ENABLE or KGSL_PROP_INTERRUPT_WAITS
		 */
		status = device->ftbl->getproperty(device, type, value,
						sizebytes);
	}

	return status;
}

long adreno_compat_ioctl(struct kgsl_device_private *dev_priv,
			      unsigned int cmd, void *data)
{
	struct kgsl_device *device = dev_priv->device;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int result = 0;

	switch (cmd) {
	case IOCTL_KGSL_PERFCOUNTER_QUERY_COMPAT: {
		struct kgsl_perfcounter_query_compat *query32 = data;
		struct kgsl_perfcounter_query query;
		query.groupid = query32->groupid;
		query.countables = (unsigned int __user *)(uintptr_t)
							query32->countables;
		query.count = query32->count;
		query.max_counters = query32->max_counters;
		result = adreno_perfcounter_query_group(adreno_dev,
			query.groupid, query.countables,
			query.count, &query.max_counters);
		query32->max_counters = query.max_counters;
		break;
	}
	case IOCTL_KGSL_PERFCOUNTER_READ_COMPAT: {
		struct kgsl_perfcounter_read_compat *read32 = data;
		struct kgsl_perfcounter_read read;
		read.reads = (struct kgsl_perfcounter_read_group __user *)
				(uintptr_t)read32->reads;
		read.count = read32->count;
		result = adreno_perfcounter_read_group(adreno_dev,
			read.reads, read.count);
		break;
	}
	default:
		KGSL_DRV_INFO(dev_priv->device,
			"invalid ioctl code %08x\n", cmd);
		result = -ENOIOCTLCMD;
		break;
	}
	return result;

}
+21 −2
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
#include "kgsl_trace.h"
#include "kgsl_sync.h"
#include "adreno.h"
#include "kgsl_compat.h"

#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "kgsl."
@@ -1318,6 +1319,11 @@ long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
		break;
	}
	default:
		if (is_compat_task())
			result = dev_priv->device->ftbl->getproperty_compat(
					dev_priv->device, param->type,
					param->value, param->sizebytes);
		else
			result = dev_priv->device->ftbl->getproperty(
					dev_priv->device, param->type,
					param->value, param->sizebytes);
@@ -2029,6 +2035,12 @@ static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device,
	if (IS_ERR(cmdbatch))
		return cmdbatch;

	if (is_compat_task()) {
		ret = kgsl_cmdbatch_create_compat(device, flags, cmdbatch,
					cmdlist, numcmds, synclist, numsyncs);
		goto done;
	}

	if (!(flags & KGSL_CONTEXT_SYNC)) {
		if (copy_from_user(cmdbatch->ibdesc, cmdlist,
			sizeof(struct kgsl_ibdesc) * numcmds)) {
@@ -3464,6 +3476,12 @@ long kgsl_ioctl_helper(struct file *filep, unsigned int cmd,
		func = ioctl_funcs[nr].func;
		lock = ioctl_funcs[nr].flags & KGSL_IOCTL_LOCK;
	} else {
		if (is_compat_task() &&
		    cmd != IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET &&
		    cmd != IOCTL_KGSL_PERFCOUNTER_GET &&
		    cmd != IOCTL_KGSL_PERFCOUNTER_PUT)
			func = dev_priv->device->ftbl->compat_ioctl;
		else
			func = dev_priv->device->ftbl->ioctl;
		if (!func) {
			KGSL_DRV_INFO(dev_priv->device,
@@ -4023,6 +4041,7 @@ static const struct file_operations kgsl_fops = {
	.mmap = kgsl_mmap,
	.get_unmapped_area = kgsl_get_unmapped_area,
	.unlocked_ioctl = kgsl_ioctl,
	.compat_ioctl = kgsl_compat_ioctl,
};

struct kgsl_driver kgsl_driver  = {
+406 −0
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/fs.h>
#include <linux/file.h>
#include <linux/uaccess.h>
#include <asm/ioctl.h>

#include "kgsl.h"
#include "kgsl_compat.h"
#include "kgsl_device.h"

#include "adreno.h"

static long
kgsl_ioctl_device_getproperty_compat(struct kgsl_device_private *dev_priv,
				unsigned int cmd, void *data)
{
	struct kgsl_device_getproperty_compat *param32 = data;
	struct kgsl_device_getproperty param;

	param.type = param32->type;
	param.value = compat_ptr(param32->value);
	param.sizebytes = (size_t)param32->sizebytes;

	return kgsl_ioctl_device_getproperty(dev_priv, cmd, &param);
}

static long
kgsl_ioctl_device_setproperty_compat(struct kgsl_device_private *dev_priv,
				unsigned int cmd, void *data)
{
	struct kgsl_device_getproperty_compat *param32 = data;
	struct kgsl_device_getproperty param;

	param.type = param32->type;
	param.value = compat_ptr(param32->value);
	param.sizebytes = (size_t)param32->sizebytes;

	return kgsl_ioctl_device_setproperty(dev_priv, cmd, &param);
}

static long
kgsl_ioctl_submit_commands_compat(struct kgsl_device_private *dev_priv,
				      unsigned int cmd, void *data)
{
	int result;
	struct kgsl_submit_commands_compat *param32 = data;
	struct kgsl_submit_commands param;

	param.context_id = param32->context_id;
	param.flags = param32->flags;
	param.cmdlist = compat_ptr(param32->cmdlist);
	param.numcmds = param32->numcmds;
	param.synclist = compat_ptr(param32->synclist);
	param.numsyncs = param32->numsyncs;
	param.timestamp = param32->timestamp;

	result = kgsl_ioctl_submit_commands(dev_priv, cmd, &param);

	param32->timestamp = param.timestamp;

	return result;
}

static long
kgsl_ioctl_cmdstream_freememontimestamp_compat(struct kgsl_device_private
					*dev_priv, unsigned int cmd,
					void *data)
{
	struct kgsl_cmdstream_freememontimestamp_compat *param32 = data;
	struct kgsl_cmdstream_freememontimestamp param;

	param.gpuaddr = (unsigned long)param32->gpuaddr;
	param.type = param32->type;
	param.timestamp = param32->timestamp;

	return kgsl_ioctl_cmdstream_freememontimestamp(dev_priv, cmd, &param);
}

static long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid_compat(
						struct kgsl_device_private
						*dev_priv, unsigned int cmd,
						void *data)
{
	struct kgsl_cmdstream_freememontimestamp_ctxtid_compat *param32 = data;
	struct kgsl_cmdstream_freememontimestamp_ctxtid param;

	param.context_id = param32->context_id;
	param.gpuaddr = (unsigned long)param32->gpuaddr;
	param.type = param32->type;
	param.timestamp = param32->timestamp;

	return kgsl_ioctl_cmdstream_freememontimestamp_ctxtid(dev_priv, cmd,
								&param);
}

static long kgsl_ioctl_sharedmem_free_compat(struct kgsl_device_private
					*dev_priv, unsigned int cmd,
					void *data)
{
	struct kgsl_sharedmem_free_compat *param32 = data;
	struct kgsl_sharedmem_free param;

	param.gpuaddr = (unsigned long)param32->gpuaddr;

	return kgsl_ioctl_sharedmem_free(dev_priv, cmd, &param);
}

static long kgsl_ioctl_map_user_mem_compat(struct kgsl_device_private
					*dev_priv, unsigned int cmd,
					void *data)
{
	int result = 0;
	struct kgsl_map_user_mem_compat *param32 = data;
	struct kgsl_map_user_mem param;

	param.fd = param32->fd;
	param.gpuaddr = (unsigned long)param32->gpuaddr;
	param.len = (size_t)param32->len;
	param.offset = (size_t)param32->offset;
	param.hostptr = (unsigned long)param32->hostptr;
	param.memtype = param32->memtype;
	param.flags = param32->flags;

	result = kgsl_ioctl_map_user_mem(dev_priv, cmd, &param);

	param32->gpuaddr = gpuaddr_to_compat(param.gpuaddr);
	param32->flags = param.flags;
	return result;
}

static long
kgsl_ioctl_gpumem_sync_cache_compat(struct kgsl_device_private *dev_priv,
				unsigned int cmd, void *data)
{
	struct kgsl_gpumem_sync_cache_compat *param32 = data;
	struct kgsl_gpumem_sync_cache param;

	param.gpuaddr = (unsigned long)param32->gpuaddr;
	param.id = param32->id;
	param.op = param32->op;

	return kgsl_ioctl_gpumem_sync_cache(dev_priv, cmd, &param);
}

static long
kgsl_ioctl_gpumem_sync_cache_bulk_compat(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	struct kgsl_gpumem_sync_cache_bulk_compat *param32 = data;
	struct kgsl_gpumem_sync_cache_bulk param;

	param.id_list = (unsigned int __user *)(uintptr_t)param32->id_list;
	param.count = param32->count;
	param.op = param32->op;

	return kgsl_ioctl_gpumem_sync_cache_bulk(dev_priv, cmd, &param);
}

static long
kgsl_ioctl_sharedmem_flush_cache_compat(struct kgsl_device_private *dev_priv,
				 unsigned int cmd, void *data)
{
	struct kgsl_sharedmem_free_compat *param32 = data;
	struct kgsl_sharedmem_free param;

	param.gpuaddr = (unsigned long)param32->gpuaddr;

	return kgsl_ioctl_sharedmem_flush_cache(dev_priv, cmd, &param);
}

static long
kgsl_ioctl_gpumem_alloc_compat(struct kgsl_device_private *dev_priv,
			unsigned int cmd, void *data)
{
	int result = 0;
	struct kgsl_gpumem_alloc_compat *param32 = data;
	struct kgsl_gpumem_alloc param;

	param.gpuaddr = (unsigned long)param32->gpuaddr;
	param.size = (size_t)param32->size;
	param.flags = param32->flags;

	result = kgsl_ioctl_gpumem_alloc(dev_priv, cmd, &param);

	param32->gpuaddr = gpuaddr_to_compat(param.gpuaddr);
	param32->size = sizet_to_compat(param.size);
	param32->flags = param.flags;

	return result;
}

static long
kgsl_ioctl_gpumem_alloc_id_compat(struct kgsl_device_private *dev_priv,
			unsigned int cmd, void *data)
{
	int result = 0;
	struct kgsl_gpumem_alloc_id_compat *param32 = data;
	struct kgsl_gpumem_alloc_id param;

	param.id = param32->id;
	param.flags = param32->flags;
	param.size = (size_t)param32->size;
	param.mmapsize = (size_t)param32->mmapsize;
	param.gpuaddr = (unsigned long)param32->gpuaddr;

	result = kgsl_ioctl_gpumem_alloc_id(dev_priv, cmd, &param);

	param32->id = param.id;
	param32->flags = param.flags;
	param32->size = sizet_to_compat(param.size);
	param32->mmapsize = sizet_to_compat(param.mmapsize);
	param32->gpuaddr = gpuaddr_to_compat(param.gpuaddr);

	return result;
}

static long
kgsl_ioctl_gpumem_get_info_compat(struct kgsl_device_private *dev_priv,
				unsigned int cmd, void *data)
{
	int result = 0;
	struct kgsl_gpumem_get_info_compat *param32 = data;
	struct kgsl_gpumem_get_info param;

	param.gpuaddr = (unsigned long)param32->gpuaddr;
	param.id = param32->id;

	result = kgsl_ioctl_gpumem_get_info(dev_priv, cmd, &param);

	param32->gpuaddr = gpuaddr_to_compat(param.gpuaddr);
	param32->id = param.id;
	param32->flags = param.flags;
	param32->size = sizet_to_compat(param.size);
	param32->mmapsize = sizet_to_compat(param.mmapsize);
	param32->useraddr = (compat_ulong_t)param.useraddr;

	return result;
}

static long kgsl_ioctl_cff_syncmem_compat(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	struct kgsl_cff_syncmem_compat *param32 = data;
	struct kgsl_cff_syncmem param;

	param.gpuaddr = (unsigned long)param32->gpuaddr;
	param.len = (size_t)param32->len;

	return kgsl_ioctl_cff_syncmem(dev_priv, cmd, &param);
}

static long kgsl_ioctl_timestamp_event_compat(struct kgsl_device_private
				*dev_priv, unsigned int cmd, void *data)
{
	struct kgsl_timestamp_event_compat *param32 = data;
	struct kgsl_timestamp_event param;

	param.type = param32->type;
	param.timestamp = param32->timestamp;
	param.context_id = param32->context_id;
	param.priv = compat_ptr(param32->priv);
	param.len = (size_t)param32->len;

	return kgsl_ioctl_timestamp_event(dev_priv, cmd, &param);
}


static const struct kgsl_ioctl kgsl_compat_ioctl_funcs[] = {
	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY_COMPAT,
			kgsl_ioctl_device_getproperty_compat,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
			kgsl_ioctl_device_waittimestamp,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
			kgsl_ioctl_device_waittimestamp_ctxtid,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS_COMPAT,
			kgsl_ioctl_submit_commands_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
			kgsl_ioctl_cmdstream_readtimestamp,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID,
			kgsl_ioctl_cmdstream_readtimestamp_ctxtid,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_COMPAT,
			kgsl_ioctl_cmdstream_freememontimestamp_compat,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID_COMPAT,
			kgsl_ioctl_cmdstream_freememontimestamp_ctxtid_compat,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
			kgsl_ioctl_drawctxt_create,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
			kgsl_ioctl_drawctxt_destroy,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_MAP_USER_MEM_COMPAT,
			kgsl_ioctl_map_user_mem_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FREE_COMPAT,
			kgsl_ioctl_sharedmem_free_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE_COMPAT,
			kgsl_ioctl_sharedmem_flush_cache_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_COMPAT,
			kgsl_ioctl_gpumem_alloc_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_SYNCMEM_COMPAT,
			kgsl_ioctl_cff_syncmem_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT,
			kgsl_ioctl_cff_user_event, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT_COMPAT,
			kgsl_ioctl_timestamp_event_compat,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY_COMPAT,
			kgsl_ioctl_device_setproperty_compat,
			KGSL_IOCTL_LOCK),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID_COMPAT,
			kgsl_ioctl_gpumem_alloc_id_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
			kgsl_ioctl_gpumem_free_id, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO_COMPAT,
			kgsl_ioctl_gpumem_get_info_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_COMPAT,
			kgsl_ioctl_gpumem_sync_cache_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK_COMPAT,
			kgsl_ioctl_gpumem_sync_cache_bulk_compat, 0),
};

long kgsl_compat_ioctl(struct file *filep, unsigned int cmd,
				unsigned long arg)
{
	return kgsl_ioctl_helper(filep, cmd, kgsl_compat_ioctl_funcs,
				ARRAY_SIZE(kgsl_compat_ioctl_funcs), arg);
}

/**
 * kgsl_cmdbatch_create_compat() - Compat helper to _kgsl_cmdbatch_create()
 * @device: Pointer to the KGSL device struct for the GPU
 * @flags: Flags passed in from the user command
 * @cmdlist: Pointer to the list of commands from the user. Should point to a
 * kgsl_ibdesc_compat struct
 * @numcmds: Number of commands in the list
 * @synclist: Pointer to the list of syncpoints from the user. Should point to
 * a kgsl_cmd_syncpoint_compat struct
 * @numsyncs: Number of syncpoints in the list
 *
 * This function is called from _kgsl_cmdbatch_create(), if the user process
 * submitting cmds is 32 bit, instead of executing rest of the function.
 * It is needed since we do multiple copy_from_user() calls which would
 * otherwise be copying user data into the wrongly sized/structured struct.
 */
int kgsl_cmdbatch_create_compat(struct kgsl_device *device, unsigned int flags,
			struct kgsl_cmdbatch *cmdbatch, void __user *cmdlist,
			unsigned int numcmds, void __user *synclist,
			unsigned int numsyncs)
{
	int ret = 0;
	struct kgsl_ibdesc_compat *cmdbatch_ibdesc;

	if (!(flags & KGSL_CONTEXT_SYNC)) {
		if (copy_from_user(cmdbatch_ibdesc, cmdlist,
			sizeof(struct kgsl_ibdesc_compat) * numcmds))
			return -EFAULT;

		cmdbatch->ibdesc->gpuaddr = (unsigned long)
						cmdbatch_ibdesc->gpuaddr;
		cmdbatch->ibdesc->sizedwords = (size_t)
						cmdbatch_ibdesc->sizedwords;
		cmdbatch->ibdesc->ctrl = cmdbatch_ibdesc->ctrl;
	}
	if (synclist && numsyncs) {

		struct kgsl_cmd_syncpoint_compat sync32;
		struct kgsl_cmd_syncpoint sync;
		void __user *uptr = synclist;
		int i;

		for (i = 0; i < numsyncs; i++) {
			memset(&sync32, 0, sizeof(sync32));

			if (copy_from_user(&sync32, uptr, sizeof(sync32)))
				return -EFAULT;

			sync.type = sync32.type;
			sync.priv = compat_ptr(sync32.priv);
			sync.size = (size_t)sync32.size;

			ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync);
			if (ret)
				return ret;
			uptr += sizeof(sync32);
		}
	}
	return ret;
}
Loading