forked from mirrors/linux
		
	tee: generic TEE subsystem
Initial patch for generic TEE subsystem. This subsystem provides: * Registration/un-registration of TEE drivers. * Shared memory between normal world and secure world. * Ioctl interface for interaction with user space. * Sysfs implementation_id of TEE driver A TEE (Trusted Execution Environment) driver is a driver that interfaces with a trusted OS running in some secure environment, for example, TrustZone on ARM cpus, or a separate secure co-processor etc. The TEE subsystem can serve a TEE driver for a Global Platform compliant TEE, but it's not limited to only Global Platform TEEs. This patch builds on other similar implementations trying to solve the same problem: * "optee_linuxdriver" by among others Jean-michel DELORME<jean-michel.delorme@st.com> and Emmanuel MICHEL <emmanuel.michel@st.com> * "Generic TrustZone Driver" by Javier González <javier@javigon.com> Acked-by: Andreas Dannenberg <dannenberg@ti.com> Tested-by: Jerome Forissier <jerome.forissier@linaro.org> (HiKey) Tested-by: Volodymyr Babchuk <vlad.babchuk@gmail.com> (RCAR H3) Tested-by: Scott Branden <scott.branden@broadcom.com> Reviewed-by: Javier González <javier@javigon.com> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
This commit is contained in:
		
							parent
							
								
									c8bfafb159
								
							
						
					
					
						commit
						967c9cca2c
					
				
					 12 changed files with 2182 additions and 0 deletions
				
			
		|  | @ -308,6 +308,7 @@ Code  Seq#(hex)	Include File		Comments | ||||||
| 0xA3	80-8F	Port ACL		in development: | 0xA3	80-8F	Port ACL		in development: | ||||||
| 					<mailto:tlewis@mindspring.com> | 					<mailto:tlewis@mindspring.com> | ||||||
| 0xA3	90-9F	linux/dtlk.h | 0xA3	90-9F	linux/dtlk.h | ||||||
|  | 0xA4	00-1F	uapi/linux/tee.h	Generic TEE subsystem | ||||||
| 0xAA	00-3F	linux/uapi/linux/userfaultfd.h | 0xAA	00-3F	linux/uapi/linux/userfaultfd.h | ||||||
| 0xAB	00-1F	linux/nbd.h | 0xAB	00-1F	linux/nbd.h | ||||||
| 0xAC	00-1F	linux/raw.h | 0xAC	00-1F	linux/raw.h | ||||||
|  |  | ||||||
|  | @ -11086,6 +11086,13 @@ F:	drivers/hwtracing/stm/ | ||||||
| F:	include/linux/stm.h | F:	include/linux/stm.h | ||||||
| F:	include/uapi/linux/stm.h | F:	include/uapi/linux/stm.h | ||||||
| 
 | 
 | ||||||
|  | TEE SUBSYSTEM | ||||||
|  | M:	Jens Wiklander <jens.wiklander@linaro.org> | ||||||
|  | S:	Maintained | ||||||
|  | F:	include/linux/tee_drv.h | ||||||
|  | F:	include/uapi/linux/tee.h | ||||||
|  | F:	drivers/tee/ | ||||||
|  | 
 | ||||||
| THUNDERBOLT DRIVER | THUNDERBOLT DRIVER | ||||||
| M:	Andreas Noever <andreas.noever@gmail.com> | M:	Andreas Noever <andreas.noever@gmail.com> | ||||||
| S:	Maintained | S:	Maintained | ||||||
|  |  | ||||||
|  | @ -204,4 +204,6 @@ source "drivers/fpga/Kconfig" | ||||||
| 
 | 
 | ||||||
| source "drivers/fsi/Kconfig" | source "drivers/fsi/Kconfig" | ||||||
| 
 | 
 | ||||||
|  | source "drivers/tee/Kconfig" | ||||||
|  | 
 | ||||||
| endmenu | endmenu | ||||||
|  |  | ||||||
|  | @ -177,3 +177,4 @@ obj-$(CONFIG_ANDROID)		+= android/ | ||||||
| obj-$(CONFIG_NVMEM)		+= nvmem/ | obj-$(CONFIG_NVMEM)		+= nvmem/ | ||||||
| obj-$(CONFIG_FPGA)		+= fpga/ | obj-$(CONFIG_FPGA)		+= fpga/ | ||||||
| obj-$(CONFIG_FSI)		+= fsi/ | obj-$(CONFIG_FSI)		+= fsi/ | ||||||
|  | obj-$(CONFIG_TEE)		+= tee/ | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								drivers/tee/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								drivers/tee/Kconfig
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | # Generic Trusted Execution Environment Configuration | ||||||
|  | config TEE | ||||||
|  | 	tristate "Trusted Execution Environment support" | ||||||
|  | 	select DMA_SHARED_BUFFER | ||||||
|  | 	select GENERIC_ALLOCATOR | ||||||
|  | 	help | ||||||
|  | 	  This implements a generic interface towards a Trusted Execution | ||||||
|  | 	  Environment (TEE). | ||||||
							
								
								
									
										4
									
								
								drivers/tee/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								drivers/tee/Makefile
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | obj-$(CONFIG_TEE) += tee.o | ||||||
|  | tee-objs += tee_core.o | ||||||
|  | tee-objs += tee_shm.o | ||||||
|  | tee-objs += tee_shm_pool.o | ||||||
							
								
								
									
										893
									
								
								drivers/tee/tee_core.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										893
									
								
								drivers/tee/tee_core.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,893 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2015-2016, Linaro Limited | ||||||
|  |  * | ||||||
|  |  * This software is licensed under the terms of the GNU General Public | ||||||
|  |  * License version 2, as published by the Free Software Foundation, and | ||||||
|  |  * may be copied, distributed, and modified under those terms. | ||||||
|  |  * | ||||||
|  |  * 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. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||||||
|  | 
 | ||||||
|  | #include <linux/cdev.h> | ||||||
|  | #include <linux/device.h> | ||||||
|  | #include <linux/fs.h> | ||||||
|  | #include <linux/idr.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | #include <linux/tee_drv.h> | ||||||
|  | #include <linux/uaccess.h> | ||||||
|  | #include "tee_private.h" | ||||||
|  | 
 | ||||||
|  | #define TEE_NUM_DEVICES	32 | ||||||
|  | 
 | ||||||
|  | #define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x)) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Unprivileged devices in the lower half range and privileged devices in | ||||||
|  |  * the upper half range. | ||||||
|  |  */ | ||||||
|  | static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES); | ||||||
|  | static DEFINE_SPINLOCK(driver_lock); | ||||||
|  | 
 | ||||||
|  | static struct class *tee_class; | ||||||
|  | static dev_t tee_devt; | ||||||
|  | 
 | ||||||
|  | static int tee_open(struct inode *inode, struct file *filp) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  | 	struct tee_device *teedev; | ||||||
|  | 	struct tee_context *ctx; | ||||||
|  | 
 | ||||||
|  | 	teedev = container_of(inode->i_cdev, struct tee_device, cdev); | ||||||
|  | 	if (!tee_device_get(teedev)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||||||
|  | 	if (!ctx) { | ||||||
|  | 		rc = -ENOMEM; | ||||||
|  | 		goto err; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ctx->teedev = teedev; | ||||||
|  | 	INIT_LIST_HEAD(&ctx->list_shm); | ||||||
|  | 	filp->private_data = ctx; | ||||||
|  | 	rc = teedev->desc->ops->open(ctx); | ||||||
|  | 	if (rc) | ||||||
|  | 		goto err; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | err: | ||||||
|  | 	kfree(ctx); | ||||||
|  | 	tee_device_put(teedev); | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_release(struct inode *inode, struct file *filp) | ||||||
|  | { | ||||||
|  | 	struct tee_context *ctx = filp->private_data; | ||||||
|  | 	struct tee_device *teedev = ctx->teedev; | ||||||
|  | 	struct tee_shm *shm; | ||||||
|  | 
 | ||||||
|  | 	ctx->teedev->desc->ops->release(ctx); | ||||||
|  | 	mutex_lock(&ctx->teedev->mutex); | ||||||
|  | 	list_for_each_entry(shm, &ctx->list_shm, link) | ||||||
|  | 		shm->ctx = NULL; | ||||||
|  | 	mutex_unlock(&ctx->teedev->mutex); | ||||||
|  | 	kfree(ctx); | ||||||
|  | 	tee_device_put(teedev); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_ioctl_version(struct tee_context *ctx, | ||||||
|  | 			     struct tee_ioctl_version_data __user *uvers) | ||||||
|  | { | ||||||
|  | 	struct tee_ioctl_version_data vers; | ||||||
|  | 
 | ||||||
|  | 	ctx->teedev->desc->ops->get_version(ctx->teedev, &vers); | ||||||
|  | 	if (copy_to_user(uvers, &vers, sizeof(vers))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_ioctl_shm_alloc(struct tee_context *ctx, | ||||||
|  | 			       struct tee_ioctl_shm_alloc_data __user *udata) | ||||||
|  | { | ||||||
|  | 	long ret; | ||||||
|  | 	struct tee_ioctl_shm_alloc_data data; | ||||||
|  | 	struct tee_shm *shm; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_user(&data, udata, sizeof(data))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	/* Currently no input flags are supported */ | ||||||
|  | 	if (data.flags) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	data.id = -1; | ||||||
|  | 
 | ||||||
|  | 	shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); | ||||||
|  | 	if (IS_ERR(shm)) | ||||||
|  | 		return PTR_ERR(shm); | ||||||
|  | 
 | ||||||
|  | 	data.id = shm->id; | ||||||
|  | 	data.flags = shm->flags; | ||||||
|  | 	data.size = shm->size; | ||||||
|  | 
 | ||||||
|  | 	if (copy_to_user(udata, &data, sizeof(data))) | ||||||
|  | 		ret = -EFAULT; | ||||||
|  | 	else | ||||||
|  | 		ret = tee_shm_get_fd(shm); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * When user space closes the file descriptor the shared memory | ||||||
|  | 	 * should be freed or if tee_shm_get_fd() failed then it will | ||||||
|  | 	 * be freed immediately. | ||||||
|  | 	 */ | ||||||
|  | 	tee_shm_put(shm); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int params_from_user(struct tee_context *ctx, struct tee_param *params, | ||||||
|  | 			    size_t num_params, | ||||||
|  | 			    struct tee_ioctl_param __user *uparams) | ||||||
|  | { | ||||||
|  | 	size_t n; | ||||||
|  | 
 | ||||||
|  | 	for (n = 0; n < num_params; n++) { | ||||||
|  | 		struct tee_shm *shm; | ||||||
|  | 		struct tee_ioctl_param ip; | ||||||
|  | 
 | ||||||
|  | 		if (copy_from_user(&ip, uparams + n, sizeof(ip))) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 		/* All unused attribute bits has to be zero */ | ||||||
|  | 		if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) | ||||||
|  | 			return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 		params[n].attr = ip.attr; | ||||||
|  | 		switch (ip.attr) { | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: | ||||||
|  | 			break; | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | ||||||
|  | 			params[n].u.value.a = ip.a; | ||||||
|  | 			params[n].u.value.b = ip.b; | ||||||
|  | 			params[n].u.value.c = ip.c; | ||||||
|  | 			break; | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | ||||||
|  | 			/*
 | ||||||
|  | 			 * If we fail to get a pointer to a shared memory | ||||||
|  | 			 * object (and increase the ref count) from an | ||||||
|  | 			 * identifier we return an error. All pointers that | ||||||
|  | 			 * has been added in params have an increased ref | ||||||
|  | 			 * count. It's the callers responibility to do | ||||||
|  | 			 * tee_shm_put() on all resolved pointers. | ||||||
|  | 			 */ | ||||||
|  | 			shm = tee_shm_get_from_id(ctx, ip.c); | ||||||
|  | 			if (IS_ERR(shm)) | ||||||
|  | 				return PTR_ERR(shm); | ||||||
|  | 
 | ||||||
|  | 			params[n].u.memref.shm_offs = ip.a; | ||||||
|  | 			params[n].u.memref.size = ip.b; | ||||||
|  | 			params[n].u.memref.shm = shm; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			/* Unknown attribute */ | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int params_to_user(struct tee_ioctl_param __user *uparams, | ||||||
|  | 			  size_t num_params, struct tee_param *params) | ||||||
|  | { | ||||||
|  | 	size_t n; | ||||||
|  | 
 | ||||||
|  | 	for (n = 0; n < num_params; n++) { | ||||||
|  | 		struct tee_ioctl_param __user *up = uparams + n; | ||||||
|  | 		struct tee_param *p = params + n; | ||||||
|  | 
 | ||||||
|  | 		switch (p->attr) { | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | ||||||
|  | 			if (put_user(p->u.value.a, &up->a) || | ||||||
|  | 			    put_user(p->u.value.b, &up->b) || | ||||||
|  | 			    put_user(p->u.value.c, &up->c)) | ||||||
|  | 				return -EFAULT; | ||||||
|  | 			break; | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | ||||||
|  | 			if (put_user((u64)p->u.memref.size, &up->b)) | ||||||
|  | 				return -EFAULT; | ||||||
|  | 		default: | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool param_is_memref(struct tee_param *param) | ||||||
|  | { | ||||||
|  | 	switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { | ||||||
|  | 	case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: | ||||||
|  | 	case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | ||||||
|  | 	case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | ||||||
|  | 		return true; | ||||||
|  | 	default: | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_ioctl_open_session(struct tee_context *ctx, | ||||||
|  | 				  struct tee_ioctl_buf_data __user *ubuf) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  | 	size_t n; | ||||||
|  | 	struct tee_ioctl_buf_data buf; | ||||||
|  | 	struct tee_ioctl_open_session_arg __user *uarg; | ||||||
|  | 	struct tee_ioctl_open_session_arg arg; | ||||||
|  | 	struct tee_ioctl_param __user *uparams = NULL; | ||||||
|  | 	struct tee_param *params = NULL; | ||||||
|  | 	bool have_session = false; | ||||||
|  | 
 | ||||||
|  | 	if (!ctx->teedev->desc->ops->open_session) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_user(&buf, ubuf, sizeof(buf))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	if (buf.buf_len > TEE_MAX_ARG_SIZE || | ||||||
|  | 	    buf.buf_len < sizeof(struct tee_ioctl_open_session_arg)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	uarg = u64_to_user_ptr(buf.buf_ptr); | ||||||
|  | 	if (copy_from_user(&arg, uarg, sizeof(arg))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (arg.num_params) { | ||||||
|  | 		params = kcalloc(arg.num_params, sizeof(struct tee_param), | ||||||
|  | 				 GFP_KERNEL); | ||||||
|  | 		if (!params) | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		uparams = uarg->params; | ||||||
|  | 		rc = params_from_user(ctx, params, arg.num_params, uparams); | ||||||
|  | 		if (rc) | ||||||
|  | 			goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params); | ||||||
|  | 	if (rc) | ||||||
|  | 		goto out; | ||||||
|  | 	have_session = true; | ||||||
|  | 
 | ||||||
|  | 	if (put_user(arg.session, &uarg->session) || | ||||||
|  | 	    put_user(arg.ret, &uarg->ret) || | ||||||
|  | 	    put_user(arg.ret_origin, &uarg->ret_origin)) { | ||||||
|  | 		rc = -EFAULT; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	rc = params_to_user(uparams, arg.num_params, params); | ||||||
|  | out: | ||||||
|  | 	/*
 | ||||||
|  | 	 * If we've succeeded to open the session but failed to communicate | ||||||
|  | 	 * it back to user space, close the session again to avoid leakage. | ||||||
|  | 	 */ | ||||||
|  | 	if (rc && have_session && ctx->teedev->desc->ops->close_session) | ||||||
|  | 		ctx->teedev->desc->ops->close_session(ctx, arg.session); | ||||||
|  | 
 | ||||||
|  | 	if (params) { | ||||||
|  | 		/* Decrease ref count for all valid shared memory pointers */ | ||||||
|  | 		for (n = 0; n < arg.num_params; n++) | ||||||
|  | 			if (param_is_memref(params + n) && | ||||||
|  | 			    params[n].u.memref.shm) | ||||||
|  | 				tee_shm_put(params[n].u.memref.shm); | ||||||
|  | 		kfree(params); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_ioctl_invoke(struct tee_context *ctx, | ||||||
|  | 			    struct tee_ioctl_buf_data __user *ubuf) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  | 	size_t n; | ||||||
|  | 	struct tee_ioctl_buf_data buf; | ||||||
|  | 	struct tee_ioctl_invoke_arg __user *uarg; | ||||||
|  | 	struct tee_ioctl_invoke_arg arg; | ||||||
|  | 	struct tee_ioctl_param __user *uparams = NULL; | ||||||
|  | 	struct tee_param *params = NULL; | ||||||
|  | 
 | ||||||
|  | 	if (!ctx->teedev->desc->ops->invoke_func) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_user(&buf, ubuf, sizeof(buf))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	if (buf.buf_len > TEE_MAX_ARG_SIZE || | ||||||
|  | 	    buf.buf_len < sizeof(struct tee_ioctl_invoke_arg)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	uarg = u64_to_user_ptr(buf.buf_ptr); | ||||||
|  | 	if (copy_from_user(&arg, uarg, sizeof(arg))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (arg.num_params) { | ||||||
|  | 		params = kcalloc(arg.num_params, sizeof(struct tee_param), | ||||||
|  | 				 GFP_KERNEL); | ||||||
|  | 		if (!params) | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		uparams = uarg->params; | ||||||
|  | 		rc = params_from_user(ctx, params, arg.num_params, uparams); | ||||||
|  | 		if (rc) | ||||||
|  | 			goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params); | ||||||
|  | 	if (rc) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	if (put_user(arg.ret, &uarg->ret) || | ||||||
|  | 	    put_user(arg.ret_origin, &uarg->ret_origin)) { | ||||||
|  | 		rc = -EFAULT; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	rc = params_to_user(uparams, arg.num_params, params); | ||||||
|  | out: | ||||||
|  | 	if (params) { | ||||||
|  | 		/* Decrease ref count for all valid shared memory pointers */ | ||||||
|  | 		for (n = 0; n < arg.num_params; n++) | ||||||
|  | 			if (param_is_memref(params + n) && | ||||||
|  | 			    params[n].u.memref.shm) | ||||||
|  | 				tee_shm_put(params[n].u.memref.shm); | ||||||
|  | 		kfree(params); | ||||||
|  | 	} | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_ioctl_cancel(struct tee_context *ctx, | ||||||
|  | 			    struct tee_ioctl_cancel_arg __user *uarg) | ||||||
|  | { | ||||||
|  | 	struct tee_ioctl_cancel_arg arg; | ||||||
|  | 
 | ||||||
|  | 	if (!ctx->teedev->desc->ops->cancel_req) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_user(&arg, uarg, sizeof(arg))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	return ctx->teedev->desc->ops->cancel_req(ctx, arg.cancel_id, | ||||||
|  | 						  arg.session); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | tee_ioctl_close_session(struct tee_context *ctx, | ||||||
|  | 			struct tee_ioctl_close_session_arg __user *uarg) | ||||||
|  | { | ||||||
|  | 	struct tee_ioctl_close_session_arg arg; | ||||||
|  | 
 | ||||||
|  | 	if (!ctx->teedev->desc->ops->close_session) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_user(&arg, uarg, sizeof(arg))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	return ctx->teedev->desc->ops->close_session(ctx, arg.session); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int params_to_supp(struct tee_context *ctx, | ||||||
|  | 			  struct tee_ioctl_param __user *uparams, | ||||||
|  | 			  size_t num_params, struct tee_param *params) | ||||||
|  | { | ||||||
|  | 	size_t n; | ||||||
|  | 
 | ||||||
|  | 	for (n = 0; n < num_params; n++) { | ||||||
|  | 		struct tee_ioctl_param ip; | ||||||
|  | 		struct tee_param *p = params + n; | ||||||
|  | 
 | ||||||
|  | 		ip.attr = p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK; | ||||||
|  | 		switch (p->attr) { | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | ||||||
|  | 			ip.a = p->u.value.a; | ||||||
|  | 			ip.b = p->u.value.b; | ||||||
|  | 			ip.c = p->u.value.c; | ||||||
|  | 			break; | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | ||||||
|  | 			ip.b = p->u.memref.size; | ||||||
|  | 			if (!p->u.memref.shm) { | ||||||
|  | 				ip.a = 0; | ||||||
|  | 				ip.c = (u64)-1; /* invalid shm id */ | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			ip.a = p->u.memref.shm_offs; | ||||||
|  | 			ip.c = p->u.memref.shm->id; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			ip.a = 0; | ||||||
|  | 			ip.b = 0; | ||||||
|  | 			ip.c = 0; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (copy_to_user(uparams + n, &ip, sizeof(ip))) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_ioctl_supp_recv(struct tee_context *ctx, | ||||||
|  | 			       struct tee_ioctl_buf_data __user *ubuf) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  | 	struct tee_ioctl_buf_data buf; | ||||||
|  | 	struct tee_iocl_supp_recv_arg __user *uarg; | ||||||
|  | 	struct tee_param *params; | ||||||
|  | 	u32 num_params; | ||||||
|  | 	u32 func; | ||||||
|  | 
 | ||||||
|  | 	if (!ctx->teedev->desc->ops->supp_recv) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_user(&buf, ubuf, sizeof(buf))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	if (buf.buf_len > TEE_MAX_ARG_SIZE || | ||||||
|  | 	    buf.buf_len < sizeof(struct tee_iocl_supp_recv_arg)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	uarg = u64_to_user_ptr(buf.buf_ptr); | ||||||
|  | 	if (get_user(num_params, &uarg->num_params)) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); | ||||||
|  | 	if (!params) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params); | ||||||
|  | 	if (rc) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	if (put_user(func, &uarg->func) || | ||||||
|  | 	    put_user(num_params, &uarg->num_params)) { | ||||||
|  | 		rc = -EFAULT; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rc = params_to_supp(ctx, uarg->params, num_params, params); | ||||||
|  | out: | ||||||
|  | 	kfree(params); | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int params_from_supp(struct tee_param *params, size_t num_params, | ||||||
|  | 			    struct tee_ioctl_param __user *uparams) | ||||||
|  | { | ||||||
|  | 	size_t n; | ||||||
|  | 
 | ||||||
|  | 	for (n = 0; n < num_params; n++) { | ||||||
|  | 		struct tee_param *p = params + n; | ||||||
|  | 		struct tee_ioctl_param ip; | ||||||
|  | 
 | ||||||
|  | 		if (copy_from_user(&ip, uparams + n, sizeof(ip))) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 		/* All unused attribute bits has to be zero */ | ||||||
|  | 		if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK) | ||||||
|  | 			return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 		p->attr = ip.attr; | ||||||
|  | 		switch (ip.attr) { | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: | ||||||
|  | 			/* Only out and in/out values can be updated */ | ||||||
|  | 			p->u.value.a = ip.a; | ||||||
|  | 			p->u.value.b = ip.b; | ||||||
|  | 			p->u.value.c = ip.c; | ||||||
|  | 			break; | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: | ||||||
|  | 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: | ||||||
|  | 			/*
 | ||||||
|  | 			 * Only the size of the memref can be updated. | ||||||
|  | 			 * Since we don't have access to the original | ||||||
|  | 			 * parameters here, only store the supplied size. | ||||||
|  | 			 * The driver will copy the updated size into the | ||||||
|  | 			 * original parameters. | ||||||
|  | 			 */ | ||||||
|  | 			p->u.memref.shm = NULL; | ||||||
|  | 			p->u.memref.shm_offs = 0; | ||||||
|  | 			p->u.memref.size = ip.b; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			memset(&p->u, 0, sizeof(p->u)); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_ioctl_supp_send(struct tee_context *ctx, | ||||||
|  | 			       struct tee_ioctl_buf_data __user *ubuf) | ||||||
|  | { | ||||||
|  | 	long rc; | ||||||
|  | 	struct tee_ioctl_buf_data buf; | ||||||
|  | 	struct tee_iocl_supp_send_arg __user *uarg; | ||||||
|  | 	struct tee_param *params; | ||||||
|  | 	u32 num_params; | ||||||
|  | 	u32 ret; | ||||||
|  | 
 | ||||||
|  | 	/* Not valid for this driver */ | ||||||
|  | 	if (!ctx->teedev->desc->ops->supp_send) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_user(&buf, ubuf, sizeof(buf))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	if (buf.buf_len > TEE_MAX_ARG_SIZE || | ||||||
|  | 	    buf.buf_len < sizeof(struct tee_iocl_supp_send_arg)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	uarg = u64_to_user_ptr(buf.buf_ptr); | ||||||
|  | 	if (get_user(ret, &uarg->ret) || | ||||||
|  | 	    get_user(num_params, &uarg->num_params)) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL); | ||||||
|  | 	if (!params) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	rc = params_from_supp(params, num_params, uarg->params); | ||||||
|  | 	if (rc) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	rc = ctx->teedev->desc->ops->supp_send(ctx, ret, num_params, params); | ||||||
|  | out: | ||||||
|  | 	kfree(params); | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||||||
|  | { | ||||||
|  | 	struct tee_context *ctx = filp->private_data; | ||||||
|  | 	void __user *uarg = (void __user *)arg; | ||||||
|  | 
 | ||||||
|  | 	switch (cmd) { | ||||||
|  | 	case TEE_IOC_VERSION: | ||||||
|  | 		return tee_ioctl_version(ctx, uarg); | ||||||
|  | 	case TEE_IOC_SHM_ALLOC: | ||||||
|  | 		return tee_ioctl_shm_alloc(ctx, uarg); | ||||||
|  | 	case TEE_IOC_OPEN_SESSION: | ||||||
|  | 		return tee_ioctl_open_session(ctx, uarg); | ||||||
|  | 	case TEE_IOC_INVOKE: | ||||||
|  | 		return tee_ioctl_invoke(ctx, uarg); | ||||||
|  | 	case TEE_IOC_CANCEL: | ||||||
|  | 		return tee_ioctl_cancel(ctx, uarg); | ||||||
|  | 	case TEE_IOC_CLOSE_SESSION: | ||||||
|  | 		return tee_ioctl_close_session(ctx, uarg); | ||||||
|  | 	case TEE_IOC_SUPPL_RECV: | ||||||
|  | 		return tee_ioctl_supp_recv(ctx, uarg); | ||||||
|  | 	case TEE_IOC_SUPPL_SEND: | ||||||
|  | 		return tee_ioctl_supp_send(ctx, uarg); | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct file_operations tee_fops = { | ||||||
|  | 	.owner = THIS_MODULE, | ||||||
|  | 	.open = tee_open, | ||||||
|  | 	.release = tee_release, | ||||||
|  | 	.unlocked_ioctl = tee_ioctl, | ||||||
|  | 	.compat_ioctl = tee_ioctl, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void tee_release_device(struct device *dev) | ||||||
|  | { | ||||||
|  | 	struct tee_device *teedev = container_of(dev, struct tee_device, dev); | ||||||
|  | 
 | ||||||
|  | 	spin_lock(&driver_lock); | ||||||
|  | 	clear_bit(teedev->id, dev_mask); | ||||||
|  | 	spin_unlock(&driver_lock); | ||||||
|  | 	mutex_destroy(&teedev->mutex); | ||||||
|  | 	idr_destroy(&teedev->idr); | ||||||
|  | 	kfree(teedev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_device_alloc() - Allocate a new struct tee_device instance | ||||||
|  |  * @teedesc:	Descriptor for this driver | ||||||
|  |  * @dev:	Parent device for this device | ||||||
|  |  * @pool:	Shared memory pool, NULL if not used | ||||||
|  |  * @driver_data: Private driver data for this device | ||||||
|  |  * | ||||||
|  |  * Allocates a new struct tee_device instance. The device is | ||||||
|  |  * removed by tee_device_unregister(). | ||||||
|  |  * | ||||||
|  |  * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure | ||||||
|  |  */ | ||||||
|  | struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, | ||||||
|  | 				    struct device *dev, | ||||||
|  | 				    struct tee_shm_pool *pool, | ||||||
|  | 				    void *driver_data) | ||||||
|  | { | ||||||
|  | 	struct tee_device *teedev; | ||||||
|  | 	void *ret; | ||||||
|  | 	int rc; | ||||||
|  | 	int offs = 0; | ||||||
|  | 
 | ||||||
|  | 	if (!teedesc || !teedesc->name || !teedesc->ops || | ||||||
|  | 	    !teedesc->ops->get_version || !teedesc->ops->open || | ||||||
|  | 	    !teedesc->ops->release || !pool) | ||||||
|  | 		return ERR_PTR(-EINVAL); | ||||||
|  | 
 | ||||||
|  | 	teedev = kzalloc(sizeof(*teedev), GFP_KERNEL); | ||||||
|  | 	if (!teedev) { | ||||||
|  | 		ret = ERR_PTR(-ENOMEM); | ||||||
|  | 		goto err; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (teedesc->flags & TEE_DESC_PRIVILEGED) | ||||||
|  | 		offs = TEE_NUM_DEVICES / 2; | ||||||
|  | 
 | ||||||
|  | 	spin_lock(&driver_lock); | ||||||
|  | 	teedev->id = find_next_zero_bit(dev_mask, TEE_NUM_DEVICES, offs); | ||||||
|  | 	if (teedev->id < TEE_NUM_DEVICES) | ||||||
|  | 		set_bit(teedev->id, dev_mask); | ||||||
|  | 	spin_unlock(&driver_lock); | ||||||
|  | 
 | ||||||
|  | 	if (teedev->id >= TEE_NUM_DEVICES) { | ||||||
|  | 		ret = ERR_PTR(-ENOMEM); | ||||||
|  | 		goto err; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	snprintf(teedev->name, sizeof(teedev->name), "tee%s%d", | ||||||
|  | 		 teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "", | ||||||
|  | 		 teedev->id - offs); | ||||||
|  | 
 | ||||||
|  | 	teedev->dev.class = tee_class; | ||||||
|  | 	teedev->dev.release = tee_release_device; | ||||||
|  | 	teedev->dev.parent = dev; | ||||||
|  | 
 | ||||||
|  | 	teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id); | ||||||
|  | 
 | ||||||
|  | 	rc = dev_set_name(&teedev->dev, "%s", teedev->name); | ||||||
|  | 	if (rc) { | ||||||
|  | 		ret = ERR_PTR(rc); | ||||||
|  | 		goto err_devt; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cdev_init(&teedev->cdev, &tee_fops); | ||||||
|  | 	teedev->cdev.owner = teedesc->owner; | ||||||
|  | 	teedev->cdev.kobj.parent = &teedev->dev.kobj; | ||||||
|  | 
 | ||||||
|  | 	dev_set_drvdata(&teedev->dev, driver_data); | ||||||
|  | 	device_initialize(&teedev->dev); | ||||||
|  | 
 | ||||||
|  | 	/* 1 as tee_device_unregister() does one final tee_device_put() */ | ||||||
|  | 	teedev->num_users = 1; | ||||||
|  | 	init_completion(&teedev->c_no_users); | ||||||
|  | 	mutex_init(&teedev->mutex); | ||||||
|  | 	idr_init(&teedev->idr); | ||||||
|  | 
 | ||||||
|  | 	teedev->desc = teedesc; | ||||||
|  | 	teedev->pool = pool; | ||||||
|  | 
 | ||||||
|  | 	return teedev; | ||||||
|  | err_devt: | ||||||
|  | 	unregister_chrdev_region(teedev->dev.devt, 1); | ||||||
|  | err: | ||||||
|  | 	pr_err("could not register %s driver\n", | ||||||
|  | 	       teedesc->flags & TEE_DESC_PRIVILEGED ? "privileged" : "client"); | ||||||
|  | 	if (teedev && teedev->id < TEE_NUM_DEVICES) { | ||||||
|  | 		spin_lock(&driver_lock); | ||||||
|  | 		clear_bit(teedev->id, dev_mask); | ||||||
|  | 		spin_unlock(&driver_lock); | ||||||
|  | 	} | ||||||
|  | 	kfree(teedev); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_device_alloc); | ||||||
|  | 
 | ||||||
|  | static ssize_t implementation_id_show(struct device *dev, | ||||||
|  | 				      struct device_attribute *attr, char *buf) | ||||||
|  | { | ||||||
|  | 	struct tee_device *teedev = container_of(dev, struct tee_device, dev); | ||||||
|  | 	struct tee_ioctl_version_data vers; | ||||||
|  | 
 | ||||||
|  | 	teedev->desc->ops->get_version(teedev, &vers); | ||||||
|  | 	return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id); | ||||||
|  | } | ||||||
|  | static DEVICE_ATTR_RO(implementation_id); | ||||||
|  | 
 | ||||||
|  | static struct attribute *tee_dev_attrs[] = { | ||||||
|  | 	&dev_attr_implementation_id.attr, | ||||||
|  | 	NULL | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct attribute_group tee_dev_group = { | ||||||
|  | 	.attrs = tee_dev_attrs, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_device_register() - Registers a TEE device | ||||||
|  |  * @teedev:	Device to register | ||||||
|  |  * | ||||||
|  |  * tee_device_unregister() need to be called to remove the @teedev if | ||||||
|  |  * this function fails. | ||||||
|  |  * | ||||||
|  |  * @returns < 0 on failure | ||||||
|  |  */ | ||||||
|  | int tee_device_register(struct tee_device *teedev) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  | 
 | ||||||
|  | 	if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { | ||||||
|  | 		dev_err(&teedev->dev, "attempt to register twice\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1); | ||||||
|  | 	if (rc) { | ||||||
|  | 		dev_err(&teedev->dev, | ||||||
|  | 			"unable to cdev_add() %s, major %d, minor %d, err=%d\n", | ||||||
|  | 			teedev->name, MAJOR(teedev->dev.devt), | ||||||
|  | 			MINOR(teedev->dev.devt), rc); | ||||||
|  | 		return rc; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rc = device_add(&teedev->dev); | ||||||
|  | 	if (rc) { | ||||||
|  | 		dev_err(&teedev->dev, | ||||||
|  | 			"unable to device_add() %s, major %d, minor %d, err=%d\n", | ||||||
|  | 			teedev->name, MAJOR(teedev->dev.devt), | ||||||
|  | 			MINOR(teedev->dev.devt), rc); | ||||||
|  | 		goto err_device_add; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group); | ||||||
|  | 	if (rc) { | ||||||
|  | 		dev_err(&teedev->dev, | ||||||
|  | 			"failed to create sysfs attributes, err=%d\n", rc); | ||||||
|  | 		goto err_sysfs_create_group; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	teedev->flags |= TEE_DEVICE_FLAG_REGISTERED; | ||||||
|  | 	return 0; | ||||||
|  | 
 | ||||||
|  | err_sysfs_create_group: | ||||||
|  | 	device_del(&teedev->dev); | ||||||
|  | err_device_add: | ||||||
|  | 	cdev_del(&teedev->cdev); | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_device_register); | ||||||
|  | 
 | ||||||
|  | void tee_device_put(struct tee_device *teedev) | ||||||
|  | { | ||||||
|  | 	mutex_lock(&teedev->mutex); | ||||||
|  | 	/* Shouldn't put in this state */ | ||||||
|  | 	if (!WARN_ON(!teedev->desc)) { | ||||||
|  | 		teedev->num_users--; | ||||||
|  | 		if (!teedev->num_users) { | ||||||
|  | 			teedev->desc = NULL; | ||||||
|  | 			complete(&teedev->c_no_users); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	mutex_unlock(&teedev->mutex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool tee_device_get(struct tee_device *teedev) | ||||||
|  | { | ||||||
|  | 	mutex_lock(&teedev->mutex); | ||||||
|  | 	if (!teedev->desc) { | ||||||
|  | 		mutex_unlock(&teedev->mutex); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	teedev->num_users++; | ||||||
|  | 	mutex_unlock(&teedev->mutex); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_device_unregister() - Removes a TEE device | ||||||
|  |  * @teedev:	Device to unregister | ||||||
|  |  * | ||||||
|  |  * This function should be called to remove the @teedev even if | ||||||
|  |  * tee_device_register() hasn't been called yet. Does nothing if | ||||||
|  |  * @teedev is NULL. | ||||||
|  |  */ | ||||||
|  | void tee_device_unregister(struct tee_device *teedev) | ||||||
|  | { | ||||||
|  | 	if (!teedev) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { | ||||||
|  | 		sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group); | ||||||
|  | 		cdev_del(&teedev->cdev); | ||||||
|  | 		device_del(&teedev->dev); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	tee_device_put(teedev); | ||||||
|  | 	wait_for_completion(&teedev->c_no_users); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * No need to take a mutex any longer now since teedev->desc was | ||||||
|  | 	 * set to NULL before teedev->c_no_users was completed. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	teedev->pool = NULL; | ||||||
|  | 
 | ||||||
|  | 	put_device(&teedev->dev); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_device_unregister); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_get_drvdata() - Return driver_data pointer | ||||||
|  |  * @teedev:	Device containing the driver_data pointer | ||||||
|  |  * @returns the driver_data pointer supplied to tee_register(). | ||||||
|  |  */ | ||||||
|  | void *tee_get_drvdata(struct tee_device *teedev) | ||||||
|  | { | ||||||
|  | 	return dev_get_drvdata(&teedev->dev); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_get_drvdata); | ||||||
|  | 
 | ||||||
|  | static int __init tee_init(void) | ||||||
|  | { | ||||||
|  | 	int rc; | ||||||
|  | 
 | ||||||
|  | 	tee_class = class_create(THIS_MODULE, "tee"); | ||||||
|  | 	if (IS_ERR(tee_class)) { | ||||||
|  | 		pr_err("couldn't create class\n"); | ||||||
|  | 		return PTR_ERR(tee_class); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee"); | ||||||
|  | 	if (rc) { | ||||||
|  | 		pr_err("failed to allocate char dev region\n"); | ||||||
|  | 		class_destroy(tee_class); | ||||||
|  | 		tee_class = NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void __exit tee_exit(void) | ||||||
|  | { | ||||||
|  | 	class_destroy(tee_class); | ||||||
|  | 	tee_class = NULL; | ||||||
|  | 	unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | subsys_initcall(tee_init); | ||||||
|  | module_exit(tee_exit); | ||||||
|  | 
 | ||||||
|  | MODULE_AUTHOR("Linaro"); | ||||||
|  | MODULE_DESCRIPTION("TEE Driver"); | ||||||
|  | MODULE_VERSION("1.0"); | ||||||
|  | MODULE_LICENSE("GPL v2"); | ||||||
							
								
								
									
										129
									
								
								drivers/tee/tee_private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								drivers/tee/tee_private.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,129 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2015-2016, Linaro Limited | ||||||
|  |  * | ||||||
|  |  * This software is licensed under the terms of the GNU General Public | ||||||
|  |  * License version 2, as published by the Free Software Foundation, and | ||||||
|  |  * may be copied, distributed, and modified under those terms. | ||||||
|  |  * | ||||||
|  |  * 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. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | #ifndef TEE_PRIVATE_H | ||||||
|  | #define TEE_PRIVATE_H | ||||||
|  | 
 | ||||||
|  | #include <linux/cdev.h> | ||||||
|  | #include <linux/completion.h> | ||||||
|  | #include <linux/device.h> | ||||||
|  | #include <linux/kref.h> | ||||||
|  | #include <linux/mutex.h> | ||||||
|  | #include <linux/types.h> | ||||||
|  | 
 | ||||||
|  | struct tee_device; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_shm - shared memory object | ||||||
|  |  * @teedev:	device used to allocate the object | ||||||
|  |  * @ctx:	context using the object, if NULL the context is gone | ||||||
|  |  * @link	link element | ||||||
|  |  * @paddr:	physical address of the shared memory | ||||||
|  |  * @kaddr:	virtual address of the shared memory | ||||||
|  |  * @size:	size of shared memory | ||||||
|  |  * @dmabuf:	dmabuf used to for exporting to user space | ||||||
|  |  * @flags:	defined by TEE_SHM_* in tee_drv.h | ||||||
|  |  * @id:		unique id of a shared memory object on this device | ||||||
|  |  */ | ||||||
|  | struct tee_shm { | ||||||
|  | 	struct tee_device *teedev; | ||||||
|  | 	struct tee_context *ctx; | ||||||
|  | 	struct list_head link; | ||||||
|  | 	phys_addr_t paddr; | ||||||
|  | 	void *kaddr; | ||||||
|  | 	size_t size; | ||||||
|  | 	struct dma_buf *dmabuf; | ||||||
|  | 	u32 flags; | ||||||
|  | 	int id; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct tee_shm_pool_mgr; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_shm_pool_mgr_ops - shared memory pool manager operations | ||||||
|  |  * @alloc:	called when allocating shared memory | ||||||
|  |  * @free:	called when freeing shared memory | ||||||
|  |  */ | ||||||
|  | struct tee_shm_pool_mgr_ops { | ||||||
|  | 	int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm, | ||||||
|  | 		     size_t size); | ||||||
|  | 	void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_shm_pool_mgr - shared memory manager | ||||||
|  |  * @ops:		operations | ||||||
|  |  * @private_data:	private data for the shared memory manager | ||||||
|  |  */ | ||||||
|  | struct tee_shm_pool_mgr { | ||||||
|  | 	const struct tee_shm_pool_mgr_ops *ops; | ||||||
|  | 	void *private_data; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_shm_pool - shared memory pool | ||||||
|  |  * @private_mgr:	pool manager for shared memory only between kernel | ||||||
|  |  *			and secure world | ||||||
|  |  * @dma_buf_mgr:	pool manager for shared memory exported to user space | ||||||
|  |  * @destroy:		called when destroying the pool | ||||||
|  |  * @private_data:	private data for the pool | ||||||
|  |  */ | ||||||
|  | struct tee_shm_pool { | ||||||
|  | 	struct tee_shm_pool_mgr private_mgr; | ||||||
|  | 	struct tee_shm_pool_mgr dma_buf_mgr; | ||||||
|  | 	void (*destroy)(struct tee_shm_pool *pool); | ||||||
|  | 	void *private_data; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define TEE_DEVICE_FLAG_REGISTERED	0x1 | ||||||
|  | #define TEE_MAX_DEV_NAME_LEN		32 | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_device - TEE Device representation | ||||||
|  |  * @name:	name of device | ||||||
|  |  * @desc:	description of device | ||||||
|  |  * @id:		unique id of device | ||||||
|  |  * @flags:	represented by TEE_DEVICE_FLAG_REGISTERED above | ||||||
|  |  * @dev:	embedded basic device structure | ||||||
|  |  * @cdev:	embedded cdev | ||||||
|  |  * @num_users:	number of active users of this device | ||||||
|  |  * @c_no_user:	completion used when unregistering the device | ||||||
|  |  * @mutex:	mutex protecting @num_users and @idr | ||||||
|  |  * @idr:	register of shared memory object allocated on this device | ||||||
|  |  * @pool:	shared memory pool | ||||||
|  |  */ | ||||||
|  | struct tee_device { | ||||||
|  | 	char name[TEE_MAX_DEV_NAME_LEN]; | ||||||
|  | 	const struct tee_desc *desc; | ||||||
|  | 	int id; | ||||||
|  | 	unsigned int flags; | ||||||
|  | 
 | ||||||
|  | 	struct device dev; | ||||||
|  | 	struct cdev cdev; | ||||||
|  | 
 | ||||||
|  | 	size_t num_users; | ||||||
|  | 	struct completion c_no_users; | ||||||
|  | 	struct mutex mutex;	/* protects num_users and idr */ | ||||||
|  | 
 | ||||||
|  | 	struct idr idr; | ||||||
|  | 	struct tee_shm_pool *pool; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | int tee_shm_init(void); | ||||||
|  | 
 | ||||||
|  | int tee_shm_get_fd(struct tee_shm *shm); | ||||||
|  | 
 | ||||||
|  | bool tee_device_get(struct tee_device *teedev); | ||||||
|  | void tee_device_put(struct tee_device *teedev); | ||||||
|  | 
 | ||||||
|  | #endif /*TEE_PRIVATE_H*/ | ||||||
							
								
								
									
										358
									
								
								drivers/tee/tee_shm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								drivers/tee/tee_shm.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,358 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2015-2016, Linaro Limited | ||||||
|  |  * | ||||||
|  |  * This software is licensed under the terms of the GNU General Public | ||||||
|  |  * License version 2, as published by the Free Software Foundation, and | ||||||
|  |  * may be copied, distributed, and modified under those terms. | ||||||
|  |  * | ||||||
|  |  * 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/device.h> | ||||||
|  | #include <linux/dma-buf.h> | ||||||
|  | #include <linux/fdtable.h> | ||||||
|  | #include <linux/idr.h> | ||||||
|  | #include <linux/sched.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | #include <linux/tee_drv.h> | ||||||
|  | #include "tee_private.h" | ||||||
|  | 
 | ||||||
|  | static void tee_shm_release(struct tee_shm *shm) | ||||||
|  | { | ||||||
|  | 	struct tee_device *teedev = shm->teedev; | ||||||
|  | 	struct tee_shm_pool_mgr *poolm; | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&teedev->mutex); | ||||||
|  | 	idr_remove(&teedev->idr, shm->id); | ||||||
|  | 	if (shm->ctx) | ||||||
|  | 		list_del(&shm->link); | ||||||
|  | 	mutex_unlock(&teedev->mutex); | ||||||
|  | 
 | ||||||
|  | 	if (shm->flags & TEE_SHM_DMA_BUF) | ||||||
|  | 		poolm = &teedev->pool->dma_buf_mgr; | ||||||
|  | 	else | ||||||
|  | 		poolm = &teedev->pool->private_mgr; | ||||||
|  | 
 | ||||||
|  | 	poolm->ops->free(poolm, shm); | ||||||
|  | 	kfree(shm); | ||||||
|  | 
 | ||||||
|  | 	tee_device_put(teedev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment | ||||||
|  | 			*attach, enum dma_data_direction dir) | ||||||
|  | { | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach, | ||||||
|  | 				     struct sg_table *table, | ||||||
|  | 				     enum dma_data_direction dir) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void tee_shm_op_release(struct dma_buf *dmabuf) | ||||||
|  | { | ||||||
|  | 	struct tee_shm *shm = dmabuf->priv; | ||||||
|  | 
 | ||||||
|  | 	tee_shm_release(shm); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void *tee_shm_op_kmap_atomic(struct dma_buf *dmabuf, unsigned long pgnum) | ||||||
|  | { | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void *tee_shm_op_kmap(struct dma_buf *dmabuf, unsigned long pgnum) | ||||||
|  | { | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) | ||||||
|  | { | ||||||
|  | 	struct tee_shm *shm = dmabuf->priv; | ||||||
|  | 	size_t size = vma->vm_end - vma->vm_start; | ||||||
|  | 
 | ||||||
|  | 	return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, | ||||||
|  | 			       size, vma->vm_page_prot); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct dma_buf_ops tee_shm_dma_buf_ops = { | ||||||
|  | 	.map_dma_buf = tee_shm_op_map_dma_buf, | ||||||
|  | 	.unmap_dma_buf = tee_shm_op_unmap_dma_buf, | ||||||
|  | 	.release = tee_shm_op_release, | ||||||
|  | 	.kmap_atomic = tee_shm_op_kmap_atomic, | ||||||
|  | 	.kmap = tee_shm_op_kmap, | ||||||
|  | 	.mmap = tee_shm_op_mmap, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_alloc() - Allocate shared memory | ||||||
|  |  * @ctx:	Context that allocates the shared memory | ||||||
|  |  * @size:	Requested size of shared memory | ||||||
|  |  * @flags:	Flags setting properties for the requested shared memory. | ||||||
|  |  * | ||||||
|  |  * Memory allocated as global shared memory is automatically freed when the | ||||||
|  |  * TEE file pointer is closed. The @flags field uses the bits defined by | ||||||
|  |  * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be | ||||||
|  |  * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and | ||||||
|  |  * associated with a dma-buf handle, else driver private memory. | ||||||
|  |  */ | ||||||
|  | struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) | ||||||
|  | { | ||||||
|  | 	struct tee_device *teedev = ctx->teedev; | ||||||
|  | 	struct tee_shm_pool_mgr *poolm = NULL; | ||||||
|  | 	struct tee_shm *shm; | ||||||
|  | 	void *ret; | ||||||
|  | 	int rc; | ||||||
|  | 
 | ||||||
|  | 	if (!(flags & TEE_SHM_MAPPED)) { | ||||||
|  | 		dev_err(teedev->dev.parent, | ||||||
|  | 			"only mapped allocations supported\n"); | ||||||
|  | 		return ERR_PTR(-EINVAL); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) { | ||||||
|  | 		dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags); | ||||||
|  | 		return ERR_PTR(-EINVAL); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!tee_device_get(teedev)) | ||||||
|  | 		return ERR_PTR(-EINVAL); | ||||||
|  | 
 | ||||||
|  | 	if (!teedev->pool) { | ||||||
|  | 		/* teedev has been detached from driver */ | ||||||
|  | 		ret = ERR_PTR(-EINVAL); | ||||||
|  | 		goto err_dev_put; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	shm = kzalloc(sizeof(*shm), GFP_KERNEL); | ||||||
|  | 	if (!shm) { | ||||||
|  | 		ret = ERR_PTR(-ENOMEM); | ||||||
|  | 		goto err_dev_put; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	shm->flags = flags; | ||||||
|  | 	shm->teedev = teedev; | ||||||
|  | 	shm->ctx = ctx; | ||||||
|  | 	if (flags & TEE_SHM_DMA_BUF) | ||||||
|  | 		poolm = &teedev->pool->dma_buf_mgr; | ||||||
|  | 	else | ||||||
|  | 		poolm = &teedev->pool->private_mgr; | ||||||
|  | 
 | ||||||
|  | 	rc = poolm->ops->alloc(poolm, shm, size); | ||||||
|  | 	if (rc) { | ||||||
|  | 		ret = ERR_PTR(rc); | ||||||
|  | 		goto err_kfree; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&teedev->mutex); | ||||||
|  | 	shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL); | ||||||
|  | 	mutex_unlock(&teedev->mutex); | ||||||
|  | 	if (shm->id < 0) { | ||||||
|  | 		ret = ERR_PTR(shm->id); | ||||||
|  | 		goto err_pool_free; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (flags & TEE_SHM_DMA_BUF) { | ||||||
|  | 		DEFINE_DMA_BUF_EXPORT_INFO(exp_info); | ||||||
|  | 
 | ||||||
|  | 		exp_info.ops = &tee_shm_dma_buf_ops; | ||||||
|  | 		exp_info.size = shm->size; | ||||||
|  | 		exp_info.flags = O_RDWR; | ||||||
|  | 		exp_info.priv = shm; | ||||||
|  | 
 | ||||||
|  | 		shm->dmabuf = dma_buf_export(&exp_info); | ||||||
|  | 		if (IS_ERR(shm->dmabuf)) { | ||||||
|  | 			ret = ERR_CAST(shm->dmabuf); | ||||||
|  | 			goto err_rem; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	mutex_lock(&teedev->mutex); | ||||||
|  | 	list_add_tail(&shm->link, &ctx->list_shm); | ||||||
|  | 	mutex_unlock(&teedev->mutex); | ||||||
|  | 
 | ||||||
|  | 	return shm; | ||||||
|  | err_rem: | ||||||
|  | 	mutex_lock(&teedev->mutex); | ||||||
|  | 	idr_remove(&teedev->idr, shm->id); | ||||||
|  | 	mutex_unlock(&teedev->mutex); | ||||||
|  | err_pool_free: | ||||||
|  | 	poolm->ops->free(poolm, shm); | ||||||
|  | err_kfree: | ||||||
|  | 	kfree(shm); | ||||||
|  | err_dev_put: | ||||||
|  | 	tee_device_put(teedev); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_alloc); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_fd() - Increase reference count and return file descriptor | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @returns user space file descriptor to shared memory | ||||||
|  |  */ | ||||||
|  | int tee_shm_get_fd(struct tee_shm *shm) | ||||||
|  | { | ||||||
|  | 	u32 req_flags = TEE_SHM_MAPPED | TEE_SHM_DMA_BUF; | ||||||
|  | 	int fd; | ||||||
|  | 
 | ||||||
|  | 	if ((shm->flags & req_flags) != req_flags) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC); | ||||||
|  | 	if (fd >= 0) | ||||||
|  | 		get_dma_buf(shm->dmabuf); | ||||||
|  | 	return fd; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_free() - Free shared memory | ||||||
|  |  * @shm:	Handle to shared memory to free | ||||||
|  |  */ | ||||||
|  | void tee_shm_free(struct tee_shm *shm) | ||||||
|  | { | ||||||
|  | 	/*
 | ||||||
|  | 	 * dma_buf_put() decreases the dmabuf reference counter and will | ||||||
|  | 	 * call tee_shm_release() when the last reference is gone. | ||||||
|  | 	 * | ||||||
|  | 	 * In the case of driver private memory we call tee_shm_release | ||||||
|  | 	 * directly instead as it doesn't have a reference counter. | ||||||
|  | 	 */ | ||||||
|  | 	if (shm->flags & TEE_SHM_DMA_BUF) | ||||||
|  | 		dma_buf_put(shm->dmabuf); | ||||||
|  | 	else | ||||||
|  | 		tee_shm_release(shm); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_free); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_va2pa() - Get physical address of a virtual address | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @va:		Virtual address to tranlsate | ||||||
|  |  * @pa:		Returned physical address | ||||||
|  |  * @returns 0 on success and < 0 on failure | ||||||
|  |  */ | ||||||
|  | int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa) | ||||||
|  | { | ||||||
|  | 	/* Check that we're in the range of the shm */ | ||||||
|  | 	if ((char *)va < (char *)shm->kaddr) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	if ((char *)va >= ((char *)shm->kaddr + shm->size)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	return tee_shm_get_pa( | ||||||
|  | 			shm, (unsigned long)va - (unsigned long)shm->kaddr, pa); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_va2pa); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_pa2va() - Get virtual address of a physical address | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @pa:		Physical address to tranlsate | ||||||
|  |  * @va:		Returned virtual address | ||||||
|  |  * @returns 0 on success and < 0 on failure | ||||||
|  |  */ | ||||||
|  | int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va) | ||||||
|  | { | ||||||
|  | 	/* Check that we're in the range of the shm */ | ||||||
|  | 	if (pa < shm->paddr) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	if (pa >= (shm->paddr + shm->size)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (va) { | ||||||
|  | 		void *v = tee_shm_get_va(shm, pa - shm->paddr); | ||||||
|  | 
 | ||||||
|  | 		if (IS_ERR(v)) | ||||||
|  | 			return PTR_ERR(v); | ||||||
|  | 		*va = v; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_pa2va); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_va() - Get virtual address of a shared memory plus an offset | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @offs:	Offset from start of this shared memory | ||||||
|  |  * @returns virtual address of the shared memory + offs if offs is within | ||||||
|  |  *	the bounds of this shared memory, else an ERR_PTR | ||||||
|  |  */ | ||||||
|  | void *tee_shm_get_va(struct tee_shm *shm, size_t offs) | ||||||
|  | { | ||||||
|  | 	if (offs >= shm->size) | ||||||
|  | 		return ERR_PTR(-EINVAL); | ||||||
|  | 	return (char *)shm->kaddr + offs; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_get_va); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_pa() - Get physical address of a shared memory plus an offset | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @offs:	Offset from start of this shared memory | ||||||
|  |  * @pa:		Physical address to return | ||||||
|  |  * @returns 0 if offs is within the bounds of this shared memory, else an | ||||||
|  |  *	error code. | ||||||
|  |  */ | ||||||
|  | int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa) | ||||||
|  | { | ||||||
|  | 	if (offs >= shm->size) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	if (pa) | ||||||
|  | 		*pa = shm->paddr + offs; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_get_pa); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_from_id() - Find shared memory object and increase reference | ||||||
|  |  * count | ||||||
|  |  * @ctx:	Context owning the shared memory | ||||||
|  |  * @id:		Id of shared memory object | ||||||
|  |  * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure | ||||||
|  |  */ | ||||||
|  | struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id) | ||||||
|  | { | ||||||
|  | 	struct tee_device *teedev; | ||||||
|  | 	struct tee_shm *shm; | ||||||
|  | 
 | ||||||
|  | 	if (!ctx) | ||||||
|  | 		return ERR_PTR(-EINVAL); | ||||||
|  | 
 | ||||||
|  | 	teedev = ctx->teedev; | ||||||
|  | 	mutex_lock(&teedev->mutex); | ||||||
|  | 	shm = idr_find(&teedev->idr, id); | ||||||
|  | 	if (!shm || shm->ctx != ctx) | ||||||
|  | 		shm = ERR_PTR(-EINVAL); | ||||||
|  | 	else if (shm->flags & TEE_SHM_DMA_BUF) | ||||||
|  | 		get_dma_buf(shm->dmabuf); | ||||||
|  | 	mutex_unlock(&teedev->mutex); | ||||||
|  | 	return shm; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_get_from_id); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_id() - Get id of a shared memory object | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @returns id | ||||||
|  |  */ | ||||||
|  | int tee_shm_get_id(struct tee_shm *shm) | ||||||
|  | { | ||||||
|  | 	return shm->id; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_get_id); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_put() - Decrease reference count on a shared memory handle | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  */ | ||||||
|  | void tee_shm_put(struct tee_shm *shm) | ||||||
|  | { | ||||||
|  | 	if (shm->flags & TEE_SHM_DMA_BUF) | ||||||
|  | 		dma_buf_put(shm->dmabuf); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_put); | ||||||
							
								
								
									
										156
									
								
								drivers/tee/tee_shm_pool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								drivers/tee/tee_shm_pool.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,156 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2015, Linaro Limited | ||||||
|  |  * | ||||||
|  |  * This software is licensed under the terms of the GNU General Public | ||||||
|  |  * License version 2, as published by the Free Software Foundation, and | ||||||
|  |  * may be copied, distributed, and modified under those terms. | ||||||
|  |  * | ||||||
|  |  * 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/device.h> | ||||||
|  | #include <linux/dma-buf.h> | ||||||
|  | #include <linux/genalloc.h> | ||||||
|  | #include <linux/slab.h> | ||||||
|  | #include <linux/tee_drv.h> | ||||||
|  | #include "tee_private.h" | ||||||
|  | 
 | ||||||
|  | static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm, | ||||||
|  | 			     struct tee_shm *shm, size_t size) | ||||||
|  | { | ||||||
|  | 	unsigned long va; | ||||||
|  | 	struct gen_pool *genpool = poolm->private_data; | ||||||
|  | 	size_t s = roundup(size, 1 << genpool->min_alloc_order); | ||||||
|  | 
 | ||||||
|  | 	va = gen_pool_alloc(genpool, s); | ||||||
|  | 	if (!va) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	memset((void *)va, 0, s); | ||||||
|  | 	shm->kaddr = (void *)va; | ||||||
|  | 	shm->paddr = gen_pool_virt_to_phys(genpool, va); | ||||||
|  | 	shm->size = s; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm, | ||||||
|  | 			     struct tee_shm *shm) | ||||||
|  | { | ||||||
|  | 	gen_pool_free(poolm->private_data, (unsigned long)shm->kaddr, | ||||||
|  | 		      shm->size); | ||||||
|  | 	shm->kaddr = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct tee_shm_pool_mgr_ops pool_ops_generic = { | ||||||
|  | 	.alloc = pool_op_gen_alloc, | ||||||
|  | 	.free = pool_op_gen_free, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void pool_res_mem_destroy(struct tee_shm_pool *pool) | ||||||
|  | { | ||||||
|  | 	gen_pool_destroy(pool->private_mgr.private_data); | ||||||
|  | 	gen_pool_destroy(pool->dma_buf_mgr.private_data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr, | ||||||
|  | 				 struct tee_shm_pool_mem_info *info, | ||||||
|  | 				 int min_alloc_order) | ||||||
|  | { | ||||||
|  | 	size_t page_mask = PAGE_SIZE - 1; | ||||||
|  | 	struct gen_pool *genpool = NULL; | ||||||
|  | 	int rc; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Start and end must be page aligned | ||||||
|  | 	 */ | ||||||
|  | 	if ((info->vaddr & page_mask) || (info->paddr & page_mask) || | ||||||
|  | 	    (info->size & page_mask)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	genpool = gen_pool_create(min_alloc_order, -1); | ||||||
|  | 	if (!genpool) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	gen_pool_set_algo(genpool, gen_pool_best_fit, NULL); | ||||||
|  | 	rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size, | ||||||
|  | 			       -1); | ||||||
|  | 	if (rc) { | ||||||
|  | 		gen_pool_destroy(genpool); | ||||||
|  | 		return rc; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mgr->private_data = genpool; | ||||||
|  | 	mgr->ops = &pool_ops_generic; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved | ||||||
|  |  * memory range | ||||||
|  |  * @priv_info:	Information for driver private shared memory pool | ||||||
|  |  * @dmabuf_info: Information for dma-buf shared memory pool | ||||||
|  |  * | ||||||
|  |  * Start and end of pools will must be page aligned. | ||||||
|  |  * | ||||||
|  |  * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied | ||||||
|  |  * in @dmabuf, others will use the range provided by @priv. | ||||||
|  |  * | ||||||
|  |  * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure. | ||||||
|  |  */ | ||||||
|  | struct tee_shm_pool * | ||||||
|  | tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info, | ||||||
|  | 			   struct tee_shm_pool_mem_info *dmabuf_info) | ||||||
|  | { | ||||||
|  | 	struct tee_shm_pool *pool = NULL; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	pool = kzalloc(sizeof(*pool), GFP_KERNEL); | ||||||
|  | 	if (!pool) { | ||||||
|  | 		ret = -ENOMEM; | ||||||
|  | 		goto err; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Create the pool for driver private shared memory | ||||||
|  | 	 */ | ||||||
|  | 	ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info, | ||||||
|  | 				    3 /* 8 byte aligned */); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto err; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Create the pool for dma_buf shared memory | ||||||
|  | 	 */ | ||||||
|  | 	ret = pool_res_mem_mgr_init(&pool->dma_buf_mgr, dmabuf_info, | ||||||
|  | 				    PAGE_SHIFT); | ||||||
|  | 	if (ret) | ||||||
|  | 		goto err; | ||||||
|  | 
 | ||||||
|  | 	pool->destroy = pool_res_mem_destroy; | ||||||
|  | 	return pool; | ||||||
|  | err: | ||||||
|  | 	if (ret == -ENOMEM) | ||||||
|  | 		pr_err("%s: can't allocate memory for res_mem shared memory pool\n", __func__); | ||||||
|  | 	if (pool && pool->private_mgr.private_data) | ||||||
|  | 		gen_pool_destroy(pool->private_mgr.private_data); | ||||||
|  | 	kfree(pool); | ||||||
|  | 	return ERR_PTR(ret); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_pool_free() - Free a shared memory pool | ||||||
|  |  * @pool:	The shared memory pool to free | ||||||
|  |  * | ||||||
|  |  * There must be no remaining shared memory allocated from this pool when | ||||||
|  |  * this function is called. | ||||||
|  |  */ | ||||||
|  | void tee_shm_pool_free(struct tee_shm_pool *pool) | ||||||
|  | { | ||||||
|  | 	pool->destroy(pool); | ||||||
|  | 	kfree(pool); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(tee_shm_pool_free); | ||||||
							
								
								
									
										277
									
								
								include/linux/tee_drv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								include/linux/tee_drv.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,277 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2015-2016, Linaro Limited | ||||||
|  |  * | ||||||
|  |  * This software is licensed under the terms of the GNU General Public | ||||||
|  |  * License version 2, as published by the Free Software Foundation, and | ||||||
|  |  * may be copied, distributed, and modified under those terms. | ||||||
|  |  * | ||||||
|  |  * 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. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __TEE_DRV_H | ||||||
|  | #define __TEE_DRV_H | ||||||
|  | 
 | ||||||
|  | #include <linux/types.h> | ||||||
|  | #include <linux/idr.h> | ||||||
|  | #include <linux/list.h> | ||||||
|  | #include <linux/tee.h> | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * The file describes the API provided by the generic TEE driver to the | ||||||
|  |  * specific TEE driver. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define TEE_SHM_MAPPED		0x1	/* Memory mapped by the kernel */ | ||||||
|  | #define TEE_SHM_DMA_BUF		0x2	/* Memory with dma-buf handle */ | ||||||
|  | 
 | ||||||
|  | struct tee_device; | ||||||
|  | struct tee_shm; | ||||||
|  | struct tee_shm_pool; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_context - driver specific context on file pointer data | ||||||
|  |  * @teedev:	pointer to this drivers struct tee_device | ||||||
|  |  * @list_shm:	List of shared memory object owned by this context | ||||||
|  |  * @data:	driver specific context data, managed by the driver | ||||||
|  |  */ | ||||||
|  | struct tee_context { | ||||||
|  | 	struct tee_device *teedev; | ||||||
|  | 	struct list_head list_shm; | ||||||
|  | 	void *data; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct tee_param_memref { | ||||||
|  | 	size_t shm_offs; | ||||||
|  | 	size_t size; | ||||||
|  | 	struct tee_shm *shm; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct tee_param_value { | ||||||
|  | 	u64 a; | ||||||
|  | 	u64 b; | ||||||
|  | 	u64 c; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct tee_param { | ||||||
|  | 	u64 attr; | ||||||
|  | 	union { | ||||||
|  | 		struct tee_param_memref memref; | ||||||
|  | 		struct tee_param_value value; | ||||||
|  | 	} u; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_driver_ops - driver operations vtable | ||||||
|  |  * @get_version:	returns version of driver | ||||||
|  |  * @open:		called when the device file is opened | ||||||
|  |  * @release:		release this open file | ||||||
|  |  * @open_session:	open a new session | ||||||
|  |  * @close_session:	close a session | ||||||
|  |  * @invoke_func:	invoke a trusted function | ||||||
|  |  * @cancel_req:		request cancel of an ongoing invoke or open | ||||||
|  |  * @supp_revc:		called for supplicant to get a command | ||||||
|  |  * @supp_send:		called for supplicant to send a response | ||||||
|  |  */ | ||||||
|  | struct tee_driver_ops { | ||||||
|  | 	void (*get_version)(struct tee_device *teedev, | ||||||
|  | 			    struct tee_ioctl_version_data *vers); | ||||||
|  | 	int (*open)(struct tee_context *ctx); | ||||||
|  | 	void (*release)(struct tee_context *ctx); | ||||||
|  | 	int (*open_session)(struct tee_context *ctx, | ||||||
|  | 			    struct tee_ioctl_open_session_arg *arg, | ||||||
|  | 			    struct tee_param *param); | ||||||
|  | 	int (*close_session)(struct tee_context *ctx, u32 session); | ||||||
|  | 	int (*invoke_func)(struct tee_context *ctx, | ||||||
|  | 			   struct tee_ioctl_invoke_arg *arg, | ||||||
|  | 			   struct tee_param *param); | ||||||
|  | 	int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session); | ||||||
|  | 	int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params, | ||||||
|  | 			 struct tee_param *param); | ||||||
|  | 	int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params, | ||||||
|  | 			 struct tee_param *param); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_desc - Describes the TEE driver to the subsystem | ||||||
|  |  * @name:	name of driver | ||||||
|  |  * @ops:	driver operations vtable | ||||||
|  |  * @owner:	module providing the driver | ||||||
|  |  * @flags:	Extra properties of driver, defined by TEE_DESC_* below | ||||||
|  |  */ | ||||||
|  | #define TEE_DESC_PRIVILEGED	0x1 | ||||||
|  | struct tee_desc { | ||||||
|  | 	const char *name; | ||||||
|  | 	const struct tee_driver_ops *ops; | ||||||
|  | 	struct module *owner; | ||||||
|  | 	u32 flags; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_device_alloc() - Allocate a new struct tee_device instance | ||||||
|  |  * @teedesc:	Descriptor for this driver | ||||||
|  |  * @dev:	Parent device for this device | ||||||
|  |  * @pool:	Shared memory pool, NULL if not used | ||||||
|  |  * @driver_data: Private driver data for this device | ||||||
|  |  * | ||||||
|  |  * Allocates a new struct tee_device instance. The device is | ||||||
|  |  * removed by tee_device_unregister(). | ||||||
|  |  * | ||||||
|  |  * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure | ||||||
|  |  */ | ||||||
|  | struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, | ||||||
|  | 				    struct device *dev, | ||||||
|  | 				    struct tee_shm_pool *pool, | ||||||
|  | 				    void *driver_data); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_device_register() - Registers a TEE device | ||||||
|  |  * @teedev:	Device to register | ||||||
|  |  * | ||||||
|  |  * tee_device_unregister() need to be called to remove the @teedev if | ||||||
|  |  * this function fails. | ||||||
|  |  * | ||||||
|  |  * @returns < 0 on failure | ||||||
|  |  */ | ||||||
|  | int tee_device_register(struct tee_device *teedev); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_device_unregister() - Removes a TEE device | ||||||
|  |  * @teedev:	Device to unregister | ||||||
|  |  * | ||||||
|  |  * This function should be called to remove the @teedev even if | ||||||
|  |  * tee_device_register() hasn't been called yet. Does nothing if | ||||||
|  |  * @teedev is NULL. | ||||||
|  |  */ | ||||||
|  | void tee_device_unregister(struct tee_device *teedev); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_shm_pool_mem_info - holds information needed to create a shared | ||||||
|  |  * memory pool | ||||||
|  |  * @vaddr:	Virtual address of start of pool | ||||||
|  |  * @paddr:	Physical address of start of pool | ||||||
|  |  * @size:	Size in bytes of the pool | ||||||
|  |  */ | ||||||
|  | struct tee_shm_pool_mem_info { | ||||||
|  | 	unsigned long vaddr; | ||||||
|  | 	phys_addr_t paddr; | ||||||
|  | 	size_t size; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved | ||||||
|  |  * memory range | ||||||
|  |  * @priv_info:	 Information for driver private shared memory pool | ||||||
|  |  * @dmabuf_info: Information for dma-buf shared memory pool | ||||||
|  |  * | ||||||
|  |  * Start and end of pools will must be page aligned. | ||||||
|  |  * | ||||||
|  |  * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied | ||||||
|  |  * in @dmabuf, others will use the range provided by @priv. | ||||||
|  |  * | ||||||
|  |  * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure. | ||||||
|  |  */ | ||||||
|  | struct tee_shm_pool * | ||||||
|  | tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info, | ||||||
|  | 			   struct tee_shm_pool_mem_info *dmabuf_info); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_pool_free() - Free a shared memory pool | ||||||
|  |  * @pool:	The shared memory pool to free | ||||||
|  |  * | ||||||
|  |  * The must be no remaining shared memory allocated from this pool when | ||||||
|  |  * this function is called. | ||||||
|  |  */ | ||||||
|  | void tee_shm_pool_free(struct tee_shm_pool *pool); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_get_drvdata() - Return driver_data pointer | ||||||
|  |  * @returns the driver_data pointer supplied to tee_register(). | ||||||
|  |  */ | ||||||
|  | void *tee_get_drvdata(struct tee_device *teedev); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_alloc() - Allocate shared memory | ||||||
|  |  * @ctx:	Context that allocates the shared memory | ||||||
|  |  * @size:	Requested size of shared memory | ||||||
|  |  * @flags:	Flags setting properties for the requested shared memory. | ||||||
|  |  * | ||||||
|  |  * Memory allocated as global shared memory is automatically freed when the | ||||||
|  |  * TEE file pointer is closed. The @flags field uses the bits defined by | ||||||
|  |  * TEE_SHM_* above. TEE_SHM_MAPPED must currently always be set. If | ||||||
|  |  * TEE_SHM_DMA_BUF global shared memory will be allocated and associated | ||||||
|  |  * with a dma-buf handle, else driver private memory. | ||||||
|  |  * | ||||||
|  |  * @returns a pointer to 'struct tee_shm' | ||||||
|  |  */ | ||||||
|  | struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_free() - Free shared memory | ||||||
|  |  * @shm:	Handle to shared memory to free | ||||||
|  |  */ | ||||||
|  | void tee_shm_free(struct tee_shm *shm); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_put() - Decrease reference count on a shared memory handle | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  */ | ||||||
|  | void tee_shm_put(struct tee_shm *shm); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_va2pa() - Get physical address of a virtual address | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @va:		Virtual address to tranlsate | ||||||
|  |  * @pa:		Returned physical address | ||||||
|  |  * @returns 0 on success and < 0 on failure | ||||||
|  |  */ | ||||||
|  | int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_pa2va() - Get virtual address of a physical address | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @pa:		Physical address to tranlsate | ||||||
|  |  * @va:		Returned virtual address | ||||||
|  |  * @returns 0 on success and < 0 on failure | ||||||
|  |  */ | ||||||
|  | int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_va() - Get virtual address of a shared memory plus an offset | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @offs:	Offset from start of this shared memory | ||||||
|  |  * @returns virtual address of the shared memory + offs if offs is within | ||||||
|  |  *	the bounds of this shared memory, else an ERR_PTR | ||||||
|  |  */ | ||||||
|  | void *tee_shm_get_va(struct tee_shm *shm, size_t offs); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_pa() - Get physical address of a shared memory plus an offset | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @offs:	Offset from start of this shared memory | ||||||
|  |  * @pa:		Physical address to return | ||||||
|  |  * @returns 0 if offs is within the bounds of this shared memory, else an | ||||||
|  |  *	error code. | ||||||
|  |  */ | ||||||
|  | int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_id() - Get id of a shared memory object | ||||||
|  |  * @shm:	Shared memory handle | ||||||
|  |  * @returns id | ||||||
|  |  */ | ||||||
|  | int tee_shm_get_id(struct tee_shm *shm); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tee_shm_get_from_id() - Find shared memory object and increase reference | ||||||
|  |  * count | ||||||
|  |  * @ctx:	Context owning the shared memory | ||||||
|  |  * @id:		Id of shared memory object | ||||||
|  |  * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure | ||||||
|  |  */ | ||||||
|  | struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id); | ||||||
|  | 
 | ||||||
|  | #endif /*__TEE_DRV_H*/ | ||||||
							
								
								
									
										346
									
								
								include/uapi/linux/tee.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								include/uapi/linux/tee.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,346 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2015-2016, Linaro Limited | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  * | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright notice, | ||||||
|  |  * this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |  * this list of conditions and the following disclaimer in the documentation | ||||||
|  |  * and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||||
|  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||||||
|  |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||||
|  |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||||
|  |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||||
|  |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||||
|  |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||||
|  |  * POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __TEE_H | ||||||
|  | #define __TEE_H | ||||||
|  | 
 | ||||||
|  | #include <linux/ioctl.h> | ||||||
|  | #include <linux/types.h> | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * This file describes the API provided by a TEE driver to user space. | ||||||
|  |  * | ||||||
|  |  * Each TEE driver defines a TEE specific protocol which is used for the | ||||||
|  |  * data passed back and forth using TEE_IOC_CMD. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Helpers to make the ioctl defines */ | ||||||
|  | #define TEE_IOC_MAGIC	0xa4 | ||||||
|  | #define TEE_IOC_BASE	0 | ||||||
|  | 
 | ||||||
|  | /* Flags relating to shared memory */ | ||||||
|  | #define TEE_IOCTL_SHM_MAPPED	0x1	/* memory mapped in normal world */ | ||||||
|  | #define TEE_IOCTL_SHM_DMA_BUF	0x2	/* dma-buf handle on shared memory */ | ||||||
|  | 
 | ||||||
|  | #define TEE_MAX_ARG_SIZE	1024 | ||||||
|  | 
 | ||||||
|  | #define TEE_GEN_CAP_GP		(1 << 0)/* GlobalPlatform compliant TEE */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * TEE Implementation ID | ||||||
|  |  */ | ||||||
|  | #define TEE_IMPL_ID_OPTEE	1 | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * OP-TEE specific capabilities | ||||||
|  |  */ | ||||||
|  | #define TEE_OPTEE_CAP_TZ	(1 << 0) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_ioctl_version_data - TEE version | ||||||
|  |  * @impl_id:	[out] TEE implementation id | ||||||
|  |  * @impl_caps:	[out] Implementation specific capabilities | ||||||
|  |  * @gen_caps:	[out] Generic capabilities, defined by TEE_GEN_CAPS_* above | ||||||
|  |  * | ||||||
|  |  * Identifies the TEE implementation, @impl_id is one of TEE_IMPL_ID_* above. | ||||||
|  |  * @impl_caps is implementation specific, for example TEE_OPTEE_CAP_* | ||||||
|  |  * is valid when @impl_id == TEE_IMPL_ID_OPTEE. | ||||||
|  |  */ | ||||||
|  | struct tee_ioctl_version_data { | ||||||
|  | 	__u32 impl_id; | ||||||
|  | 	__u32 impl_caps; | ||||||
|  | 	__u32 gen_caps; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * TEE_IOC_VERSION - query version of TEE | ||||||
|  |  * | ||||||
|  |  * Takes a tee_ioctl_version_data struct and returns with the TEE version | ||||||
|  |  * data filled in. | ||||||
|  |  */ | ||||||
|  | #define TEE_IOC_VERSION		_IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 0, \ | ||||||
|  | 				     struct tee_ioctl_version_data) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_ioctl_shm_alloc_data - Shared memory allocate argument | ||||||
|  |  * @size:	[in/out] Size of shared memory to allocate | ||||||
|  |  * @flags:	[in/out] Flags to/from allocation. | ||||||
|  |  * @id:		[out] Identifier of the shared memory | ||||||
|  |  * | ||||||
|  |  * The flags field should currently be zero as input. Updated by the call | ||||||
|  |  * with actual flags as defined by TEE_IOCTL_SHM_* above. | ||||||
|  |  * This structure is used as argument for TEE_IOC_SHM_ALLOC below. | ||||||
|  |  */ | ||||||
|  | struct tee_ioctl_shm_alloc_data { | ||||||
|  | 	__u64 size; | ||||||
|  | 	__u32 flags; | ||||||
|  | 	__s32 id; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * TEE_IOC_SHM_ALLOC - allocate shared memory | ||||||
|  |  * | ||||||
|  |  * Allocates shared memory between the user space process and secure OS. | ||||||
|  |  * | ||||||
|  |  * Returns a file descriptor on success or < 0 on failure | ||||||
|  |  * | ||||||
|  |  * The returned file descriptor is used to map the shared memory into user | ||||||
|  |  * space. The shared memory is freed when the descriptor is closed and the | ||||||
|  |  * memory is unmapped. | ||||||
|  |  */ | ||||||
|  | #define TEE_IOC_SHM_ALLOC	_IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 1, \ | ||||||
|  | 				     struct tee_ioctl_shm_alloc_data) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_ioctl_buf_data - Variable sized buffer | ||||||
|  |  * @buf_ptr:	[in] A __user pointer to a buffer | ||||||
|  |  * @buf_len:	[in] Length of the buffer above | ||||||
|  |  * | ||||||
|  |  * Used as argument for TEE_IOC_OPEN_SESSION, TEE_IOC_INVOKE, | ||||||
|  |  * TEE_IOC_SUPPL_RECV, and TEE_IOC_SUPPL_SEND below. | ||||||
|  |  */ | ||||||
|  | struct tee_ioctl_buf_data { | ||||||
|  | 	__u64 buf_ptr; | ||||||
|  | 	__u64 buf_len; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Attributes for struct tee_ioctl_param, selects field in the union | ||||||
|  |  */ | ||||||
|  | #define TEE_IOCTL_PARAM_ATTR_TYPE_NONE		0	/* parameter not used */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * These defines value parameters (struct tee_ioctl_param_value) | ||||||
|  |  */ | ||||||
|  | #define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT	1 | ||||||
|  | #define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT	2 | ||||||
|  | #define TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT	3	/* input and output */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * These defines shared memory reference parameters (struct | ||||||
|  |  * tee_ioctl_param_memref) | ||||||
|  |  */ | ||||||
|  | #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT	5 | ||||||
|  | #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT	6 | ||||||
|  | #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT	7	/* input and output */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Mask for the type part of the attribute, leaves room for more types | ||||||
|  |  */ | ||||||
|  | #define TEE_IOCTL_PARAM_ATTR_TYPE_MASK		0xff | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Matches TEEC_LOGIN_* in GP TEE Client API | ||||||
|  |  * Are only defined for GP compliant TEEs | ||||||
|  |  */ | ||||||
|  | #define TEE_IOCTL_LOGIN_PUBLIC			0 | ||||||
|  | #define TEE_IOCTL_LOGIN_USER			1 | ||||||
|  | #define TEE_IOCTL_LOGIN_GROUP			2 | ||||||
|  | #define TEE_IOCTL_LOGIN_APPLICATION		4 | ||||||
|  | #define TEE_IOCTL_LOGIN_USER_APPLICATION	5 | ||||||
|  | #define TEE_IOCTL_LOGIN_GROUP_APPLICATION	6 | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_ioctl_param - parameter | ||||||
|  |  * @attr: attributes | ||||||
|  |  * @a: if a memref, offset into the shared memory object, else a value parameter | ||||||
|  |  * @b: if a memref, size of the buffer, else a value parameter | ||||||
|  |  * @c: if a memref, shared memory identifier, else a value parameter | ||||||
|  |  * | ||||||
|  |  * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in | ||||||
|  |  * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and | ||||||
|  |  * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE | ||||||
|  |  * indicates that none of the members are used. | ||||||
|  |  * | ||||||
|  |  * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an | ||||||
|  |  * identifier representing the shared memory object. A memref can reference | ||||||
|  |  * a part of a shared memory by specifying an offset (@a) and size (@b) of | ||||||
|  |  * the object. To supply the entire shared memory object set the offset | ||||||
|  |  * (@a) to 0 and size (@b) to the previously returned size of the object. | ||||||
|  |  */ | ||||||
|  | struct tee_ioctl_param { | ||||||
|  | 	__u64 attr; | ||||||
|  | 	__u64 a; | ||||||
|  | 	__u64 b; | ||||||
|  | 	__u64 c; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define TEE_IOCTL_UUID_LEN		16 | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_ioctl_open_session_arg - Open session argument | ||||||
|  |  * @uuid:	[in] UUID of the Trusted Application | ||||||
|  |  * @clnt_uuid:	[in] UUID of client | ||||||
|  |  * @clnt_login:	[in] Login class of client, TEE_IOCTL_LOGIN_* above | ||||||
|  |  * @cancel_id:	[in] Cancellation id, a unique value to identify this request | ||||||
|  |  * @session:	[out] Session id | ||||||
|  |  * @ret:	[out] return value | ||||||
|  |  * @ret_origin	[out] origin of the return value | ||||||
|  |  * @num_params	[in] number of parameters following this struct | ||||||
|  |  */ | ||||||
|  | struct tee_ioctl_open_session_arg { | ||||||
|  | 	__u8 uuid[TEE_IOCTL_UUID_LEN]; | ||||||
|  | 	__u8 clnt_uuid[TEE_IOCTL_UUID_LEN]; | ||||||
|  | 	__u32 clnt_login; | ||||||
|  | 	__u32 cancel_id; | ||||||
|  | 	__u32 session; | ||||||
|  | 	__u32 ret; | ||||||
|  | 	__u32 ret_origin; | ||||||
|  | 	__u32 num_params; | ||||||
|  | 	/* num_params tells the actual number of element in params */ | ||||||
|  | 	struct tee_ioctl_param params[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * TEE_IOC_OPEN_SESSION - opens a session to a Trusted Application | ||||||
|  |  * | ||||||
|  |  * Takes a struct tee_ioctl_buf_data which contains a struct | ||||||
|  |  * tee_ioctl_open_session_arg followed by any array of struct | ||||||
|  |  * tee_ioctl_param | ||||||
|  |  */ | ||||||
|  | #define TEE_IOC_OPEN_SESSION	_IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 2, \ | ||||||
|  | 				     struct tee_ioctl_buf_data) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_ioctl_invoke_func_arg - Invokes a function in a Trusted | ||||||
|  |  * Application | ||||||
|  |  * @func:	[in] Trusted Application function, specific to the TA | ||||||
|  |  * @session:	[in] Session id | ||||||
|  |  * @cancel_id:	[in] Cancellation id, a unique value to identify this request | ||||||
|  |  * @ret:	[out] return value | ||||||
|  |  * @ret_origin	[out] origin of the return value | ||||||
|  |  * @num_params	[in] number of parameters following this struct | ||||||
|  |  */ | ||||||
|  | struct tee_ioctl_invoke_arg { | ||||||
|  | 	__u32 func; | ||||||
|  | 	__u32 session; | ||||||
|  | 	__u32 cancel_id; | ||||||
|  | 	__u32 ret; | ||||||
|  | 	__u32 ret_origin; | ||||||
|  | 	__u32 num_params; | ||||||
|  | 	/* num_params tells the actual number of element in params */ | ||||||
|  | 	struct tee_ioctl_param params[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * TEE_IOC_INVOKE - Invokes a function in a Trusted Application | ||||||
|  |  * | ||||||
|  |  * Takes a struct tee_ioctl_buf_data which contains a struct | ||||||
|  |  * tee_invoke_func_arg followed by any array of struct tee_param | ||||||
|  |  */ | ||||||
|  | #define TEE_IOC_INVOKE		_IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 3, \ | ||||||
|  | 				     struct tee_ioctl_buf_data) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_ioctl_cancel_arg - Cancels an open session or invoke ioctl | ||||||
|  |  * @cancel_id:	[in] Cancellation id, a unique value to identify this request | ||||||
|  |  * @session:	[in] Session id, if the session is opened, else set to 0 | ||||||
|  |  */ | ||||||
|  | struct tee_ioctl_cancel_arg { | ||||||
|  | 	__u32 cancel_id; | ||||||
|  | 	__u32 session; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * TEE_IOC_CANCEL - Cancels an open session or invoke | ||||||
|  |  */ | ||||||
|  | #define TEE_IOC_CANCEL		_IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 4, \ | ||||||
|  | 				     struct tee_ioctl_cancel_arg) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_ioctl_close_session_arg - Closes an open session | ||||||
|  |  * @session:	[in] Session id | ||||||
|  |  */ | ||||||
|  | struct tee_ioctl_close_session_arg { | ||||||
|  | 	__u32 session; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * TEE_IOC_CLOSE_SESSION - Closes a session | ||||||
|  |  */ | ||||||
|  | #define TEE_IOC_CLOSE_SESSION	_IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 5, \ | ||||||
|  | 				     struct tee_ioctl_close_session_arg) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_iocl_supp_recv_arg - Receive a request for a supplicant function | ||||||
|  |  * @func:	[in] supplicant function | ||||||
|  |  * @num_params	[in/out] number of parameters following this struct | ||||||
|  |  * | ||||||
|  |  * @num_params is the number of params that tee-supplicant has room to | ||||||
|  |  * receive when input, @num_params is the number of actual params | ||||||
|  |  * tee-supplicant receives when output. | ||||||
|  |  */ | ||||||
|  | struct tee_iocl_supp_recv_arg { | ||||||
|  | 	__u32 func; | ||||||
|  | 	__u32 num_params; | ||||||
|  | 	/* num_params tells the actual number of element in params */ | ||||||
|  | 	struct tee_ioctl_param params[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * TEE_IOC_SUPPL_RECV - Receive a request for a supplicant function | ||||||
|  |  * | ||||||
|  |  * Takes a struct tee_ioctl_buf_data which contains a struct | ||||||
|  |  * tee_iocl_supp_recv_arg followed by any array of struct tee_param | ||||||
|  |  */ | ||||||
|  | #define TEE_IOC_SUPPL_RECV	_IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 6, \ | ||||||
|  | 				     struct tee_ioctl_buf_data) | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct tee_iocl_supp_send_arg - Send a response to a received request | ||||||
|  |  * @ret:	[out] return value | ||||||
|  |  * @num_params	[in] number of parameters following this struct | ||||||
|  |  */ | ||||||
|  | struct tee_iocl_supp_send_arg { | ||||||
|  | 	__u32 ret; | ||||||
|  | 	__u32 num_params; | ||||||
|  | 	/* num_params tells the actual number of element in params */ | ||||||
|  | 	struct tee_ioctl_param params[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * TEE_IOC_SUPPL_SEND - Receive a request for a supplicant function | ||||||
|  |  * | ||||||
|  |  * Takes a struct tee_ioctl_buf_data which contains a struct | ||||||
|  |  * tee_iocl_supp_send_arg followed by any array of struct tee_param | ||||||
|  |  */ | ||||||
|  | #define TEE_IOC_SUPPL_SEND	_IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \ | ||||||
|  | 				     struct tee_ioctl_buf_data) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Five syscalls are used when communicating with the TEE driver. | ||||||
|  |  * open(): opens the device associated with the driver | ||||||
|  |  * ioctl(): as described above operating on the file descriptor from open() | ||||||
|  |  * close(): two cases | ||||||
|  |  *   - closes the device file descriptor | ||||||
|  |  *   - closes a file descriptor connected to allocated shared memory | ||||||
|  |  * mmap(): maps shared memory into user space using information from struct | ||||||
|  |  *	   tee_ioctl_shm_alloc_data | ||||||
|  |  * munmap(): unmaps previously shared memory | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #endif /*__TEE_H*/ | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jens Wiklander
						Jens Wiklander