mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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