aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric Chaumont <cedric.chaumont@st.com>2014-10-06 09:36:38 +0200
committerPascal Brand <pascal.brand@st.com>2015-02-06 16:41:39 +0100
commit724298b6e425d9ce6daae3131bb4b1029190aa2a (patch)
treef5937b0a2399b8f331f2727f1bf95330335c7706
parent9f504dbd39efb84805d1abe81d3844cd46954f67 (diff)
Linux driver refactoring
New architecture of the optee linux driver split the driver in 2 parts: - a generic driver, called optee - a specific backend. In this implementation, a single backend is provided for TrustZone. The name of the module is optee_armtz In order to load the linux driver, the following should be done: - modprobe optee_armtz This loads the specific backend optee_armtz.ko, linked with the generic module optee.ko Device /dev/opteearmtz00 is instanciated - tee-supplicant opteearmtz00 Fix #7 Reviewed-by: Joakim Bech <joakim.bech@linaro.org> Tested-by: Pascal Brand <pascal.brand@linaro.org> (STM platform) Tested-by: Pascal Brand <pascal.brand@linaro.org> (QEMU) Tested-by: Cedric Chaumont <cedric.chaumont@linaro.org> (FVP) Tested-by: Cedric Chaumont <cedric.chaumont@linaro.org> (Juno) Signed-off-by: Cedric Chaumont <cedric.chaumont@st.com>
-rw-r--r--.gitignore3
-rw-r--r--Makefile57
-rw-r--r--armtz/Makefile40
-rw-r--r--armtz/handle.c (renamed from core/arm64/handle.c)0
-rw-r--r--armtz/handle.h (renamed from core/arm64/handle.h)0
-rw-r--r--armtz/tee_mem.c (renamed from generic/tee_mem.c)163
-rw-r--r--armtz/tee_mem.h46
-rw-r--r--armtz/tee_smc-arm.S27
-rw-r--r--armtz/tee_smc-arm64.S (renamed from core/arm64/smc.S)8
-rw-r--r--armtz/tee_tz_drv.c1297
-rw-r--r--armtz/tee_tz_op.h259
-rw-r--r--armtz/tee_tz_priv.h52
-rw-r--r--core/Makefile32
-rw-r--r--core/arm64/tee_tz.c989
-rw-r--r--core/arm64/tee_tz.h41
-rw-r--r--core/arm64/tee_tz_debug.c113
-rw-r--r--core/armv7/stm-smc.S33
-rw-r--r--core/armv7/tee_tz.c975
-rw-r--r--core/armv7/tee_tz.h41
-rw-r--r--core/armv7/tee_tz_debug.c113
-rw-r--r--core/tee_context.c299
-rw-r--r--core/tee_core.c524
-rw-r--r--core/tee_core_priv.h41
-rw-r--r--core/tee_debugfs.c74
-rw-r--r--core/tee_debugfs.h13
-rw-r--r--core/tee_kernel_api.c264
-rw-r--r--core/tee_mutex_wait.c (renamed from generic/tee_mutex_wait.c)25
-rw-r--r--core/tee_mutex_wait.h (renamed from generic/tee_mutex_wait.h)13
-rw-r--r--core/tee_session.c1042
-rw-r--r--core/tee_shm.c455
-rw-r--r--core/tee_shm.h20
-rw-r--r--core/tee_supp_com.c271
-rw-r--r--core/tee_supp_com.h (renamed from generic/tee_supp_com.h)55
-rw-r--r--core/tee_sysfs.c193
-rw-r--r--core/tee_sysfs.h10
-rw-r--r--generic/tee-op.h318
-rw-r--r--generic/tee_debug.c125
-rw-r--r--generic/tee_debug.h25
-rw-r--r--generic/tee_driver.c481
-rw-r--r--generic/tee_driver.h73
-rw-r--r--generic/tee_kernel_api.c375
-rw-r--r--generic/tee_mem.h62
-rw-r--r--generic/tee_op.c82
-rw-r--r--generic/tee_service.c888
-rw-r--r--generic/tee_service.h53
-rw-r--r--generic/tee_supp_com.c234
-rw-r--r--include/arm_common/teesmc.h2
-rw-r--r--include/arm_common/teesmc_st.h6
-rw-r--r--include/linux/tee_client_api.h232
-rw-r--r--include/linux/tee_core.h186
-rw-r--r--include/linux/tee_ioc.h51
-rw-r--r--include/linux/tee_ioctl.h49
-rw-r--r--include/linux/tee_kernel_api.h24
53 files changed, 5565 insertions, 5289 deletions
diff --git a/.gitignore b/.gitignore
index 19cf6cb..b4011f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,6 @@ Debug
.*.swp
.project
.settings
+.optee_armtz.ko.cmd
+optee_armtz.ko
+optee_armtz.mod.c
diff --git a/Makefile b/Makefile
index 469dae5..25c0406 100644
--- a/Makefile
+++ b/Makefile
@@ -1,47 +1,10 @@
-CFG_TEE_DRV_DEBUGFS?=0
-
-ccflags-y+=-Werror
-ccflags-y+=-I$(M)/include/linux -iquote$(M)/generic
-ccflags-y+=-I$(src)/include
-
-ccflags-y+=-DCFG_TEE_DRV_DEBUGFS=${CFG_TEE_DRV_DEBUGFS}
-
-obj-m += optee.o
-
-optee-objs:= \
- generic/tee_service.o \
- generic/tee_driver.o \
- generic/tee_kernel_api.o \
- generic/tee_supp_com.o \
- generic/tee_mem.o \
- generic/tee_op.o \
- generic/tee_mutex_wait.o
-
-ifeq ($(ARCH),arm)
-ccflags-y+=-iquote$(M)/core/armv7
-optee-objs += core/armv7/tee_tz.o
-optee-objs += core/armv7/stm-smc.o
-# "smc" assembly intruction requires dedicated "armv7 secure extension"
-secext := $(call as-instr,.arch_extension sec,+sec)
-AFLAGS_stm-smc.o := -Wa,-march=armv7-a$(secext)
-endif
-
-ifeq ($(ARCH),arm64)
-ccflags-y+=-iquote$(M)/core/arm64
-optee-objs += core/arm64/tee_tz.o
-optee-objs += core/arm64/smc.o
-optee-objs += core/arm64/handle.o
-endif
-
-ifeq ($(CFG_TEE_DRV_DEBUGFS),1)
-
-ifeq ($(ARCH),arm)
-optee-objs += core/armv7/tee_tz_debug.o
-endif
-
-ifeq ($(ARCH),arm64)
-optee-objs += core/arm64/tee_tz_debug.o
-endif
-
-optee-objs += generic/tee_debug.o
-endif # CFG_TEE_DRV_DEBUGFS
+#
+# Copyright (C) STMicroelectronics 2014. All rights reserved.
+#
+# This code is STMicroelectronics proprietary and confidential.
+# Any use of the code for whatever purpose is subject to
+# specific written permission of STMicroelectronics SA.
+#
+
+obj-y += core/
+obj-y += armtz/
diff --git a/armtz/Makefile b/armtz/Makefile
new file mode 100644
index 0000000..af2b10c
--- /dev/null
+++ b/armtz/Makefile
@@ -0,0 +1,40 @@
+
+#########################################################################
+# Set Internal Variables #
+# May be modified to match your setup #
+#########################################################################
+CFG_TEE_DRV_DEBUGFS?=0
+CFG_TEE_CORE_LOG_LEVEL?=2
+CFG_TEE_TA_LOG_LEVEL?=2
+
+ccflags-y+=-Werror
+ccflags-y+=-I$(M)/include/arm_common
+ccflags-y+=-I$(M)/include/linux
+ccflags-y+=-I$(M)/include
+ccflags-y+=-I$(M)/core
+
+ccflags-y+=-DCFG_TEE_DRV_DEBUGFS=${CFG_TEE_DRV_DEBUGFS}
+ccflags-y+=-DCFG_TEE_CORE_LOG_LEVEL=${CFG_TEE_CORE_LOG_LEVEL}
+ccflags-y+=-DCFG_TEE_TA_LOG_LEVEL=${CFG_TEE_TA_LOG_LEVEL}
+
+obj-m += optee_armtz.o
+
+optee_armtz-objs:= \
+ tee_tz_drv.o \
+ tee_mem.o \
+ handle.o
+
+
+ifeq ($(CONFIG_ARM),y)
+# "smc" assembly intruction requires dedicated "armv7 secure extension"
+secext := $(call as-instr,.arch_extension sec,+sec)
+AFLAGS_tee_smc-arm.o := -Wa,-march=armv7-a$(secext)
+optee_armtz-objs += \
+ tee_smc-arm.o
+endif
+
+ifeq ($(CONFIG_ARM64),y)
+optee_armtz-objs += \
+ tee_smc-arm64.o
+endif
+
diff --git a/core/arm64/handle.c b/armtz/handle.c
index 33a0541..33a0541 100644
--- a/core/arm64/handle.c
+++ b/armtz/handle.c
diff --git a/core/arm64/handle.h b/armtz/handle.h
index 7132630..7132630 100644
--- a/core/arm64/handle.h
+++ b/armtz/handle.h
diff --git a/generic/tee_mem.c b/armtz/tee_mem.c
index 92c0982..aeb6dbf 100644
--- a/generic/tee_mem.c
+++ b/armtz/tee_mem.c
@@ -1,19 +1,10 @@
/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
+* Copyright (C) STMicroelectronics 2014. All rights reserved.
+*
+* This code is STMicroelectronics proprietary and confidential.
+* Any use of the code for whatever purpose is subject to
+* specific written permission of STMicroelectronics SA.
+*/
/**
* \file tee_mem.c
@@ -32,7 +23,6 @@
#include "tee_mem.h"
-
#define _DUMP_INFO_ALLOCATOR 0
#define USE_DEVM_ALLOC 1
@@ -58,9 +48,9 @@
*/
struct mem_chunk {
struct list_head node;
- uint32_t counter;
- size_t size;
- unsigned long paddr;
+ uint32_t counter;
+ size_t size;
+ unsigned long paddr;
};
/**
@@ -76,18 +66,17 @@ struct mem_chunk {
* Shared memory pool structure definition
*/
struct shm_pool {
- struct mutex lock; /* Shared memory lock */
- size_t size; /* Size of pool/heap memory segment */
- size_t used; /* Number of bytes allocated */
- void *vaddr; /* Associated Virtual address */
- unsigned long paddr; /* Associated Physical address */
- bool cached; /* true if pool is cacheable */
- struct list_head mchunks; /* Head of memory chunk/block list */
+ struct mutex lock;
+ size_t size; /* Size of pool/heap memory segment */
+ size_t used; /* Number of bytes allocated */
+ void *vaddr; /* Associated Virtual address */
+ unsigned long paddr; /* Associated Physical address */
+ bool cached; /* true if pool is cacheable */
+ struct list_head mchunks; /* Head of memory chunk/block list */
};
#define __CALCULATE_RATIO_MEM_USED(a) (((a->used)*100)/(a->size))
-
/**
* \brief Dumps the information of the shared memory pool
*
@@ -97,8 +86,7 @@ struct shm_pool {
* Dump/log the meta data of the shared memory pool on the standard output.
*
*/
-void tee_shm_pool_dump(struct device *dev, struct shm_pool *pool,
- bool forced)
+void tee_shm_pool_dump(struct device *dev, struct shm_pool *pool, bool forced)
{
struct mem_chunk *chunk;
@@ -110,9 +98,7 @@ void tee_shm_pool_dump(struct device *dev, struct shm_pool *pool,
(void *)pool,
(void *)pool->paddr,
(void *)pool->vaddr,
- pool->size,
- pool->used,
- __CALCULATE_RATIO_MEM_USED(pool));
+ pool->size, pool->used, __CALCULATE_RATIO_MEM_USED(pool));
if ((pool->used != 0) || (forced == true)) {
dev_info(dev, " \\ HEAD next:[0x%p] prev:[0x%p]\n",
@@ -128,8 +114,7 @@ void tee_shm_pool_dump(struct device *dev, struct shm_pool *pool,
(void *)chunk->node.next,
(void *)chunk->node.prev,
(void *)chunk->paddr,
- chunk->size,
- chunk->counter);
+ chunk->size, chunk->counter);
}
}
}
@@ -160,29 +145,29 @@ void tee_shm_pool_set_cached(struct shm_pool *pool)
* If a error is detected returned pool is NULL.
*/
struct shm_pool *tee_shm_pool_create(struct device *dev, size_t shm_size,
- void *shm_vaddr, unsigned long shm_paddr)
+ void *shm_vaddr, unsigned long shm_paddr)
{
struct mem_chunk *chunk = NULL;
- struct shm_pool *pool = NULL;
+ struct shm_pool *pool = NULL;
if (WARN_ON(!dev))
goto alloc_failed;
- dev_dbg(dev, "> vaddr=0x%p, paddr=0x%lx, size=%zuKiB\n",
- shm_vaddr, shm_paddr, shm_size/1024);
+ dev_dbg(dev, "> vaddr=0x%p, paddr=0x%p, size=%zuKiB\n",
+ shm_vaddr, (void *)shm_paddr, shm_size / 1024);
/* Alloc and initialize the shm_pool structure */
pool = _KMALLOC(sizeof(struct shm_pool), GFP_KERNEL);
if (!pool) {
dev_err(dev, "kmalloc <struct shm_pool> failed\n");
- goto alloc_failed;
+ goto alloc_failed;
}
memset(pool, 0, sizeof(*pool));
mutex_init(&pool->lock);
mutex_lock(&pool->lock);
INIT_LIST_HEAD(&(pool->mchunks));
- pool->size = shm_size;
+ pool->size = shm_size;
pool->vaddr = shm_vaddr;
pool->paddr = shm_paddr;
@@ -191,11 +176,11 @@ struct shm_pool *tee_shm_pool_create(struct device *dev, size_t shm_size,
chunk = _KMALLOC(sizeof(struct mem_chunk), GFP_KERNEL);
if (!chunk) {
dev_err(dev, "kmalloc <struct MemChunk> failed\n");
- goto alloc_failed;
+ goto alloc_failed;
}
memset(chunk, 0, sizeof(*chunk));
- chunk->paddr = shm_paddr;
- chunk->size = shm_size;
+ chunk->paddr = shm_paddr;
+ chunk->size = shm_size;
/* Adds the new entry immediately after the list head */
list_add(&(chunk->node), &(pool->mchunks));
@@ -266,7 +251,6 @@ void tee_shm_pool_destroy(struct device *dev, struct shm_pool *pool)
dev_dbg(dev, "<\n");
}
-
/**
* \brief Free all reserved chunk if any, and set pool at it initial state
*
@@ -295,9 +279,9 @@ void tee_shm_pool_reset(struct device *dev, struct shm_pool *pool)
}
first->counter = 0;
- first->paddr = pool->paddr;
- first->size = pool->size;
- pool->used = 0;
+ first->paddr = pool->paddr;
+ first->size = pool->size;
+ pool->used = 0;
mutex_unlock(&pool->lock);
}
@@ -315,7 +299,7 @@ void tee_shm_pool_reset(struct device *dev, struct shm_pool *pool)
*
*/
void *tee_shm_pool_p2v(struct device *dev, struct shm_pool *pool,
- unsigned long paddr)
+ unsigned long paddr)
{
if (WARN_ON(!dev || !pool))
return NULL;
@@ -348,7 +332,7 @@ void *tee_shm_pool_p2v(struct device *dev, struct shm_pool *pool,
*
*/
unsigned long tee_shm_pool_v2p(struct device *dev, struct shm_pool *pool,
- void *vaddr)
+ void *vaddr)
{
if (WARN_ON(!dev || !pool))
return 0UL;
@@ -361,7 +345,7 @@ unsigned long tee_shm_pool_v2p(struct device *dev, struct shm_pool *pool,
mutex_unlock(&pool->lock);
return 0UL;
} else {
- unsigned long offset = vaddr - pool->vaddr;
+ unsigned long offset = vaddr - pool->vaddr;
unsigned long p = pool->paddr + offset;
mutex_unlock(&pool->lock);
return p;
@@ -381,21 +365,22 @@ unsigned long tee_shm_pool_v2p(struct device *dev, struct shm_pool *pool,
*
*/
unsigned long tee_shm_pool_alloc(struct device *dev,
- struct shm_pool *pool,
- size_t size, size_t alignment)
+ struct shm_pool *pool,
+ size_t size, size_t alignment)
{
struct mem_chunk *chunk;
struct mem_chunk *betterchunk = NULL;
- struct mem_chunk *prev_chunk = NULL;
- struct mem_chunk *next_chunk = NULL;
+ struct mem_chunk *prev_chunk = NULL;
+ struct mem_chunk *next_chunk = NULL;
unsigned long begAddr;
unsigned long endAddr;
if (WARN_ON(!dev || !pool))
return 0UL;
- dev_dbg(dev, "> poolH(0x%p) size=0x%zx align=0x%zx\n",
- pool, size, alignment);
+ dev_dbg(dev, "> poolH(%p:%p:%x) size=0x%zx align=0x%zx\n",
+ pool, (void *)pool->paddr, (unsigned int)pool->size, size,
+ alignment);
/* Align on cache line of the target */
/* \todo(jmd) Should be defined by a global target specific parameter */
@@ -422,15 +407,15 @@ unsigned long tee_shm_pool_alloc(struct device *dev,
* size(b) - size is as small as possible.
*/
list_for_each_entry(chunk, &pool->mchunks, node) {
- if (chunk->counter == 0) { /* Free chunk */
+ if (chunk->counter == 0) { /* Free chunk */
begAddr = ALIGN(chunk->paddr, alignment);
endAddr = begAddr + size;
- if (begAddr >= chunk->paddr &&
- endAddr <= (chunk->paddr + chunk->size) &&
- (betterchunk == NULL ||
- /* Always split smaller block */
- chunk->size < betterchunk->size))
+ if (begAddr >= chunk->paddr
+ && endAddr <= (chunk->paddr + chunk->size)
+ && (betterchunk == NULL
+ /* Always split smaller block */
+ || chunk->size < betterchunk->size))
betterchunk = chunk;
}
}
@@ -452,8 +437,8 @@ unsigned long tee_shm_pool_alloc(struct device *dev,
/* memory between begin of chunk and begin
* of created memory => create a free chunk */
prev_chunk->counter = 0;
- prev_chunk->paddr = betterchunk->paddr;
- prev_chunk->size = begAddr - betterchunk->paddr;
+ prev_chunk->paddr = betterchunk->paddr;
+ prev_chunk->size = begAddr - betterchunk->paddr;
betterchunk->paddr = begAddr;
betterchunk->size -= prev_chunk->size;
@@ -461,8 +446,7 @@ unsigned long tee_shm_pool_alloc(struct device *dev,
dev_dbg(dev,
"create p_chunkH=0x%p paddr=0x%p (s=%zu)\n",
(void *)prev_chunk,
- (void *)prev_chunk->paddr,
- prev_chunk->size);
+ (void *)prev_chunk->paddr, prev_chunk->size);
list_add_tail(&(prev_chunk->node),
&(betterchunk->node));
@@ -475,14 +459,13 @@ unsigned long tee_shm_pool_alloc(struct device *dev,
/* memory between end of chunk and end of
* created memory => create a free chunk */
next_chunk->counter = 0;
- next_chunk->paddr = endAddr;
- next_chunk->size = betterchunk->size - size;
+ next_chunk->paddr = endAddr;
+ next_chunk->size = betterchunk->size - size;
dev_dbg(dev,
"create n_chunkH=0x%p paddr=0x%p (s=%zu)\n",
(void *)next_chunk,
- (void *)next_chunk->paddr,
- next_chunk->size);
+ (void *)next_chunk->paddr, next_chunk->size);
betterchunk->size = size;
@@ -505,9 +488,7 @@ unsigned long tee_shm_pool_alloc(struct device *dev,
"< chunkH=0x%p paddr=%p (s=%zu) align=0x%zx\n",
(void *)betterchunk,
(void *)betterchunk->paddr,
- betterchunk->size,
- alignment);
-
+ betterchunk->size, alignment);
return betterchunk->paddr;
}
@@ -542,14 +523,13 @@ failed_out:
* the memory region managed by the pool.
*
*/
-void tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
- unsigned long paddr, size_t *size)
+int tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
+ unsigned long paddr, size_t *size)
{
struct mem_chunk *chunk;
- struct mem_chunk *tmp;
if (WARN_ON(!dev || !pool))
- return;
+ return -EINVAL;
dev_dbg(dev, "> Try to free ... poolH(0x%p) paddr=0x%p\n",
(void *)pool, (void *)paddr);
@@ -563,15 +543,16 @@ void tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
if (!is_valid_paddr(pool, paddr))
goto out_failed;
- list_for_each_entry_safe(chunk, tmp, &pool->mchunks, node) {
+ list_for_each_entry(chunk, &pool->mchunks, node) {
if (chunk->paddr == paddr) {
if (size != NULL)
*size = chunk->size;
if (chunk->counter == 0) {
dev_warn(dev,
- "tee_shm_pool_free() WARNING, paddr=0x%p already released\n",
- (void *)paddr);
+ "< tee_shm_pool_free() WARNING, paddr=0x%p already released\n",
+ (void *)paddr);
+ return -EINVAL;
} else if (--chunk->counter == 0) {
dev_dbg(dev, "paddr=%p\n", (void *)paddr);
@@ -580,9 +561,8 @@ void tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
/* Merge with previous */
if (chunk->node.prev != &pool->mchunks) {
struct mem_chunk *prev =
- list_entry(chunk->node.prev,
- struct mem_chunk,
- node);
+ list_entry(chunk->node.prev,
+ struct mem_chunk, node);
if (prev->counter == 0) {
dev_dbg(dev,
"chunkH=0x%p paddr=0x%p free ok\n",
@@ -597,9 +577,8 @@ void tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
/* Merge with next */
if (chunk->node.next != &pool->mchunks) {
struct mem_chunk *next =
- list_entry(chunk->node.next,
- struct mem_chunk,
- node);
+ list_entry(chunk->node.next,
+ struct mem_chunk, node);
if (next->counter == 0) {
dev_dbg(dev,
"chunkH=0x%p paddr=0x%p free ok\n",
@@ -615,17 +594,16 @@ void tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 1)
tee_shm_pool_dump(dev, pool, false);
#endif
+ dev_dbg(dev, "< freed\n");
+ return 0;
} else {
mutex_unlock(&pool->lock);
dev_dbg(dev,
- "paddr=0x%p (--) refcounter is decremented\n",
+ "< paddr=0x%p (--) refcounter is decremented ret=1\n",
(void *)paddr);
+ return 1;
}
-
- dev_dbg(dev, "<\n");
-
- return;
}
}
@@ -637,6 +615,7 @@ out_failed:
dev_err(dev,
"< tee_shm_pool_free() FAILED, pAddr=0x%p not found\n",
(void *)paddr);
+ return -EINVAL;
}
/**
@@ -652,7 +631,7 @@ out_failed:
*
*/
bool tee_shm_pool_incref(struct device *dev, struct shm_pool *pool,
- unsigned long paddr)
+ unsigned long paddr)
{
struct mem_chunk *chunk;
diff --git a/armtz/tee_mem.h b/armtz/tee_mem.h
new file mode 100644
index 0000000..c60efa0
--- /dev/null
+++ b/armtz/tee_mem.h
@@ -0,0 +1,46 @@
+/*
+* Copyright (C) STMicroelectronics 2014. All rights reserved.
+*
+* This code is STMicroelectronics proprietary and confidential.
+* Any use of the code for whatever purpose is subject to
+* specific written permission of STMicroelectronics SA.
+*/
+
+#ifndef TEE_MEM_H
+#define TEE_MEM_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+struct shm_pool;
+
+struct shm_pool *tee_shm_pool_create(struct device *dev, size_t shm_size,
+ void *shm_vaddr, unsigned long shm_paddr);
+
+void tee_shm_pool_destroy(struct device *dev, struct shm_pool *pool);
+
+void *tee_shm_pool_p2v(struct device *dev, struct shm_pool *pool,
+ unsigned long paddr);
+
+unsigned long tee_shm_pool_v2p(struct device *dev, struct shm_pool *pool,
+ void *vaddr);
+
+unsigned long tee_shm_pool_alloc(struct device *dev,
+ struct shm_pool *pool,
+ size_t size, size_t alignment);
+
+int tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
+ unsigned long paddr, size_t *size);
+
+bool tee_shm_pool_incref(struct device *dev, struct shm_pool *pool,
+ unsigned long paddr);
+
+void tee_shm_pool_dump(struct device *dev, struct shm_pool *pool, bool forced);
+
+void tee_shm_pool_reset(struct device *dev, struct shm_pool *pool);
+
+bool tee_shm_pool_is_cached(struct shm_pool *pool);
+
+void tee_shm_pool_set_cached(struct shm_pool *pool);
+
+#endif
diff --git a/armtz/tee_smc-arm.S b/armtz/tee_smc-arm.S
new file mode 100644
index 0000000..b5ae88d
--- /dev/null
+++ b/armtz/tee_smc-arm.S
@@ -0,0 +1,27 @@
+/*
+* Copyright (C) STMicroelectronics 2014. All rights reserved.
+*
+* This code is STMicroelectronics proprietary and confidential.
+* Any use of the code for whatever purpose is subject to
+* specific written permission of STMicroelectronics SA.
+*/
+
+#include <linux/linkage.h>
+
+.text
+.balign 4
+.code 32
+
+ /* void tee_smc_call(struct smc_param *param); */
+ .globl tee_smc_call
+ENTRY(tee_smc_call)
+ push {r4-r8, lr}
+ mov r8, r0
+ ldm r8, {r0-r7}
+.arch_extension sec
+ smc #0
+ stm r8, {r0-r7}
+ pop {r4-r8, pc}
+ENDPROC(tee_smc_call)
+
+
diff --git a/core/arm64/smc.S b/armtz/tee_smc-arm64.S
index 462f9a4..105e18f 100644
--- a/core/arm64/smc.S
+++ b/armtz/tee_smc-arm64.S
@@ -23,9 +23,9 @@
#define SMC_PARAM_X4_OFFS 32
#define SMC_PARAM_X6_OFFS 48
- /* void tee_smc_call64(struct smc_param64 *param); */
- .globl tee_smc_call64
-ENTRY(tee_smc_call64)
+ /* void tee_smc_call(struct smc_param *param); */
+ .globl tee_smc_call
+ENTRY(tee_smc_call)
stp x28, x30, [sp, #-16]!
mov x28, x0
ldp x0, x1, [x28, #SMC_PARAM_X0_OFFS]
@@ -37,4 +37,4 @@ ENTRY(tee_smc_call64)
stp x2, x3, [x28, #SMC_PARAM_X2_OFFS]
ldp x28, x30, [sp], #16
ret
-ENDPROC(tee_smc_call64)
+ENDPROC(tee_smc_call)
diff --git a/armtz/tee_tz_drv.c b/armtz/tee_tz_drv.c
new file mode 100644
index 0000000..fa5e4e9
--- /dev/null
+++ b/armtz/tee_tz_drv.c
@@ -0,0 +1,1297 @@
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+
+#include <linux/tee_core.h>
+#include <linux/tee_ioc.h>
+
+#include <tee_shm.h>
+#include <tee_supp_com.h>
+#include <tee_mutex_wait.h>
+
+#include <arm_common/teesmc.h>
+#include <arm_common/teesmc_st.h>
+
+#include "tee_mem.h"
+#include "tee_tz_op.h"
+#include "tee_tz_priv.h"
+#include "handle.h"
+
+#define _TEE_TZ_NAME "armtz"
+#define DEV (ptee->tee->dev)
+
+/* #define TEE_STRESS_OUTERCACHE_FLUSH */
+
+/* magic config: bit 1 is set, Secure TEE shall handler NSec IRQs */
+#define SEC_ROM_NO_FLAG_MASK 0x0000
+#define SEC_ROM_IRQ_ENABLE_MASK 0x0001
+#define SEC_ROM_DEFAULT SEC_ROM_IRQ_ENABLE_MASK
+#define TEE_RETURN_BUSY 0x3
+#define ALLOC_ALIGN SZ_4K
+
+#define CAPABLE(tee) !(tee->conf & TEE_CONF_FW_NOT_CAPABLE)
+
+static struct tee_tz *tee_tz;
+
+static struct handle_db shm_handle_db = HANDLE_DB_INITIALIZER;
+
+
+/* Temporary workaround until we're only using post 3.13 kernels */
+#ifdef ioremap_cached
+#define ioremap_cache ioremap_cached
+#endif
+
+
+/*******************************************************************
+ * Calling TEE
+ *******************************************************************/
+
+static void e_lock_teez(struct tee_tz *ptee)
+{
+ mutex_lock(&ptee->mutex);
+}
+
+static void e_lock_wait_completion_teez(struct tee_tz *ptee)
+{
+ /*
+ * Release the lock until "something happens" and then reacquire it
+ * again.
+ *
+ * This is needed when TEE returns "busy" and we need to try again
+ * later.
+ */
+ ptee->c_waiters++;
+ mutex_unlock(&ptee->mutex);
+ /*
+ * Wait at most one second. Secure world is normally never busy
+ * more than that so we should normally never timeout.
+ */
+ wait_for_completion_timeout(&ptee->c, HZ);
+ mutex_lock(&ptee->mutex);
+ ptee->c_waiters--;
+}
+
+static void e_unlock_teez(struct tee_tz *ptee)
+{
+ /*
+ * If at least one thread is waiting for "something to happen" let
+ * one thread know that "something has happened".
+ */
+ if (ptee->c_waiters)
+ complete(&ptee->c);
+ mutex_unlock(&ptee->mutex);
+}
+
+static void handle_rpc_func_cmd_mutex_wait(struct tee_tz *ptee,
+ struct teesmc32_arg *arg32)
+{
+ struct teesmc32_param *params;
+
+ if (arg32->num_params != 2)
+ goto bad;
+
+ params = TEESMC32_GET_PARAMS(arg32);
+
+ if ((params[0].attr & TEESMC_ATTR_TYPE_MASK) !=
+ TEESMC_ATTR_TYPE_VALUE_INPUT)
+ goto bad;
+ if ((params[1].attr & TEESMC_ATTR_TYPE_MASK) !=
+ TEESMC_ATTR_TYPE_VALUE_INPUT)
+ goto bad;
+
+ switch (params[0].u.value.a) {
+ case TEE_MUTEX_WAIT_SLEEP:
+ tee_mutex_wait_sleep(DEV, &ptee->mutex_wait,
+ params[1].u.value.a,
+ params[1].u.value.b);
+ break;
+ case TEE_MUTEX_WAIT_WAKEUP:
+ tee_mutex_wait_wakeup(DEV, &ptee->mutex_wait,
+ params[1].u.value.a,
+ params[1].u.value.b);
+ break;
+ case TEE_MUTEX_WAIT_DELETE:
+ tee_mutex_wait_delete(DEV, &ptee->mutex_wait,
+ params[1].u.value.a);
+ break;
+ default:
+ goto bad;
+ }
+
+ arg32->ret = TEEC_SUCCESS;
+ return;
+bad:
+ arg32->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+
+static void handle_rpc_func_cmd_wait(struct teesmc32_arg *arg32)
+{
+ struct teesmc32_param *params;
+ u32 msec_to_wait;
+
+ if (arg32->num_params != 1)
+ goto bad;
+
+ params = TEESMC32_GET_PARAMS(arg32);
+ msec_to_wait = params[0].u.value.a;
+
+ /* set task's state to interruptible sleep */
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /* take a nap */
+ schedule_timeout(msecs_to_jiffies(msec_to_wait));
+
+ arg32->ret = TEEC_SUCCESS;
+ return;
+bad:
+ arg32->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+
+static void handle_rpc_func_cmd_to_supplicant(struct tee_tz *ptee,
+ struct teesmc32_arg *arg32)
+{
+ struct teesmc32_param *params;
+ struct tee_rpc_invoke inv;
+ size_t n;
+ uint32_t ret;
+
+ if (arg32->num_params > TEE_RPC_BUFFER_NUMBER) {
+ arg32->ret = TEEC_ERROR_GENERIC;
+ return;
+ }
+
+ params = TEESMC32_GET_PARAMS(arg32);
+
+ memset(&inv, 0, sizeof(inv));
+ inv.cmd = arg32->cmd;
+ /*
+ * Set a suitable error code in case tee-supplicant
+ * ignores the request.
+ */
+ inv.res = TEEC_ERROR_NOT_IMPLEMENTED;
+ inv.nbr_bf = arg32->num_params;
+ for (n = 0; n < arg32->num_params; n++) {
+ inv.cmds[n].buffer =
+ (void *)(uintptr_t)params[n].u.memref.buf_ptr;
+ inv.cmds[n].size = params[n].u.memref.size;
+ switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
+ case TEESMC_ATTR_TYPE_VALUE_INPUT:
+ case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
+ case TEESMC_ATTR_TYPE_VALUE_INOUT:
+ inv.cmds[n].type = TEE_RPC_VALUE;
+ break;
+ case TEESMC_ATTR_TYPE_MEMREF_INPUT:
+ case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEESMC_ATTR_TYPE_MEMREF_INOUT:
+ inv.cmds[n].type = TEE_RPC_BUFFER;
+ break;
+ default:
+ arg32->ret = TEEC_ERROR_GENERIC;
+ return;
+ }
+ }
+
+ ret = tee_supp_cmd(ptee->tee, TEE_RPC_ICMD_INVOKE,
+ &inv, sizeof(inv));
+ if (ret == TEEC_RPC_OK)
+ arg32->ret = inv.res;
+
+ for (n = 0; n < arg32->num_params; n++) {
+ switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
+ case TEESMC_ATTR_TYPE_VALUE_INPUT:
+ case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
+ case TEESMC_ATTR_TYPE_VALUE_INOUT:
+ case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEESMC_ATTR_TYPE_MEMREF_INOUT:
+ /*
+ * Allow supplicant to assign a new pointer
+ * to an out-buffer. Needed when the
+ * supplicant allocates a new buffer, for
+ * instance when loading a TA.
+ */
+ params[n].u.memref.buf_ptr =
+ (uint32_t)(uintptr_t)inv.cmds[n].buffer;
+ params[n].u.memref.size = inv.cmds[n].size;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void handle_rpc_func_cmd(struct tee_tz *ptee, u32 parg32)
+{
+ struct teesmc32_arg *arg32;
+
+ arg32 = tee_shm_pool_p2v(DEV, ptee->shm_pool, parg32);
+ if (!arg32)
+ return;
+
+ switch (arg32->cmd) {
+ case TEE_RPC_MUTEX_WAIT:
+ handle_rpc_func_cmd_mutex_wait(ptee, arg32);
+ break;
+ case TEE_RPC_WAIT:
+ handle_rpc_func_cmd_wait(arg32);
+ break;
+ default:
+ handle_rpc_func_cmd_to_supplicant(ptee, arg32);
+ }
+}
+
+static u32 handle_rpc(struct tee_tz *ptee, struct smc_param *param)
+{
+ struct tee_shm *shm;
+ int cookie;
+
+ switch (TEESMC_RETURN_GET_RPC_FUNC(param->a0)) {
+ case TEESMC_RPC_FUNC_ALLOC_ARG:
+ param->a1 = tee_shm_pool_alloc(DEV, ptee->shm_pool,
+ param->a1, 4);
+ break;
+ case TEESMC_RPC_FUNC_ALLOC_PAYLOAD:
+ /* Can't support payload shared memory with this interface */
+ param->a2 = 0;
+ break;
+ case TEESMC_RPC_FUNC_FREE_ARG:
+ tee_shm_pool_free(DEV, ptee->shm_pool, param->a1, 0);
+ break;
+ case TEESMC_RPC_FUNC_FREE_PAYLOAD:
+ /* Can't support payload shared memory with this interface */
+ break;
+ case TEESMC_ST_RPC_FUNC_ALLOC_PAYLOAD:
+ shm = tee_shm_alloc_from_rpc(ptee->tee, param->a1,
+ TEE_SHM_TEMP | TEE_SHM_FROM_RPC);
+ if (!shm) {
+ param->a1 = 0;
+ break;
+ }
+ cookie = handle_get(&shm_handle_db, shm);
+ if (cookie < 0) {
+ tee_shm_free_from_rpc(shm);
+ param->a1 = 0;
+ break;
+ }
+ param->a1 = shm->paddr;
+ param->a2 = cookie;
+ break;
+ case TEESMC_ST_RPC_FUNC_FREE_PAYLOAD:
+ if (true || param->a1) {
+ shm = handle_put(&shm_handle_db, param->a1);
+ if (shm)
+ tee_shm_free_from_rpc(shm);
+ }
+ break;
+ case TEESMC_RPC_FUNC_IRQ:
+ break;
+ case TEESMC_RPC_FUNC_CMD:
+ handle_rpc_func_cmd(ptee, param->a1);
+ break;
+ default:
+ dev_warn(DEV, "Unknown RPC func 0x%x\n",
+ (u32)TEESMC_RETURN_GET_RPC_FUNC(param->a0));
+ break;
+ }
+
+ if (irqs_disabled())
+ return TEESMC32_FASTCALL_RETURN_FROM_RPC;
+ else
+ return TEESMC32_CALL_RETURN_FROM_RPC;
+}
+
+static void call_tee(struct tee_tz *ptee,
+ uintptr_t parg32, struct teesmc32_arg *arg32)
+{
+ u32 ret;
+ u32 funcid;
+ struct smc_param param = { 0 };
+
+ if (irqs_disabled())
+ funcid = TEESMC32_FASTCALL_WITH_ARG;
+ else
+ funcid = TEESMC32_CALL_WITH_ARG;
+
+ /*
+ * Commented out elements used to visualize the layout dynamic part
+ * of the struct. Note that these fields are not available at all
+ * if num_params == 0.
+ *
+ * params is accessed through the macro TEESMC32_GET_PARAMS
+ */
+
+ /* struct teesmc32_param params[num_params]; */
+
+
+ param.a1 = parg32;
+ e_lock_teez(ptee);
+ while (true) {
+ param.a0 = funcid;
+
+ tee_smc_call(&param);
+ ret = param.a0;
+
+ if (ret == TEESMC_RETURN_EBUSY) {
+ /*
+ * Since secure world returned busy, release the
+ * lock we had when entering this function and wait
+ * for "something to happen" (something else to
+ * exit from secure world and needed resources may
+ * have become available).
+ */
+ e_lock_wait_completion_teez(ptee);
+ } else if (TEESMC_RETURN_IS_RPC(ret)) {
+ /* Process the RPC. */
+ e_unlock_teez(ptee);
+ funcid = handle_rpc(ptee, &param);
+ e_lock_teez(ptee);
+ } else {
+ break;
+ }
+ }
+ e_unlock_teez(ptee);
+
+ switch (ret) {
+ case TEESMC_RETURN_UNKNOWN_FUNCTION:
+ break;
+ case TEESMC_RETURN_OK:
+ /* arg32->ret set by secure world */
+ break;
+ default:
+ /* Should not happen */
+ arg32->ret = TEEC_ERROR_COMMUNICATION;
+ arg32->ret_origin = TEEC_ORIGIN_COMMS;
+ break;
+ }
+}
+
+/*******************************************************************
+ * TEE service invoke formating
+ *******************************************************************/
+
+/* allocate tee service argument buffer and return virtual address */
+static void *alloc_tee_arg(struct tee_tz *ptee, unsigned long *p, size_t l)
+{
+ void *vaddr;
+ dev_dbg(DEV, ">\n");
+ BUG_ON(!CAPABLE(ptee->tee));
+
+ if ((p == NULL) || (l == 0))
+ return NULL;
+
+ /* assume a 4 bytes aligned is sufficient */
+ *p = tee_shm_pool_alloc(DEV, ptee->shm_pool, l, ALLOC_ALIGN);
+ if (*p == 0)
+ return NULL;
+
+ vaddr = tee_shm_pool_p2v(DEV, ptee->shm_pool, *p);
+
+ dev_dbg(DEV, "< %p\n", vaddr);
+
+ return vaddr;
+}
+
+/* free tee service argument buffer (from its physical address) */
+static void free_tee_arg(struct tee_tz *ptee, unsigned long p)
+{
+ dev_dbg(DEV, ">\n");
+ BUG_ON(!CAPABLE(ptee->tee));
+
+ if (p)
+ tee_shm_pool_free(DEV, ptee->shm_pool, p, 0);
+
+ dev_dbg(DEV, "<\n");
+}
+
+static uint32_t get_cache_attrs(struct tee_tz *ptee)
+{
+ if (tee_shm_pool_is_cached(ptee->shm_pool))
+ return TEESMC_ATTR_CACHE_DEFAULT << TEESMC_ATTR_CACHE_SHIFT;
+ else
+ return TEESMC_ATTR_CACHE_NONCACHE << TEESMC_ATTR_CACHE_SHIFT;
+}
+
+static uint32_t param_type_teec2teesmc(uint8_t type)
+{
+ switch (type) {
+ case TEEC_NONE:
+ return TEESMC_ATTR_TYPE_NONE;
+ case TEEC_VALUE_INPUT:
+ return TEESMC_ATTR_TYPE_VALUE_INPUT;
+ case TEEC_VALUE_OUTPUT:
+ return TEESMC_ATTR_TYPE_VALUE_OUTPUT;
+ case TEEC_VALUE_INOUT:
+ return TEESMC_ATTR_TYPE_VALUE_INOUT;
+ case TEEC_MEMREF_TEMP_INPUT:
+ case TEEC_MEMREF_PARTIAL_INPUT:
+ return TEESMC_ATTR_TYPE_MEMREF_INPUT;
+ case TEEC_MEMREF_TEMP_OUTPUT:
+ case TEEC_MEMREF_PARTIAL_OUTPUT:
+ return TEESMC_ATTR_TYPE_MEMREF_OUTPUT;
+ case TEEC_MEMREF_WHOLE:
+ case TEEC_MEMREF_TEMP_INOUT:
+ case TEEC_MEMREF_PARTIAL_INOUT:
+ return TEESMC_ATTR_TYPE_MEMREF_INOUT;
+ default:
+ WARN_ON(true);
+ return 0;
+ }
+}
+
+static void set_params(struct tee_tz *ptee,
+ struct teesmc32_param params32[TEEC_CONFIG_PAYLOAD_REF_COUNT],
+ uint32_t param_types,
+ struct tee_data *data)
+{
+ size_t n;
+ struct tee_shm **shm;
+ TEEC_Value *value;
+
+ for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
+ uint32_t type = TEEC_PARAM_TYPE_GET(param_types, n);
+
+ params32[n].attr = param_type_teec2teesmc(type);
+ if (params32[n].attr == TEESMC_ATTR_TYPE_NONE)
+ continue;
+ if (params32[n].attr < TEESMC_ATTR_TYPE_MEMREF_INPUT) {
+ value = (TEEC_Value *)&data->params[n];
+ params32[n].u.value.a = value->a;
+ params32[n].u.value.b = value->b;
+ continue;
+ }
+ shm = (struct tee_shm **)&data->params[n];
+ params32[n].attr |= get_cache_attrs(ptee);
+ params32[n].u.memref.buf_ptr = (*shm)->paddr;
+ params32[n].u.memref.size = (*shm)->size_req;
+ }
+}
+
+static void get_params(struct tee_data *data,
+ struct teesmc32_param params32[TEEC_CONFIG_PAYLOAD_REF_COUNT])
+{
+ size_t n;
+ struct tee_shm **shm;
+ TEEC_Value *value;
+
+ for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
+ if (params32[n].attr == TEESMC_ATTR_TYPE_NONE)
+ continue;
+ if (params32[n].attr < TEESMC_ATTR_TYPE_MEMREF_INPUT) {
+ value = (TEEC_Value *)&data->params[n];
+ value->a = params32[n].u.value.a;
+ value->b = params32[n].u.value.b;
+ continue;
+ }
+ shm = (struct tee_shm **)&data->params[n];
+ (*shm)->size_req = params32[n].u.memref.size;
+ }
+}
+
+
+/*
+ * tee_open_session - invoke TEE to open a GP TEE session
+ */
+static int tz_open(struct tee_session *sess, struct tee_cmd *cmd)
+{
+ struct tee *tee;
+ struct tee_tz *ptee;
+ int ret = 0;
+
+ struct teesmc32_arg *arg32;
+ struct teesmc32_param *params32;
+ struct teesmc_meta_open_session *meta;
+ uintptr_t parg32;
+ uintptr_t pmeta;
+ size_t num_meta = 1;
+ uint8_t *ta;
+ TEEC_UUID *uuid;
+
+ BUG_ON(!sess->ctx->tee);
+ BUG_ON(!sess->ctx->tee->priv);
+ tee = sess->ctx->tee;
+ ptee = tee->priv;
+
+ if (cmd->uuid)
+ uuid = cmd->uuid->kaddr;
+ else
+ uuid = NULL;
+
+ dev_dbg(tee->dev, "> ta kaddr %p, uuid=%08x-%04x-%04x\n",
+ (cmd->ta) ? cmd->ta->kaddr : NULL,
+ ((uuid) ? uuid->timeLow : 0xDEAD),
+ ((uuid) ? uuid->timeMid : 0xDEAD),
+ ((uuid) ? uuid->timeHiAndVersion : 0xDEAD));
+
+ if (!CAPABLE(ptee->tee)) {
+ dev_dbg(tee->dev, "< not capable\n");
+ return -EBUSY;
+ }
+
+ /* case ta binary is inside the open request */
+ ta = NULL;
+ if (cmd->ta)
+ ta = cmd->ta->kaddr;
+ if (ta)
+ num_meta++;
+
+ arg32 = alloc_tee_arg(ptee, &parg32, TEESMC32_GET_ARG_SIZE(
+ TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta));
+ meta = alloc_tee_arg(ptee, &pmeta, sizeof(*meta));
+
+ if ((arg32 == NULL) || (meta == NULL)) {
+ free_tee_arg(ptee, parg32);
+ free_tee_arg(ptee, pmeta);
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ }
+
+ memset(arg32, 0, sizeof(*arg32));
+ memset(meta, 0, sizeof(*meta));
+ arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta;
+ params32 = TEESMC32_GET_PARAMS(arg32);
+
+ arg32->cmd = TEESMC_CMD_OPEN_SESSION;
+
+ params32[0].u.memref.buf_ptr = pmeta;
+ params32[0].u.memref.size = sizeof(*meta);
+ params32[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
+ TEESMC_ATTR_META | get_cache_attrs(ptee);
+
+ if (ta) {
+ params32[1].u.memref.buf_ptr =
+ tee_shm_pool_v2p(DEV, ptee->shm_pool, cmd->ta->kaddr);
+ params32[1].u.memref.size = cmd->ta->size_req;
+ params32[1].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
+ TEESMC_ATTR_META | get_cache_attrs(ptee);
+ }
+
+ if (uuid != NULL)
+ memcpy(meta->uuid, uuid, TEESMC_UUID_LEN);
+ meta->clnt_login = 0; /* FIXME: is this reliable ? used ? */
+
+ params32 += num_meta;
+ set_params(ptee, params32, cmd->param.type, &cmd->param);
+
+ call_tee(ptee, parg32, arg32);
+
+ get_params(&cmd->param, params32);
+
+ if (arg32->ret != TEEC_ERROR_COMMUNICATION) {
+ sess->sessid = arg32->session;
+ cmd->err = arg32->ret;
+ cmd->origin = arg32->ret_origin;
+ } else
+ ret = -EBUSY;
+
+ free_tee_arg(ptee, parg32);
+ free_tee_arg(ptee, pmeta);
+
+ dev_dbg(DEV, "< %x:%d\n", arg32->ret, ret);
+ return ret;
+}
+
+/*
+ * tee_invoke_command - invoke TEE to invoke a GP TEE command
+ */
+static int tz_invoke(struct tee_session *sess, struct tee_cmd *cmd)
+{
+ struct tee *tee;
+ struct tee_tz *ptee;
+ int ret = 0;
+
+ struct teesmc32_arg *arg32;
+ uintptr_t parg32;
+ struct teesmc32_param *params32;
+
+ BUG_ON(!sess->ctx->tee);
+ BUG_ON(!sess->ctx->tee->priv);
+ tee = sess->ctx->tee;
+ ptee = tee->priv;
+
+ dev_dbg(DEV, "> sessid %x cmd %x type %x\n",
+ sess->sessid, cmd->cmd, cmd->param.type);
+
+ if (!CAPABLE(tee)) {
+ dev_dbg(tee->dev, "< not capable\n");
+ return -EBUSY;
+ }
+
+ arg32 = (typeof(arg32))alloc_tee_arg(ptee, &parg32,
+ TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT));
+ if (!arg32) {
+ free_tee_arg(ptee, parg32);
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ }
+
+ memset(arg32, 0, sizeof(*arg32));
+ arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
+ params32 = TEESMC32_GET_PARAMS(arg32);
+
+ arg32->cmd = TEESMC_CMD_INVOKE_COMMAND;
+ arg32->session = sess->sessid;
+ arg32->ta_func = cmd->cmd;
+
+ set_params(ptee, params32, cmd->param.type, &cmd->param);
+
+ call_tee(ptee, parg32, arg32);
+
+ get_params(&cmd->param, params32);
+
+ if (arg32->ret != TEEC_ERROR_COMMUNICATION) {
+ cmd->err = arg32->ret;
+ cmd->origin = arg32->ret_origin;
+ } else
+ ret = -EBUSY;
+
+ free_tee_arg(ptee, parg32);
+
+ dev_dbg(DEV, "< %x:%d\n", arg32->ret, ret);
+ return ret;
+}
+
+/*
+ * tee_cancel_command - invoke TEE to cancel a GP TEE command
+ */
+static int tz_cancel(struct tee_session *sess, struct tee_cmd *cmd)
+{
+ struct tee *tee;
+ struct tee_tz *ptee;
+ int ret = 0;
+
+ struct teesmc32_arg *arg32;
+ uintptr_t parg32;
+
+ BUG_ON(!sess->ctx->tee);
+ BUG_ON(!sess->ctx->tee->priv);
+ tee = sess->ctx->tee;
+ ptee = tee->priv;
+
+ dev_dbg(DEV, "cancel on sessid=%08x\n", sess->sessid);
+
+ arg32 = alloc_tee_arg(ptee, &parg32, TEESMC32_GET_ARG_SIZE(0));
+ if (arg32 == NULL) {
+ free_tee_arg(ptee, parg32);
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ }
+
+ memset(arg32, 0, sizeof(*arg32));
+ arg32->cmd = TEESMC_CMD_CANCEL;
+ arg32->session = sess->sessid;
+
+ call_tee(ptee, parg32, arg32);
+
+ if (arg32->ret == TEEC_ERROR_COMMUNICATION)
+ ret = -EBUSY;
+
+ free_tee_arg(ptee, parg32);
+
+ dev_dbg(DEV, "< %x:%d\n", arg32->ret, ret);
+ return ret;
+}
+
+/*
+ * tee_close_session - invoke TEE to close a GP TEE session
+ */
+static int tz_close(struct tee_session *sess)
+{
+ struct tee *tee;
+ struct tee_tz *ptee;
+ int ret = 0;
+
+ struct teesmc32_arg *arg32;
+ uintptr_t parg32;
+
+ BUG_ON(!sess->ctx->tee);
+ BUG_ON(!sess->ctx->tee->priv);
+ tee = sess->ctx->tee;
+ ptee = tee->priv;
+
+ dev_dbg(DEV, "close on sessid=%08x\n", sess->sessid);
+
+ if (!CAPABLE(tee)) {
+ dev_dbg(tee->dev, "< not capable\n");
+ return -EBUSY;
+ }
+
+ arg32 = alloc_tee_arg(ptee, &parg32, TEESMC32_GET_ARG_SIZE(0));
+ if (arg32 == NULL) {
+ free_tee_arg(ptee, parg32);
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ }
+
+ dev_dbg(DEV, "> [%x]\n", sess->sessid);
+
+ memset(arg32, 0, sizeof(*arg32));
+ arg32->cmd = TEESMC_CMD_CLOSE_SESSION;
+ arg32->session = sess->sessid;
+
+ call_tee(ptee, parg32, arg32);
+
+ if (arg32->ret == TEEC_ERROR_COMMUNICATION)
+ ret = -EBUSY;
+
+ free_tee_arg(ptee, parg32);
+
+ dev_dbg(DEV, "< %x:%d\n", arg32->ret, ret);
+ return ret;
+}
+
+static struct tee_shm *tz_alloc(struct tee *tee, size_t size, uint32_t flags)
+{
+ struct tee_shm *shm = NULL;
+ struct tee_tz *ptee;
+ size_t size_aligned;
+ BUG_ON(!tee->priv);
+ ptee = tee->priv;
+
+ dev_dbg(DEV, "%s: s=%d,flags=0x%08x\n", __func__, (int)size, flags);
+
+/* comment due to #6357
+ * if ( (flags & ~(tee->shm_flags | TEE_SHM_MAPPED
+ * | TEE_SHM_TEMP | TEE_SHM_FROM_RPC)) != 0 ) {
+ dev_err(tee->dev, "%s: flag parameter is invalid\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }*/
+
+ size_aligned = ((size / SZ_4K) + 1) * SZ_4K;
+ if (unlikely(size_aligned == 0)) {
+ dev_err(DEV, "[%s] requested size too big\n", __func__);
+ return NULL;
+ }
+
+ shm = devm_kzalloc(tee->dev, sizeof(struct tee_shm), GFP_KERNEL);
+ if (!shm) {
+ dev_err(tee->dev, "%s: kzalloc failed\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ shm->size_alloc = ((size / SZ_4K) + 1) * SZ_4K;
+ shm->size_req = size;
+ shm->paddr = tee_shm_pool_alloc(tee->dev, ptee->shm_pool,
+ shm->size_alloc, ALLOC_ALIGN);
+ if (!shm->paddr) {
+ dev_err(tee->dev, "%s: cannot alloc memory, size 0x%lx\n",
+ __func__, (unsigned long)shm->size_alloc);
+ devm_kfree(tee->dev, shm);
+ return ERR_PTR(-ENOMEM);
+ }
+ shm->kaddr = tee_shm_pool_p2v(tee->dev, ptee->shm_pool, shm->paddr);
+ if (!shm->kaddr) {
+ dev_err(tee->dev, "%s: p2v(%p)=0\n", __func__,
+ (void *)shm->paddr);
+ tee_shm_pool_free(tee->dev, ptee->shm_pool, shm->paddr, NULL);
+ devm_kfree(tee->dev, shm);
+ return ERR_PTR(-EFAULT);
+ }
+ shm->flags = flags;
+ if (ptee->shm_cached)
+ shm->flags |= TEE_SHM_CACHED;
+
+ dev_dbg(tee->dev, "%s: kaddr=%p, paddr=%p, shm=%p, size %x:%x\n",
+ __func__, shm->kaddr, (void *)shm->paddr, shm,
+ (unsigned int)shm->size_req, (unsigned int)shm->size_alloc);
+
+ return shm;
+}
+
+static void tz_free(struct tee_shm *shm)
+{
+ size_t size;
+ int ret;
+ struct tee *tee;
+ struct tee_tz *ptee;
+
+ BUG_ON(!shm->tee);
+ BUG_ON(!shm->tee->priv);
+ tee = shm->tee;
+ ptee = tee->priv;
+
+ dev_dbg(tee->dev, "%s: shm=%p\n", __func__, shm);
+
+ ret = tee_shm_pool_free(tee->dev, ptee->shm_pool, shm->paddr, &size);
+ if (!ret) {
+ devm_kfree(tee->dev, shm);
+ shm = NULL;
+ }
+}
+
+static int tz_shm_inc_ref(struct tee_shm *shm)
+{
+ struct tee *tee;
+ struct tee_tz *ptee;
+
+ BUG_ON(!shm->tee);
+ BUG_ON(!shm->tee->priv);
+ tee = shm->tee;
+ ptee = tee->priv;
+
+ return tee_shm_pool_incref(tee->dev, ptee->shm_pool, shm->paddr);
+}
+
+/******************************************************************************/
+/*
+static void tee_get_status(struct tee_tz *ptee)
+{
+ TEEC_Result ret;
+ struct tee_msg_send *arg;
+ struct tee_core_status_out *res;
+ unsigned long parg, pres;
+
+ if (!CAPABLE(ptee->tee))
+ return;
+
+ arg = (typeof(arg))alloc_tee_arg(ptee, &parg, sizeof(*arg));
+ res = (typeof(res))alloc_tee_arg(ptee, &pres, sizeof(*res));
+
+ if ((arg == NULL) || (res == NULL)) {
+ dev_err(DEV, "TZ outercache mutex error: alloc shm failed\n");
+ goto out;
+ }
+
+ memset(arg, 0, sizeof(*arg));
+ memset(res, 0, sizeof(*res));
+ arg->service = ISSWAPI_TEE_GET_CORE_STATUS;
+ ret = send_and_wait(ptee, ISSWAPI_TEE_GET_CORE_STATUS, SEC_ROM_DEFAULT,
+ parg, pres);
+ if (ret != TEEC_SUCCESS) {
+ dev_warn(DEV, "get statuc failed\n");
+ goto out;
+ }
+
+ pr_info("TEETZ Firmware status:\n");
+ pr_info("%s", res->raw);
+
+out:
+ free_tee_arg(ptee, parg);
+ free_tee_arg(ptee, pres);
+}*/
+
+#ifdef CONFIG_OUTER_CACHE
+/*
+ * Synchronised outer cache maintenance support
+ */
+#ifndef CONFIG_ARM_TZ_SUPPORT
+/* weak outer_tz_mutex in case not supported by kernel */
+bool __weak outer_tz_mutex(unsigned long *p)
+{
+ pr_err("weak outer_tz_mutex");
+ if (p != NULL)
+ return false;
+ return true;
+}
+#endif
+
+/* register_outercache_mutex - Negotiate/Disable outer cache shared mutex */
+static int register_outercache_mutex(struct tee_tz *ptee, bool reg)
+{
+ unsigned long *vaddr = NULL;
+ int ret = 0;
+ struct smc_param param;
+ uintptr_t paddr = 0;
+
+ dev_dbg(ptee->tee->dev, ">\n");
+ BUG_ON(!CAPABLE(ptee->tee));
+
+ if ((reg == true) && (ptee->tz_outer_cache_mutex != NULL)) {
+ dev_err(DEV, "outer cache shared mutex already registered\n");
+ return -EINVAL;
+ }
+ if ((reg == false) && (ptee->tz_outer_cache_mutex == NULL))
+ return 0;
+
+ mutex_lock(&ptee->mutex);
+
+ if (reg == false) {
+ vaddr = ptee->tz_outer_cache_mutex;
+ ptee->tz_outer_cache_mutex = NULL;
+ goto out;
+ }
+
+ memset(&param, 0, sizeof(param));
+ param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
+ param.a1 = TEESMC_ST_L2CC_MUTEX_GET_ADDR;
+ tee_smc_call(&param);
+
+ if (param.a0 != TEESMC_RETURN_OK) {
+ dev_warn(DEV, "no TZ l2cc mutex service supported\n");
+ goto out;
+ }
+ paddr = param.a2;
+ dev_dbg(DEV, "outer cache shared mutex paddr 0x%lx\n", paddr);
+
+ vaddr = ioremap_cache(paddr, sizeof(u32));
+ if (vaddr == NULL) {
+ dev_warn(DEV, "TZ l2cc mutex disabled: ioremap failed\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ dev_dbg(DEV, "outer cache shared mutex vaddr %p\n", vaddr);
+ if (outer_tz_mutex(vaddr) == false) {
+ dev_warn(DEV, "TZ l2cc mutex disabled: outer cache refused\n");
+ goto out;
+ }
+
+ memset(&param, 0, sizeof(param));
+ param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
+ param.a1 = TEESMC_ST_L2CC_MUTEX_ENABLE;
+ tee_smc_call(&param);
+
+ if (param.a0 != TEESMC_RETURN_OK) {
+
+ dev_warn(DEV, "TZ l2cc mutex disabled: TZ enable failed\n");
+ goto out;
+ }
+ ptee->tz_outer_cache_mutex = vaddr;
+
+out:
+ if (ptee->tz_outer_cache_mutex == NULL) {
+ memset(&param, 0, sizeof(param));
+ param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
+ param.a1 = TEESMC_ST_L2CC_MUTEX_DISABLE;
+ tee_smc_call(&param);
+ outer_tz_mutex(NULL);
+ if (vaddr)
+ iounmap(vaddr);
+ dev_dbg(DEV, "outer cache shared mutex disabled\n");
+ }
+
+ mutex_unlock(&ptee->mutex);
+ dev_dbg(DEV, "< teetz outer mutex: ret=%d pa=0x%lX va=0x%p %sabled\n",
+ ret, paddr, vaddr, ptee->tz_outer_cache_mutex ? "en" : "dis");
+ return ret;
+}
+#endif
+
+/* configure_shm - Negotiate Shared Memory configuration with teetz. */
+static int configure_shm(struct tee_tz *ptee)
+{
+ struct smc_param param = { 0 };
+ size_t shm_size = -1;
+ int ret = 0;
+
+ dev_dbg(DEV, ">\n");
+ BUG_ON(!CAPABLE(ptee->tee));
+
+ mutex_lock(&ptee->mutex);
+ param.a0 = TEESMC32_ST_FASTCALL_GET_SHM_CONFIG;
+ tee_smc_call(&param);
+ mutex_unlock(&ptee->mutex);
+
+ if (param.a0 != TEESMC_RETURN_OK) {
+ dev_err(DEV, "shm service not available: %X", (uint)param.a0);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ptee->shm_paddr = param.a1;
+ shm_size = param.a2;
+ ptee->shm_cached = (bool)param.a3;
+
+ if (ptee->shm_cached)
+ ptee->shm_vaddr = ioremap_cache(ptee->shm_paddr, shm_size);
+ else
+ ptee->shm_vaddr = ioremap_nocache(ptee->shm_paddr, shm_size);
+
+ if (ptee->shm_vaddr == NULL) {
+ dev_err(DEV, "shm ioremap failed\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ptee->shm_pool = tee_shm_pool_create(DEV, shm_size,
+ ptee->shm_vaddr, ptee->shm_paddr);
+
+ if (!ptee->shm_pool) {
+ dev_err(DEV, "shm pool creation failed (%zu)", shm_size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ptee->shm_cached)
+ tee_shm_pool_set_cached(ptee->shm_pool);
+out:
+ dev_dbg(DEV, "< ret=%d pa=0x%lX va=0x%p size=%zu, %scached",
+ ret, ptee->shm_paddr, ptee->shm_vaddr, shm_size,
+ (ptee->shm_cached == 1) ? "" : "un");
+ return ret;
+}
+
+
+/******************************************************************************/
+
+static int tz_start(struct tee *tee)
+{
+ struct tee_tz *ptee;
+ int ret;
+
+ BUG_ON(!tee || !tee->priv);
+ dev_dbg(tee->dev, ">\n");
+ if (!CAPABLE(tee)) {
+ dev_dbg(tee->dev, "< not capable\n");
+ return -EBUSY;
+ }
+
+ ptee = tee->priv;
+ BUG_ON(ptee->started);
+ ptee->started = true;
+
+ ret = configure_shm(ptee);
+ if (ret)
+ goto exit;
+
+
+#ifdef CONFIG_OUTER_CACHE
+ ret = register_outercache_mutex(ptee, true);
+ if (ret)
+ goto exit;
+#endif
+
+exit:
+ if (ret)
+ ptee->started = false;
+
+ dev_dbg(tee->dev, "< ret=%d dev=%s\n", ret, tee->name);
+ return ret;
+}
+
+static int tz_stop(struct tee *tee)
+{
+ struct tee_tz *ptee;
+
+ BUG_ON(!tee || !tee->priv);
+
+ ptee = tee->priv;
+
+ dev_dbg(tee->dev, "> dev=%s\n", tee->name);
+ if (!CAPABLE(tee)) {
+ dev_dbg(tee->dev, "< not capable\n");
+ return -EBUSY;
+ }
+
+#ifdef CONFIG_OUTER_CACHE
+ register_outercache_mutex(ptee, false);
+#endif
+ tee_shm_pool_destroy(tee->dev, ptee->shm_pool);
+ iounmap(ptee->shm_vaddr);
+ ptee->started = false;
+
+ dev_dbg(tee->dev, "< ret=0 dev=%s\n", tee->name);
+ return 0;
+}
+
+/******************************************************************************/
+
+const struct tee_ops tee_fops = {
+ .type = "tz",
+ .owner = THIS_MODULE,
+ .start = tz_start,
+ .stop = tz_stop,
+ .invoke = tz_invoke,
+ .cancel = tz_cancel,
+ .open = tz_open,
+ .close = tz_close,
+ .alloc = tz_alloc,
+ .free = tz_free,
+ .shm_inc_ref = tz_shm_inc_ref,
+};
+
+static int tz_tee_init(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ struct tee *tee = platform_get_drvdata(pdev);
+ struct tee_tz *ptee = tee->priv;
+
+ tee_tz = ptee;
+
+#if 0
+ /* To replace by a syscall */
+#ifndef CONFIG_ARM_TZ_SUPPORT
+ dev_err(tee->dev,
+ "%s: dev=%s, TZ fw is not loaded: TEE TZ is not supported.\n",
+ __func__, tee->name);
+ tee->conf = TEE_CONF_FW_NOT_CAPABLE;
+ return 0;
+#endif
+#endif
+
+ tee->shm_flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
+ tee->test = 0;
+
+ ptee->started = false;
+ ptee->sess_id = 0xAB000000;
+ mutex_init(&ptee->mutex);
+ init_completion(&ptee->c);
+ ptee->c_waiters = 0;
+
+ ret = tee_mutex_wait_init(&ptee->mutex_wait);
+
+ if (ret)
+ dev_err(tee->dev, "%s: dev=%s, Secure armv7 failed (%d)\n",
+ __func__, tee->name, ret);
+ else
+ dev_dbg(tee->dev, "%s: dev=%s, Secure armv7\n",
+ __func__, tee->name);
+ return ret;
+}
+
+static void tz_tee_deinit(struct platform_device *pdev)
+{
+ struct tee *tee = platform_get_drvdata(pdev);
+ struct tee_tz *ptee = tee->priv;
+
+ if (!CAPABLE(tee))
+ return;
+
+ tee_mutex_wait_exit(&ptee->mutex_wait);
+
+ dev_dbg(tee->dev, "%s: dev=%s, Secure armv7 started=%d\n", __func__,
+ tee->name, ptee->started);
+
+ return;
+}
+
+static int tz_tee_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct device *dev = &pdev->dev;
+ struct tee *tee;
+ struct tee_tz *ptee;
+
+ pr_info("%s: name=\"%s\", id=%d, pdev_name=\"%s\"\n", __func__,
+ pdev->name, pdev->id, dev_name(dev));
+#ifdef _TEE_DEBUG
+ pr_debug("- dev=%p\n", dev);
+ pr_debug("- dev->parent=%p\n", dev->ctx);
+ pr_debug("- dev->driver=%p\n", dev->driver);
+#endif
+
+ tee = tee_core_alloc(dev, _TEE_TZ_NAME, pdev->id, &tee_fops,
+ sizeof(struct tee_tz));
+ if (!tee)
+ return -ENOMEM;
+
+ ptee = tee->priv;
+ ptee->tee = tee;
+
+ platform_set_drvdata(pdev, tee);
+
+ ret = tz_tee_init(pdev);
+ if (ret)
+ goto bail1;
+
+ ret = tee_core_add(tee);
+ if (ret)
+ goto bail0;
+
+#ifdef _TEE_DEBUG
+ pr_debug("- tee=%p, id=%d, iminor=%d\n", tee, tee->id,
+ tee->miscdev.minor);
+#endif
+ return 0;
+
+bail1:
+ tz_tee_deinit(pdev);
+bail0:
+ return ret;
+}
+
+static int tz_tee_remove(struct platform_device *pdev)
+{
+ struct tee *tee = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+ /*struct tee_tz *ptee;*/
+
+ pr_info("%s: name=\"%s\", id=%d, pdev_name=\"%s\"\n", __func__,
+ pdev->name, pdev->id, dev_name(dev));
+#ifdef _TEE_DEBUG
+ pr_debug("- tee=%p, id=%d, iminor=%d, name=%s\n",
+ tee, tee->id, tee->miscdev.minor, tee->name);
+#endif
+
+/* ptee = tee->priv;
+ tee_get_status(ptee);*/
+
+ tz_tee_deinit(pdev);
+ tee_core_del(tee);
+ return 0;
+}
+
+static struct of_device_id tz_tee_match[] = {
+ {
+ .compatible = "stm,armv7sec",
+ },
+ {},
+};
+
+static struct platform_driver tz_tee_driver = {
+ .probe = tz_tee_probe,
+ .remove = tz_tee_remove,
+ .driver = {
+ .name = "armv7sec",
+ .owner = THIS_MODULE,
+ .of_match_table = tz_tee_match,
+ },
+};
+
+static struct platform_device tz_0_plt_device = {
+ .name = "armv7sec",
+ .id = 0,
+ .dev = {
+/* .platform_data = tz_0_tee_data,*/
+ },
+};
+
+static int __init tee_tz_init(void)
+{
+ int rc;
+
+ pr_info("TEE armv7 Driver initialization\n");
+
+#ifdef _TEE_DEBUG
+ pr_debug("- Register the platform_driver \"%s\" %p\n",
+ tz_tee_driver.driver.name, &tz_tee_driver.driver);
+#endif
+
+ rc = platform_driver_register(&tz_tee_driver);
+ if (rc != 0) {
+ pr_err("failed to register the platform driver (rc=%d)\n", rc);
+ goto bail0;
+ }
+
+ rc = platform_device_register(&tz_0_plt_device);
+ if (rc != 0) {
+ pr_err("failed to register the platform devices 0 (rc=%d)\n",
+ rc);
+ goto bail1;
+ }
+
+ return rc;
+
+bail1:
+ platform_driver_unregister(&tz_tee_driver);
+bail0:
+ return rc;
+}
+
+static void __exit tee_tz_exit(void)
+{
+ pr_info("TEE ARMV7 Driver de-initialization\n");
+
+ platform_device_unregister(&tz_0_plt_device);
+ platform_driver_unregister(&tz_tee_driver);
+}
+
+module_init(tee_tz_init);
+module_exit(tee_tz_exit);
+
+MODULE_AUTHOR("STMicroelectronics");
+MODULE_DESCRIPTION("STM Secure TEE ARMV7 TZ driver");
+MODULE_SUPPORTED_DEVICE("");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
diff --git a/armtz/tee_tz_op.h b/armtz/tee_tz_op.h
new file mode 100644
index 0000000..d260b61
--- /dev/null
+++ b/armtz/tee_tz_op.h
@@ -0,0 +1,259 @@
+
+#ifndef __TEE_ARMV7_OP_H__
+#define __TEE_ARMV7_OP_H__
+
+enum t_issw_service_id {
+ /*
+ * ("SSAPI_PRE_INIT_SERV")
+ */
+ SSAPI_PRE_INIT_SERV = 1,
+
+ /*
+ * ("SSAPI_POST_SPEEDUP_INIT_SERV")
+ * Reserved, Not used
+ */
+ SSAPI_POST_SPEEDUP_INIT_SERV = 2,
+
+ /*
+ * ("SSAPI_ISSW_IMPORT_SERV")
+ */
+ SSAPI_ISSW_IMPORT_SERV = 3,
+
+ /*
+ * ("SSAPI_RET_FROM_INT_SERV")
+ */
+ SSAPI_RET_FROM_INT_SERV = 4,
+
+ /*
+ * ("SSAPI_RET_FROM_RPC_SERV")
+ */
+ SSAPI_RET_FROM_RPC_SERV = 5,
+
+ /*
+ * "ISSWAPI_ISSW_EXECUTE_SERV" is linked to ROM code
+ * ("SSAPI_ISSW_EXECUTE_SERV")
+ */
+ ISSWAPI_ISSW_EXECUTE_SERV = 6,
+ ISSWAPI_PROT_APPL_MSG_SEND = 0x10000000,
+ ISSWAPI_EXTERNAL_CODE_CHECK = 0x10000001,
+ ISSWAPI_SECURE_LOAD = 0x10000002,
+ ISSWAPI_ISSW_REIMPORT_PUB_KEYS = 0x10000003,
+
+ /* Accessible only on request */
+ ISSWAPI_WRITE_L2CC = 0x10000004,
+ ISSWAPI_WRITE_CP15_SCTLR = 0x10000005,
+ ISSWAPI_READ_CP15_SCTLR = 0x10000006,
+ ISSWAPI_WRITE_CP15_ACTLR = 0x10000007,
+ ISSWAPI_READ_CP15_ACTLR = 0x10000008,
+ ISSWAPI_WRITE_CP15_DIAGR = 0x10000009,
+ ISSWAPI_READ_CP15_DIAGR = 0x1000000A,
+
+ ISSWAPI_EXECUTE_TA = 0x11000001,
+ ISSWAPI_CLOSE_TA = 0x11000002,
+ ISSWAPI_FLUSH_BOOT_CODE = 0x11000003,
+ /* Generic, restricted to be used by u-boot */
+ ISSWAPI_VERIFY_SIGNED_HEADER = 0x11000005,
+ ISSWAPI_VERIFY_HASH = 0x11000006,
+ /* 8500 only, restricted to be used by u-boot */
+ ISSWAPI_GET_RT_FLAGS = 0x11000007,
+
+ /* For TEE Client API 1.0 */
+ ISSWAPI_TEEC_OPEN_SESSION = 0x11000008,
+ ISSWAPI_TEEC_CLOSE_SESSION = 0x11000009,
+ ISSWAPI_TEEC_INVOKE_COMMAND = 0x1100000a,
+ ISSWAPI_REGISTER_RPC = 0x1100000b, /* this is NOT a GP TEE API ! */
+ ISSWAPI_SET_SEC_DDR = 0x1100000c, /* this is NOT a GP TEE API ! */
+ ISSWAPI_TEEC_CANCEL_COMMAND = 0x1100000d,
+ ISSWAPI_TEEC_REGISTER_MEMORY = 0x1100000e,
+ ISSWAPI_TEEC_UNREGISTER_MEMORY = 0x1100000f,
+
+ /* Internal command */
+ ISSWAPI_TEE_DEINIT_CPU = 0x11000010,
+ ISSWAPI_TEE_CRASH_CPU = 0x11000011,
+ ISSWAPI_TEE_SET_CORE_TRACE_LEVEL = 0x11000012,
+ ISSWAPI_TEE_GET_CORE_TRACE_LEVEL = 0x11000013,
+ ISSWAPI_TEE_SET_TA_TRACE_LEVEL = 0x11000014,
+ ISSWAPI_TEE_GET_TA_TRACE_LEVEL = 0x11000015,
+ ISSWAPI_TEE_GET_CORE_STATUS = 0x11000016,
+ ISSWAPI_TEE_FLUSH_CACHE = 0x11000017,
+
+ ISSWAPI_REGISTER_DEF_SHM = 0x11000020,
+ ISSWAPI_UNREGISTER_DEF_SHM = 0x11000021,
+ ISSWAPI_REGISTER_IRQFWD = 0x11000022,
+ ISSWAPI_UNREGISTER_IRQFWD = 0x11000023,
+ ISSWAPI_GET_SHM_START = 0x11000024,
+ ISSWAPI_GET_SHM_SIZE = 0x11000025,
+ ISSWAPI_GET_SHM_CACHED = 0x11000026,
+
+ ISSWAPI_ENABLE_L2CC_MUTEX = 0x20000000,
+ ISSWAPI_DISABLE_L2CC_MUTEX = 0x20000001,
+ ISSWAPI_GET_L2CC_MUTEX = 0x20000002,
+ ISSWAPI_SET_L2CC_MUTEX = 0x20000003,
+
+ ISSWAPI_LOAD_TEE = 0x20000004,
+
+};
+
+/*
+ * tee_msg_send - generic part of the msg sent to the TEE
+ */
+struct tee_msg_send {
+ unsigned int service;
+};
+
+/*
+ * tee_msg_recv - default strcutre of TEE service output message
+ */
+struct tee_msg_recv {
+ int duration;
+ uint32_t res;
+ uint32_t origin;
+};
+
+/*
+ * tee_register_irqfwd_xxx - (un)register callback for interrupt forwarding
+ */
+struct tee_register_irqfwd_send {
+ struct tee_msg_send header;
+ struct {
+ unsigned long cb;
+ } data;
+};
+struct tee_register_irqfwd_recv {
+ struct tee_msg_recv header;
+};
+
+/*
+ * tee_get_l2cc_mutex - input/output argument structures
+ */
+struct tee_get_l2cc_mutex_send {
+ struct tee_msg_send header;
+};
+struct tee_get_l2cc_mutex_recv {
+ struct tee_msg_recv header;
+ struct {
+ unsigned long paddr;
+ } data;
+};
+
+/**
+ * struct tee_identity - Represents the identity of the client
+ * @login: Login id
+ * @uuid: UUID as defined above
+ */
+struct tee_identity {
+ uint32_t login;
+ TEEC_UUID uuid;
+};
+
+/*
+ * tee_open_session_data - input arg structure for TEE open session service
+ */
+struct tee_open_session_data {
+ struct ta_signed_header_t *ta;
+ TEEC_UUID uuid;
+ uint32_t param_types;
+ TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+ struct tee_identity client_id;
+ uint32_t params_flags[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+};
+
+/*
+ * tee_open_session_send - input arg msg for TEE open session service
+ */
+struct tee_open_session_send {
+ struct tee_msg_send header;
+ struct tee_open_session_data data;
+};
+
+/*
+ * tee_open_session_recv - output arg structure for TEE open session service
+ */
+struct tee_open_session_recv {
+ struct tee_msg_recv header;
+ uint32_t sess;
+ TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+};
+
+/*
+ * tee_invoke_command_data - input arg structure for TEE invoke cmd service
+ */
+struct tee_invoke_command_data {
+ uint32_t sess;
+ uint32_t cmd;
+ uint32_t param_types;
+ TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+ uint32_t params_flags[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+};
+
+struct tee_invoke_command_send {
+ struct tee_msg_send header;
+ struct tee_invoke_command_data data;
+};
+
+/*
+ * tee_invoke_command_recv - output arg structure for TEE invoke cmd service
+ */
+struct tee_invoke_command_recv {
+ struct tee_msg_recv header;
+ TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+};
+
+/*
+ * tee_cancel_command_data - input arg structure for TEE cancel service
+ */
+struct tee_cancel_command_data {
+ uint32_t sess;
+};
+
+/*
+ * tee_cancel_command_send - input msg structure for TEE cancel service
+ */
+struct tee_cancel_command_send {
+ struct tee_msg_send header;
+ struct tee_cancel_command_data data;
+};
+
+/*
+ * tee_close_session_data - input arg structure for TEE close session service
+ */
+struct tee_close_session_data {
+ uint32_t sess;
+};
+
+/*
+ * tee_close_session_send - input arg msg for TEE close session service
+ */
+struct tee_close_session_send {
+ struct tee_msg_send header;
+ struct tee_close_session_data data;
+};
+
+/*
+ * tee_register_rpc_send_data - input arg structure for TEE register rpc service
+ */
+struct tee_register_rpc_send_data {
+ uint32_t fnk;
+ uint32_t bf;
+ uint32_t nbr_bf;
+};
+
+/*
+ * tee_register_rpc_send - input msg structure for TEE register rpc service
+ */
+struct tee_register_rpc_send {
+ struct tee_msg_send header;
+ struct tee_register_rpc_send_data data;
+};
+
+/*
+ * tee_core_status_out - output arg structure for TEE status service
+ */
+#define TEEC_STATUS_MSG_SIZE 80
+
+struct tee_core_status_out {
+ struct tee_msg_recv header;
+ char raw[TEEC_STATUS_MSG_SIZE];
+};
+
+#endif /* __TEE_ARMV7_OP_H__ */
diff --git a/armtz/tee_tz_priv.h b/armtz/tee_tz_priv.h
new file mode 100644
index 0000000..afcc8da
--- /dev/null
+++ b/armtz/tee_tz_priv.h
@@ -0,0 +1,52 @@
+
+#ifndef __TEE_TZ_PRIV__
+#define __TEE_TZ_PRIV__
+
+struct tee;
+struct shm_pool;
+struct tee_rpc_bf;
+
+#ifdef CONFIG_ARM
+struct smc_param {
+ uint32_t a0;
+ uint32_t a1;
+ uint32_t a2;
+ uint32_t a3;
+ uint32_t a4;
+ uint32_t a5;
+ uint32_t a6;
+ uint32_t a7;
+};
+#endif
+#ifdef CONFIG_ARM64
+struct smc_param {
+ uint64_t a0;
+ uint64_t a1;
+ uint64_t a2;
+ uint64_t a3;
+ uint64_t a4;
+ uint64_t a5;
+ uint64_t a6;
+ uint64_t a7;
+};
+#endif
+
+struct tee_tz {
+ uint32_t sess_id;
+ bool started;
+ struct tee *tee;
+ unsigned long shm_paddr;
+ void *shm_vaddr;
+ struct shm_pool *shm_pool;
+ struct mutex mutex;
+ struct completion c;
+ int c_waiters;
+ void *tz_outer_cache_mutex;
+ struct tee_rpc_bf *rpc_buffers;
+ bool shm_cached;
+ struct tee_mutex_wait_private mutex_wait;
+};
+
+int tee_smc_call(struct smc_param *param);
+
+#endif /* __TEE_TZ_PRIV__ */
diff --git a/core/Makefile b/core/Makefile
new file mode 100644
index 0000000..a9193fd
--- /dev/null
+++ b/core/Makefile
@@ -0,0 +1,32 @@
+CFG_TEE_CORE_CORE_TARGET := armv7
+
+#########################################################################
+# Set Internal Variables #
+# May be modified to match your setup #
+#########################################################################
+CFG_TEE_DRV_DEBUGFS?=0
+CFG_TEE_CORE_LOG_LEVEL?=2
+CFG_TEE_TA_LOG_LEVEL?=2
+
+ccflags-y+=-Werror
+ccflags-y+=-I$(M)/include/linux
+ccflags-y+=-I$(M)/include
+
+ccflags-y+=-DCFG_TEE_DRV_DEBUGFS=${CFG_TEE_DRV_DEBUGFS}
+ccflags-y+=-DCFG_TEE_CORE_LOG_LEVEL=${CFG_TEE_CORE_LOG_LEVEL}
+ccflags-y+=-DCFG_TEE_TA_LOG_LEVEL=${CFG_TEE_TA_LOG_LEVEL}
+
+obj-m += optee.o
+
+optee-objs:= \
+ tee_core.o \
+ tee_context.o \
+ tee_session.o \
+ tee_shm.o \
+ tee_supp_com.o \
+ tee_sysfs.o \
+ tee_debugfs.o \
+ tee_kernel_api.o \
+ tee_mutex_wait.o
+
+
diff --git a/core/arm64/tee_tz.c b/core/arm64/tee_tz.c
deleted file mode 100644
index df54a56..0000000
--- a/core/arm64/tee_tz.c
+++ /dev/null
@@ -1,989 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
-#include <linux/jiffies.h>
-
-#include <asm/pgtable.h>
-
-#include "tee-op.h"
-#include "tee_supp_com.h"
-#include "tee_mem.h"
-#include "tee_service.h"
-#include "tee_driver.h"
-#include "tee_debug.h"
-#include "tee_tz.h"
-#include <arm_common/teesmc.h>
-#include <arm_common/teesmc_st.h>
-#include "handle.h"
-
-#define DEV (tee_tz_miscdev.this_device)
-
-/* Shared Memory data (config loaded from secure world) */
-static unsigned long shm_paddr;
-static size_t shm_size;
-static bool shm_cached;
-static void *shm_vaddr;
-
-/* TZ shared mutex service */
-static void *tz_outer_cache_mutex;
-
-/* protect concurrent access to the tee-tz: inits, entry */
-static DEFINE_MUTEX(g_mutex_teez);
-
-static DEFINE_MUTEX(e_mutex_teez);
-static DECLARE_COMPLETION(e_comp_teez);
-static int e_num_waiters;
-
-/* device data */
-struct tee_driver tee_tz_data;
-static struct miscdevice tee_tz_miscdev;
-
-static bool tee_tz_ready;
-
-static struct handle_db shm_handle_db = HANDLE_DB_INITIALIZER;
-
-
-/*******************************************************************
- * Calling TEE
- *******************************************************************/
-
-static void e_lock_teez(void)
-{
- mutex_lock(&e_mutex_teez);
-}
-
-static void e_lock_wait_completion_teez(void)
-{
- /*
- * Release the lock until "something happens" and then reacquire it
- * again.
- *
- * This is needed when TEE returns "busy" and we need to try again
- * later.
- */
- e_num_waiters++;
- mutex_unlock(&e_mutex_teez);
- /*
- * Wait at most one second. Secure world is normally never busy
- * more than that so we should normally never timeout.
- */
- wait_for_completion_timeout(&e_comp_teez, HZ);
- mutex_lock(&e_mutex_teez);
- e_num_waiters--;
-}
-
-static void e_unlock_teez(void)
-{
- /*
- * If at least one thread is waiting for "something to happen" let
- * one thread know that "something has happened".
- */
- if (e_num_waiters)
- complete(&e_comp_teez);
- mutex_unlock(&e_mutex_teez);
-}
-
-static void handle_rpc_func_cmd_mutex_wait(struct teesmc32_arg *arg32)
-{
- struct teesmc32_param *params;
-
- if (arg32->num_params != 2)
- goto bad;
-
- params = TEESMC32_GET_PARAMS(arg32);
-
- if ((params[0].attr & TEESMC_ATTR_TYPE_MASK) !=
- TEESMC_ATTR_TYPE_VALUE_INPUT)
- goto bad;
- if ((params[1].attr & TEESMC_ATTR_TYPE_MASK) !=
- TEESMC_ATTR_TYPE_VALUE_INPUT)
- goto bad;
-
- switch (params[0].u.value.a) {
- case TEE_MUTEX_WAIT_SLEEP:
- tee_mutex_wait_sleep(DEV, params[1].u.value.a,
- params[1].u.value.b);
- break;
- case TEE_MUTEX_WAIT_WAKEUP:
- tee_mutex_wait_wakeup(DEV, params[1].u.value.a,
- params[1].u.value.b);
- break;
- case TEE_MUTEX_WAIT_DELETE:
- tee_mutex_wait_delete(DEV, params[1].u.value.a);
- break;
- default:
- goto bad;
- }
-
- arg32->ret = TEEC_SUCCESS;;
- return;
-bad:
- arg32->ret = TEEC_ERROR_BAD_PARAMETERS;
-}
-
-static void handle_rpc_func_cmd_wait(struct teesmc32_arg *arg32)
-{
- struct teesmc32_param *params;
- u32 msec_to_wait;
-
- if (arg32->num_params != 1)
- goto bad;
-
- params = TEESMC32_GET_PARAMS(arg32);
- msec_to_wait = params[0].u.value.a;
-
- /* set task's state to interruptible sleep */
- set_current_state(TASK_INTERRUPTIBLE);
-
- /* take a nap */
- schedule_timeout(msecs_to_jiffies(msec_to_wait));
-
- arg32->ret = TEEC_SUCCESS;;
- return;
-bad:
- arg32->ret = TEEC_ERROR_BAD_PARAMETERS;
-}
-
-static void handle_rpc_func_cmd_to_supplicant(struct teesmc32_arg *arg32)
-{
- struct teesmc32_param *params;
- struct tee_rpc_invoke inv;
- size_t n;
- uint32_t ret;
-
- if (arg32->num_params > TEE_RPC_BUFFER_NUMBER) {
- arg32->ret = TEEC_ERROR_GENERIC;
- return;
- }
-
- params = TEESMC32_GET_PARAMS(arg32);
-
- memset(&inv, 0, sizeof(inv));
- inv.cmd = arg32->cmd;
- /*
- * Set a suitable error code in case tee-supplicant
- * ignores the request.
- */
- inv.res = TEEC_ERROR_NOT_IMPLEMENTED;
- inv.nbr_bf = arg32->num_params;
- for (n = 0; n < arg32->num_params; n++) {
- inv.cmds[n].buffer =
- (void *)(uintptr_t)params[n].u.memref.buf_ptr;
- inv.cmds[n].size = params[n].u.memref.size;
- switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
- case TEESMC_ATTR_TYPE_VALUE_INPUT:
- case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
- case TEESMC_ATTR_TYPE_VALUE_INOUT:
- inv.cmds[n].type = TEE_RPC_VALUE;
- break;
- case TEESMC_ATTR_TYPE_MEMREF_INPUT:
- case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
- case TEESMC_ATTR_TYPE_MEMREF_INOUT:
- inv.cmds[n].type = TEE_RPC_BUFFER;
- break;
- default:
- arg32->ret = TEEC_ERROR_GENERIC;
- return;
- }
- }
-
- ret = tee_supp_cmd(&TZop, TEE_RPC_ICMD_INVOKE,
- &inv, sizeof(inv));
- if (ret == TEEC_RPC_OK)
- arg32->ret = inv.res;
-
- for (n = 0; n < arg32->num_params; n++) {
- switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
- case TEESMC_ATTR_TYPE_VALUE_INPUT:
- case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
- case TEESMC_ATTR_TYPE_VALUE_INOUT:
- case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
- case TEESMC_ATTR_TYPE_MEMREF_INOUT:
- /*
- * Allow supplicant to assign a new pointer
- * to an out-buffer. Needed when the
- * supplicant allocates a new buffer, for
- * instance when loading a TA.
- */
- params[n].u.memref.buf_ptr =
- (uint32_t)(uintptr_t)inv.cmds[n].buffer;
- params[n].u.memref.size = inv.cmds[n].size;
- break;
- default:
- break;
- }
- }
-}
-
-static void handle_rpc_func_cmd(u32 parg32)
-{
- struct teesmc32_arg *arg32;
-
- arg32 = tee_shm_pool_p2v(DEV, TZop.Allocator, parg32);
- if (!arg32)
- return;
-
- switch (arg32->cmd) {
- case TEE_RPC_MUTEX_WAIT:
- handle_rpc_func_cmd_mutex_wait(arg32);
- break;
- case TEE_RPC_WAIT:
- handle_rpc_func_cmd_wait(arg32);
- break;
- default:
- handle_rpc_func_cmd_to_supplicant(arg32);
- }
-}
-
-static u32 handle_rpc(struct smc_param64 *param)
-{
- switch (TEESMC_RETURN_GET_RPC_FUNC(param->a0)) {
- case TEESMC_RPC_FUNC_ALLOC_ARG:
- param->a1 = tee_shm_pool_alloc(DEV, TZop.Allocator,
- param->a1, 4);
- break;
- case TEESMC_RPC_FUNC_ALLOC_PAYLOAD:
- /* Can't support payload shared memory with this interface */
- param->a2 = 0;
- break;
- case TEESMC_RPC_FUNC_FREE_ARG:
- tee_shm_pool_free(DEV, TZop.Allocator, param->a1, 0);
- break;
- case TEESMC_RPC_FUNC_FREE_PAYLOAD:
- /* Can't support payload shared memory with this interface */
- break;
- case TEESMC_ST_RPC_FUNC_ALLOC_PAYLOAD:
- {
- struct tee_shm *shm;
- int cookie;
-
- shm = tee_shm_allocate(&TZop, 0, param->a1, 0);
- if (!shm) {
- param->a1 = 0;
- break;
- }
-
- cookie = handle_get(&shm_handle_db, shm);
- if (cookie < 0) {
- tee_shm_unallocate(shm);
- param->a1 = 0;
- break;
- }
- param->a1 = shm->paddr;
- param->a2 = cookie;
- break;
- }
- case TEESMC_ST_RPC_FUNC_FREE_PAYLOAD:
- if (param->a1) {
- struct tee_shm *shm;
-
- shm = handle_put(&shm_handle_db, param->a1);
- if (shm)
- tee_shm_unallocate(shm);
- }
- break;
- case TEESMC_RPC_FUNC_IRQ:
- break;
- case TEESMC_RPC_FUNC_CMD:
- handle_rpc_func_cmd(param->a1);
- break;
- default:
- dev_warn(DEV, "Unknown RPC func 0x%x\n",
- (u32)TEESMC_RETURN_GET_RPC_FUNC(param->a0));
- break;
- }
-
- if (irqs_disabled())
- return TEESMC32_FASTCALL_RETURN_FROM_RPC;
- else
- return TEESMC32_CALL_RETURN_FROM_RPC;
-}
-
-static void call_tee(uintptr_t parg32, struct teesmc32_arg *arg32)
-{
- u32 ret;
- u32 funcid;
- struct smc_param64 param = { 0 };
-
- /* Note that we're using TEESMC32 calls since OP-TEE is still 32bit */
- if (irqs_disabled())
- funcid = TEESMC32_FASTCALL_WITH_ARG;
- else
- funcid = TEESMC32_CALL_WITH_ARG;
-
- param.a1 = parg32;
- e_lock_teez();
- while (true) {
- param.a0 = funcid;
-
- tee_smc_call64(&param);
- ret = param.a0;
-
- if (ret == TEESMC_RETURN_EBUSY) {
- /*
- * Since secure world returned busy, release the
- * lock we had when entering this function and wait
- * for "something to happen" (something else to
- * exit from secure world and needed resources may
- * have become available).
- */
- e_lock_wait_completion_teez();
- } else if (TEESMC_RETURN_IS_RPC(ret)) {
- /* Process the RPC. */
- e_unlock_teez();
- funcid = handle_rpc(&param);
- e_lock_teez();
- } else {
- break;
- }
- }
- e_unlock_teez();
-
- switch (ret) {
- case TEESMC_RETURN_UNKNOWN_FUNCTION:
- arg32->ret = TEEC_ERROR_NOT_IMPLEMENTED;
- arg32->ret_origin = TEEC_ORIGIN_COMMS;
- break;
- case TEESMC_RETURN_OK:
- /* arg32->ret set by secure world */
- break;
- default:
- /* Should not happen */
- arg32->ret = TEEC_ERROR_COMMUNICATION;
- arg32->ret_origin = TEEC_ORIGIN_COMMS;
- break;
- }
-}
-
-/*******************************************************************
- * TEE service invoke formating
- *******************************************************************/
-
-/* allocate tee service argument buffer and return virtual address */
-static void *alloc_tee_arg(unsigned long *p, size_t l)
-{
- if ((p == NULL) || (l == 0))
- return NULL;
-
- /* assume a 4 bytes aligned is sufficient */
- *p = tee_shm_pool_alloc(DEV, TZop.Allocator, l, 4);
- if (*p == 0)
- return NULL;
-
- return tee_shm_pool_p2v(DEV, TZop.Allocator, *p);
-}
-
-/* free tee service argument buffer (from its physical address) */
-static void free_tee_arg(unsigned long p)
-{
- if (p)
- tee_shm_pool_free(DEV, TZop.Allocator, p, 0);
-}
-
-static uint32_t get_cache_attrs(void)
-{
- if (tee_shm_pool_is_cached(TZop.Allocator))
- return TEESMC_ATTR_CACHE_DEFAULT << TEESMC_ATTR_CACHE_SHIFT;
- else
- return 0;
-}
-
-static void set_params(
- struct teesmc32_param params32[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t param_types,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT])
-{
- size_t n;
-
- for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
- uint8_t a = TEEC_PARAM_TYPE_GET(param_types, n);
-
- if (a == TEEC_MEMREF_TEMP_INPUT ||
- a == TEEC_MEMREF_TEMP_OUTPUT ||
- a == TEEC_MEMREF_TEMP_INOUT)
- a |= get_cache_attrs();
-
- params32[n].attr = a;
- params32[n].u.value.a = params[n].a;
- params32[n].u.value.b = params[n].b;
- }
-}
-
-static void get_params(TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- struct teesmc32_param params32[TEEC_CONFIG_PAYLOAD_REF_COUNT])
-{
- size_t n;
-
- for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
- params[n].a = params32[n].u.value.a;
- params[n].b = params32[n].u.value.b;
- }
-}
-
-/*
- * tee_open_session - invoke TEE to open a GP TEE session
- */
-static TEEC_Result tee_open_session(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- uint32_t ta_cmd,
- uint32_t param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *origin)
-{
- TEEC_Result ret_tee;
- struct teesmc32_arg *arg32;
- uintptr_t parg32;
- struct teesmc32_param *params32;
- struct teesmc_meta_open_session *meta;
- uintptr_t pmeta;
- size_t num_meta = 1;
-
-
- dev_dbg(DEV, "> uuid=%08x-%04x-%04x\n",
- ((ts->uuid) ? ts->uuid->timeLow : 0xDEAD),
- ((ts->uuid) ? ts->uuid->timeMid : 0xDEAD),
- ((ts->uuid) ? ts->uuid->
- timeHiAndVersion : 0xDEAD));
-
- if (tee_tz_ready == false)
- return TEEC_ERROR_BUSY;
-
- if (ts->ta)
- num_meta++;
-
- arg32 = (typeof(arg32))alloc_tee_arg(&parg32, TEESMC32_GET_ARG_SIZE(
- TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta));
- meta = (typeof(meta))alloc_tee_arg(&pmeta, sizeof(*meta));
-
- if ((arg32 == NULL) || (meta == NULL)) {
- free_tee_arg(parg32);
- free_tee_arg(pmeta);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- memset(arg32, 0, sizeof(*arg32));
- memset(meta, 0, sizeof(*meta));
- arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta;
- params32 = TEESMC32_GET_PARAMS(arg32);
-
- arg32->cmd = TEESMC_CMD_OPEN_SESSION;
-
- params32[0].u.memref.buf_ptr = pmeta;
- params32[0].u.memref.size = sizeof(*meta);
- params32[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
- TEESMC_ATTR_META | get_cache_attrs();
-
- if (ts->ta != NULL) {
- params32[1].u.memref.buf_ptr =
- tee_shm_pool_v2p(DEV, TZop.Allocator, ts->ta);
- params32[1].u.memref.size = ts->tasize;
- params32[1].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
- TEESMC_ATTR_META | get_cache_attrs();
- }
-
- if (ts->uuid != NULL)
- memcpy(meta->uuid, ts->uuid, TEESMC_UUID_LEN);
- meta->clnt_login = ts->login;
-
- set_params(params32 + num_meta, param_type, params);
-
- call_tee(parg32, arg32);
-
- ts->id = arg32->session;
- ret_tee = arg32->ret;
- if (origin)
- *origin = arg32->ret_origin;
-
- get_params(params, params32 + num_meta);
-
- free_tee_arg(parg32);
- free_tee_arg(pmeta);
- dev_dbg(DEV, "< [%d]\n", ret_tee);
- return ret_tee;
-}
-
-/*
- * tee_invoke_command - invoke TEE to invoke a GP TEE command
- */
-static TEEC_Result tee_invoke_command(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- uint32_t ta_cmd,
- uint32_t param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *origin)
-{
- TEEC_Result ret_tee;
- struct teesmc32_arg *arg32;
- uintptr_t parg32;
- struct teesmc32_param *params32;
-
- dev_dbg(DEV, "> [0x%x] [%d]\n", ts->id, ta_cmd);
-
- arg32 = (typeof(arg32))alloc_tee_arg(&parg32,
- TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT));
- if (!arg32) {
- free_tee_arg(parg32);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- memset(arg32, 0, sizeof(*arg32));
- arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
- params32 = TEESMC32_GET_PARAMS(arg32);
-
- arg32->cmd = TEESMC_CMD_INVOKE_COMMAND;
- arg32->session = ts->id;
- arg32->ta_func = ta_cmd;
-
- set_params(params32, param_type, params);
-
- call_tee(parg32, arg32);
-
- ret_tee = arg32->ret;
-
- get_params(params, params32);
-
- if (origin)
- *origin = arg32->ret_origin;
-
- free_tee_arg(parg32);
- dev_dbg(DEV, "< [0x%x]\n", ret_tee);
- return ret_tee;
-}
-
-/*
- * tee_cancel_command - invoke TEE to cancel a GP TEE command
- */
-static TEEC_Result tee_cancel_command(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- uint32_t ta_cmd,
- uint32_t param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *origin)
-{
- TEEC_Result ret_tee = TEEC_SUCCESS;
- struct teesmc32_arg *arg32;
- uintptr_t parg32;
-
- arg32 = (typeof(arg32))alloc_tee_arg(&parg32, TEESMC32_GET_ARG_SIZE(0));
- if (arg32 == NULL) {
- free_tee_arg(parg32);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- dev_dbg(DEV, "> [0x%x] [%d] [%d]\n",
- ts->id, ta_cmd, mutex_is_locked(&g_mutex_teez));
-
- memset(arg32, 0, sizeof(*arg32));
- arg32->cmd = TEESMC_CMD_CANCEL;
- arg32->session = ts->id;
-
- call_tee(parg32, arg32);
-
- ret_tee = arg32->ret;
- if (origin)
- *origin = arg32->ret_origin;
-
- free_tee_arg(parg32);
- dev_dbg(DEV, "< [0x%x]\n", ret_tee);
- return ret_tee;
-}
-
-/*
- * tee_close_session - invoke TEE to close a GP TEE session
- */
-static TEEC_Result tee_close_session(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- u32 ta_cmd,
- u32 param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- u32 *origin)
-{
- TEEC_Result ret_tee;
- struct teesmc32_arg *arg32;
- uintptr_t parg32;
-
- arg32 = (typeof(arg32))alloc_tee_arg(&parg32, TEESMC32_GET_ARG_SIZE(0));
- if (arg32 == NULL) {
- free_tee_arg(parg32);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- dev_dbg(DEV, "> [0x%x]\n", ts->id);
-
- memset(arg32, 0, sizeof(*arg32));
- arg32->cmd = TEESMC_CMD_CLOSE_SESSION;
- arg32->session = ts->id;
-
- call_tee(parg32, arg32);
-
- ret_tee = arg32->ret;
- if (origin)
- *origin = arg32->ret_origin;
-
- free_tee_arg(parg32);
- dev_dbg(DEV, "< [0x%x]\n", ret_tee);
- return ret_tee;
-}
-
-/*
- * Synchronised L2 cache maintenance support
- */
-#ifndef CONFIG_ARM_TZ_SUPPORT
-/* weak outer_tz_mutex in case not supported by kernel */
-bool __weak outer_tz_mutex(unsigned long *p)
-{
- return !p;
-}
-#endif
-
-/* register_l2cc_mutex - Negotiate/Disable outer cache shared mutex */
-static int register_l2cc_mutex(bool reg)
-{
- unsigned long *vaddr = NULL;
- int ret = 0;
- struct smc_param64 param;
- uintptr_t paddr = 0;
-
- if ((reg == true) && (tz_outer_cache_mutex != NULL)) {
- dev_err(DEV, "outer cache shared mutex already registered\n");
- return -EINVAL;
- }
- if ((reg == false) && (tz_outer_cache_mutex == NULL))
- return 0;
-
- if (reg == false) {
- vaddr = tz_outer_cache_mutex;
- tz_outer_cache_mutex = NULL;
- goto out;
- }
-
- memset(&param, 0, sizeof(param));
- param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
- param.a1 = TEESMC_ST_L2CC_MUTEX_GET_ADDR;
- tee_smc_call64(&param);
-
- if (param.a0 != TEESMC_RETURN_OK) {
- dev_warn(DEV, "no TZ l2cc mutex service supported\n");
- goto out;
- }
- paddr = param.a2;
-
- vaddr = ioremap_cache(paddr, sizeof(u32));
- if (vaddr == NULL) {
- dev_warn(DEV, "TZ l2cc mutex disabled: ioremap failed\n");
- ret = -ENOMEM;
- goto out;
- }
-
- if (outer_tz_mutex(vaddr) == false) {
- dev_warn(DEV, "TZ l2cc mutex disabled: outer cache refused\n");
- goto out;
- }
-
- memset(&param, 0, sizeof(param));
- param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
- param.a1 = TEESMC_ST_L2CC_MUTEX_ENABLE;
- tee_smc_call64(&param);
-
- if (param.a0 != TEESMC_RETURN_OK) {
- dev_warn(DEV, "TZ l2cc mutex disabled: TZ enable failed\n");
- goto out;
- }
- tz_outer_cache_mutex = vaddr;
-
-out:
- if (tz_outer_cache_mutex == NULL) {
- memset(&param, 0, sizeof(param));
- param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
- param.a1 = TEESMC_ST_L2CC_MUTEX_DISABLE;
- tee_smc_call64(&param);
- outer_tz_mutex(NULL);
- if (vaddr)
- iounmap(vaddr);
- dev_info(DEV, "outer cache shared mutex disabled\n");
- }
-
- dev_dbg(DEV, "teetz outer mutex: ret=%d pa=0x%lX va=0x%p %sabled\n",
- ret, paddr, vaddr, tz_outer_cache_mutex ? "en" : "dis");
- return ret;
-}
-
-/* configure_shm - Negotiate Shared Memory configuration with teetz. */
-static int configure_shm(void)
-{
- struct smc_param64 param = { 0 };
- int ret = 0;
-
- if (shm_paddr)
- return -EINVAL;
-
- param.a0 = TEESMC32_ST_FASTCALL_GET_SHM_CONFIG;
- tee_smc_call64(&param);
-
- if (param.a0 != TEESMC_RETURN_OK) {
- dev_err(DEV, "shm service not available: %X", (uint)param.a0);
- ret = -EINVAL;
- goto out;
- }
-
- shm_paddr = param.a1;
- shm_size = param.a2;
- shm_cached = (bool)param.a3;
-
- if (shm_cached)
- shm_vaddr = ioremap_cache(shm_paddr, shm_size);
- else
- shm_vaddr = ioremap_nocache(shm_paddr, shm_size);
-
- if (shm_vaddr == NULL) {
- dev_err(DEV, "shm ioremap failed\n");
- ret = -ENOMEM;
- goto out;
- }
-
- TZop.Allocator = tee_shm_pool_create(
- DEV, shm_size, shm_vaddr, shm_paddr);
-
- if (!TZop.Allocator) {
- dev_err(DEV, "shm pool creation failed (%zu)", shm_size);
- ret = -EINVAL;
- goto out;
- }
-
- if (shm_cached)
- tee_shm_pool_set_cached(TZop.Allocator);
-out:
- if (ret)
- shm_paddr = 0;
-
- dev_dbg(DEV, "teetz shm: ret=%d pa=0x%lX va=0x%p size=%zu, %scached",
- ret, shm_paddr, shm_vaddr, shm_size,
- shm_cached == 1 ? "" : "un");
- return ret;
-}
-/*
- * call_tz_sec_world - wrapper for invoking TEE services
- */
-static TEEC_Result call_tz_sec_world(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- u32 ta_cmd,
- u32 param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- u32 *origin)
-{
- int ret;
-
- switch (sec_cmd) {
-
- case CMD_TEEC_OPEN_SESSION:
- ret = tee_open_session(ts, sec_cmd, ta_cmd, param_type,
- params, origin);
- break;
-
- case CMD_TEEC_INVOKE_COMMAND:
- ret = tee_invoke_command(ts, sec_cmd, ta_cmd, param_type,
- params, origin);
- break;
-
- case CMD_TEEC_CANCEL_COMMAND:
- ret = tee_cancel_command(ts, sec_cmd, ta_cmd, param_type,
- params, origin);
- break;
-
- case CMD_TEEC_CLOSE_SESSION:
- ret = tee_close_session(ts, sec_cmd, ta_cmd, param_type,
- params, origin);
- break;
-
- case CMD_TEEC_REGISTER_MEMORY:
- case CMD_TEEC_UNREGISTER_MEMORY:
- ret = TEEC_SUCCESS;
- break; /* TODO: check if these shall be transfered to TEE */
-
- default:
- ret = TEEC_ERROR_BAD_PARAMETERS;
- }
-
- return ret;
-}
-
-static TEEC_Result TZ_register_shm(ulong paddr, ulong size, void **handle)
-{
- return TEEC_SUCCESS; /* nothing to do ? */
-}
-
-static TEEC_Result TZ_unregister_shm(void *handle)
-{
- return TEEC_SUCCESS; /* nothing to do ! */
-}
-
-static struct miscdevice tee_tz_miscdev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = TEE_TZ_NAME,
- .fops = &tee_fops,
-};
-
-struct tee_targetop TZop = {
- .miscdev = &tee_tz_miscdev,
- .call_sec_world = call_tz_sec_world,
- .register_shm = TZ_register_shm,
- .unregister_shm = TZ_unregister_shm,
- .page_size = SZ_4K, /* min size alignment */
- .Allocator = NULL,
-};
-
-/*******************************************************************
- * Starting TEE support
- *******************************************************************/
-
-static bool teesmc_api_uid_is_st(void)
-{
- struct smc_param64 param = { .a0 = TEESMC32_CALLS_UID };
-
- tee_smc_call64(&param);
-
- if (param.a0 == TEESMC_ST_UID_R0 && param.a1 == TEESMC_ST_UID_R1 &&
- param.a2 == TEESMC_ST_UID_R2 && (param.a3 == TEESMC_ST_UID32_R3 ||
- param.a3 == TEESMC_ST_UID64_R3))
- return true;
-
- return false;
-}
-
-static bool teesmc_os_uuid_is_optee(void)
-{
- struct smc_param64 param = { .a0 = TEESMC32_CALL_GET_OS_UUID };
-
- tee_smc_call64(&param);
-
- if (param.a0 == TEESMC_OS_OPTEE_UUID_R0 &&
- param.a1 == TEESMC_OS_OPTEE_UUID_R1 &&
- param.a2 == TEESMC_OS_OPTEE_UUID_R2 &&
- param.a3 == TEESMC_OS_OPTEE_UUID_R3)
- return true;
-
- return false;
-}
-
-static int start_tz_world(void)
-{
- int ret;
-
- /* allow SMC call, mutex will prevent any other access */
- mutex_lock(&g_mutex_teez);
- tee_tz_ready = true;
-
- /* Check that we're talking to the expected TEE */
- if (!teesmc_api_uid_is_st() || !teesmc_os_uuid_is_optee()) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = configure_shm();
- if (ret)
- goto out;
-
- ret = register_l2cc_mutex(true);
-
-out:
- if (ret)
- tee_tz_ready = false;
-
- mutex_unlock(&g_mutex_teez);
- return ret;
-}
-
-static void stop_tz_world(void)
-{
- mutex_lock(&g_mutex_teez);
- register_l2cc_mutex(false);
- tee_shm_pool_destroy(DEV, TZop.Allocator);
- iounmap(shm_vaddr);
- mutex_unlock(&g_mutex_teez);
-}
-
-/*******************************************************************
- * TEE TZ driver inits
- *******************************************************************/
-
-int __init tee_tz_init(void)
-{
- int ret;
-
- mutex_init(&tee_tz_data.mutex_tee);
-
- tee_tz_data.memory_pool = NULL;
-
- ret = misc_register(&tee_tz_miscdev);
- if (ret) {
- pr_err("Can't register tee_tz\n");
- goto exit;
- }
-
-#if (CFG_TEE_DRV_DEBUGFS == 1)
- ret = tee_debug_init(DEV);
- if (ret)
- goto err_deregister;
-#endif
-
- ret = start_tz_world();
- if (ret) {
- dev_err(DEV, "Can't start tee-tz\n");
- goto err_dbg;
- }
-
- return 0;
-
-err_dbg:
-#if (CFG_TEE_DRV_DEBUGFS == 1)
- tee_debug_remove(DEV);
-err_deregister:
-#endif
- misc_deregister(&tee_tz_miscdev);
-exit:
- /*
- * Temporary workaround: TEE TZ firmware may not be available.
- * In case TZ driver fails, just forbid access to TZ-TEE.
- */
- if (ret) {
- pr_err("TEE/TZ driver failed. It is now disabled.\n");
- ret = 0;
- }
- return ret;
-}
-
-void tee_tz_exit(void)
-{
- if (tee_tz_ready == false)
- return;
-
- stop_tz_world();
-#if (CFG_TEE_DRV_DEBUGFS == 1)
- tee_debug_remove(DEV);
-#endif
- misc_deregister(&tee_tz_miscdev);
-}
diff --git a/core/arm64/tee_tz.h b/core/arm64/tee_tz.h
deleted file mode 100644
index dce337b..0000000
--- a/core/arm64/tee_tz.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#ifndef TEE_TZ_H
-#define TEE_TZ_H
-
-struct smc_param64 {
- uint64_t a0;
- uint64_t a1;
- uint64_t a2;
- uint64_t a3;
- uint64_t a4;
- uint64_t a5;
- uint64_t a6;
- uint64_t a7;
-};
-
-int __init tee_tz_init(void);
-void tee_tz_exit(void);
-
-const char *tee_tz_get_memory_pool(void);
-int tee_smc_call64(struct smc_param64 *param);
-
-extern struct tee_driver tee_tz_data;
-extern struct tee_targetop TZop;
-
-#endif /* TEE_TZ_H */
-
diff --git a/core/arm64/tee_tz_debug.c b/core/arm64/tee_tz_debug.c
deleted file mode 100644
index e740e68..0000000
--- a/core/arm64/tee_tz_debug.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/device.h>
-
-#include "tee-op.h"
-#include "tee_driver.h"
-#include "tee_debug.h"
-#include "tee_tz.h"
-
-static const char STR_CMD_HIST[] = "hist";
-static const char STR_CMD_HIST_HELP[] = "cmd";
-static const char STR_DUMP_ALLOCATOR[] = "dump";
-static const char STR_DUMP_ALLOCATOR_HELP[] = "shared memory";
-
-/*****************************************************************************/
-
-static ssize_t tee_write_file_settings_tz(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct device *dev = file->private_data;
- char *buf;
- char *str;
- int val;
-
- buf = devm_kzalloc(dev, count, GFP_KERNEL);
- if (!buf) {
- dev_err(dev, "can't allocate work buffer\n");
- return count;
- }
-
- val = simple_write_to_buffer(buf, count, ppos, user_buf, count);
- if (!val) {
- dev_err(dev, "no user data\n");
- goto out;
- }
-
- str = strstr(buf, STR_DUMP_ALLOCATOR);
- if (str)
- tee_shm_pool_dump(dev, TZop.Allocator, true);
-
- str = strstr(buf, STR_CMD_HIST);
- if (str)
- tee_debug_dump_cmd_hist(dev, NULL, 0);
-
-out:
- devm_kfree(dev, buf);
- return count;
-}
-
-static ssize_t tee_read_file_settings_tz(
- struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
-{
- ssize_t ret = 0;
- struct device *dev = file->private_data;
- static const int MAX_SIZE = 2 * PAGE_SIZE;
- char *buf;
-
- buf = devm_kzalloc(dev, MAX_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ret = snprintf(buf, MAX_SIZE, "teetz debug:\n=========\n");
-
- ret += snprintf(buf + ret, MAX_SIZE - ret, "Status:\n");
-
- ret += snprintf(buf + ret, MAX_SIZE - ret,
- "\tOpened session:\t\t[%d]\n", tee_tz_data.count_session);
-
- ret += snprintf(buf + ret, MAX_SIZE - ret,
- "\tMemory pool:\t[%s]\n", tee_tz_get_memory_pool());
-
- ret += snprintf(buf + ret, MAX_SIZE - ret,
- "\nAvailable cmd:\n\t[%s] (%s)\n\t[%s] (%s)\n",
- STR_CMD_HIST, STR_CMD_HIST_HELP,
- STR_DUMP_ALLOCATOR, STR_DUMP_ALLOCATOR_HELP);
-
- ret += snprintf(buf + ret, MAX_SIZE - ret,
- "\n\ti.e.: 'echo dump > /sys/kernel/debug/tee/teetz'\n");
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-
- devm_kfree(dev, buf);
-
- return ret;
-}
-
-
-const struct file_operations tee_debug_fops_tee_tz = {
- .open = simple_open,
- .read = tee_read_file_settings_tz,
- .write = tee_write_file_settings_tz,
- .llseek = default_llseek,
-};
-
-/*****************************************************************************/
-
diff --git a/core/armv7/stm-smc.S b/core/armv7/stm-smc.S
deleted file mode 100644
index 5157e50..0000000
--- a/core/armv7/stm-smc.S
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/linkage.h>
-
- .text
- .balign 4
- .code 32
-
- /* void tee_smc_call(struct smc_param *param); */
- .globl tee_smc_call
-ENTRY(tee_smc_call)
- push {r4-r8, lr}
- mov r8, r0
- ldm r8, {r0-r7}
-.arch_extension sec
- smc #0
- stm r8, {r0-r7}
- pop {r4-r8, pc}
-ENDPROC(tee_smc_call)
diff --git a/core/armv7/tee_tz.c b/core/armv7/tee_tz.c
deleted file mode 100644
index b4666b6..0000000
--- a/core/armv7/tee_tz.c
+++ /dev/null
@@ -1,975 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
-#include <linux/jiffies.h>
-
-#include <asm/pgtable.h>
-
-#include "tee-op.h"
-#include "tee_supp_com.h"
-#include "tee_mem.h"
-#include "tee_service.h"
-#include "tee_driver.h"
-#include "tee_debug.h"
-#include "tee_tz.h"
-#include <arm_common/teesmc.h>
-#include <arm_common/teesmc_st.h>
-
-#define DEV (tee_tz_miscdev.this_device)
-
-/* Shared Memory data (config loaded from secure world) */
-static unsigned long shm_paddr;
-static size_t shm_size;
-static bool shm_cached;
-static void *shm_vaddr;
-
-/* TZ shared mutex service */
-static void *tz_outer_cache_mutex;
-
-/* protect concurrent access to the tee-tz: inits, entry */
-static DEFINE_MUTEX(g_mutex_teez);
-
-static DEFINE_MUTEX(e_mutex_teez);
-static DECLARE_COMPLETION(e_comp_teez);
-static int e_num_waiters;
-
-/* device data */
-struct tee_driver tee_tz_data;
-static struct miscdevice tee_tz_miscdev;
-
-static bool tee_tz_ready;
-
-/* Temporary workaround until we're only using post 3.13 kernels */
-#ifdef ioremap_cached
-#define ioremap_cache ioremap_cached
-#endif
-
-/*******************************************************************
- * Calling TEE
- *******************************************************************/
-
-static void e_lock_teez(void)
-{
- mutex_lock(&e_mutex_teez);
-}
-
-static void e_lock_wait_completion_teez(void)
-{
- /*
- * Release the lock until "something happens" and then reacquire it
- * again.
- *
- * This is needed when TEE returns "busy" and we need to try again
- * later.
- */
- e_num_waiters++;
- mutex_unlock(&e_mutex_teez);
- /*
- * Wait at most one second. Secure world is normally never busy
- * more than that so we should normally never timeout.
- */
- wait_for_completion_timeout(&e_comp_teez, HZ);
- mutex_lock(&e_mutex_teez);
- e_num_waiters--;
-}
-
-static void e_unlock_teez(void)
-{
- /*
- * If at least one thread is waiting for "something to happen" let
- * one thread know that "something has happened".
- */
- if (e_num_waiters)
- complete(&e_comp_teez);
- mutex_unlock(&e_mutex_teez);
-}
-
-static void handle_rpc_func_cmd_mutex_wait(struct teesmc32_arg *arg32)
-{
- struct teesmc32_param *params;
-
- if (arg32->num_params != 2)
- goto bad;
-
- params = TEESMC32_GET_PARAMS(arg32);
-
- if ((params[0].attr & TEESMC_ATTR_TYPE_MASK) !=
- TEESMC_ATTR_TYPE_VALUE_INPUT)
- goto bad;
- if ((params[1].attr & TEESMC_ATTR_TYPE_MASK) !=
- TEESMC_ATTR_TYPE_VALUE_INPUT)
- goto bad;
-
- switch (params[0].u.value.a) {
- case TEE_MUTEX_WAIT_SLEEP:
- tee_mutex_wait_sleep(DEV, params[1].u.value.a,
- params[1].u.value.b);
- break;
- case TEE_MUTEX_WAIT_WAKEUP:
- tee_mutex_wait_wakeup(DEV, params[1].u.value.a,
- params[1].u.value.b);
- break;
- case TEE_MUTEX_WAIT_DELETE:
- tee_mutex_wait_delete(DEV, params[1].u.value.a);
- break;
- default:
- goto bad;
- }
-
- arg32->ret = TEEC_SUCCESS;;
- return;
-bad:
- arg32->ret = TEEC_ERROR_BAD_PARAMETERS;
-}
-
-static void handle_rpc_func_cmd_wait(struct teesmc32_arg *arg32)
-{
- struct teesmc32_param *params;
- u32 msec_to_wait;
-
- if (arg32->num_params != 1)
- goto bad;
-
- params = TEESMC32_GET_PARAMS(arg32);
- msec_to_wait = params[0].u.value.a;
-
- /* set task's state to interruptible sleep */
- set_current_state(TASK_INTERRUPTIBLE);
-
- /* take a nap */
- schedule_timeout(msecs_to_jiffies(msec_to_wait));
-
- arg32->ret = TEEC_SUCCESS;;
- return;
-bad:
- arg32->ret = TEEC_ERROR_BAD_PARAMETERS;
-}
-
-static void handle_rpc_func_cmd_to_supplicant(struct teesmc32_arg *arg32)
-{
- struct teesmc32_param *params;
- struct tee_rpc_invoke inv;
- size_t n;
- uint32_t ret;
-
- if (arg32->num_params > TEE_RPC_BUFFER_NUMBER) {
- arg32->ret = TEEC_ERROR_GENERIC;
- return;
- }
-
- params = TEESMC32_GET_PARAMS(arg32);
-
- memset(&inv, 0, sizeof(inv));
- inv.cmd = arg32->cmd;
- /*
- * Set a suitable error code in case tee-supplicant
- * ignores the request.
- */
- inv.res = TEEC_ERROR_NOT_IMPLEMENTED;
- inv.nbr_bf = arg32->num_params;
- for (n = 0; n < arg32->num_params; n++) {
- inv.cmds[n].buffer = (void *)params[n].u.memref.buf_ptr;
- inv.cmds[n].size = params[n].u.memref.size;
- switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
- case TEESMC_ATTR_TYPE_VALUE_INPUT:
- case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
- case TEESMC_ATTR_TYPE_VALUE_INOUT:
- inv.cmds[n].type = TEE_RPC_VALUE;
- break;
- case TEESMC_ATTR_TYPE_MEMREF_INPUT:
- case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
- case TEESMC_ATTR_TYPE_MEMREF_INOUT:
- inv.cmds[n].type = TEE_RPC_BUFFER;
- break;
- default:
- arg32->ret = TEEC_ERROR_GENERIC;
- return;
- }
- }
-
- ret = tee_supp_cmd(&TZop, TEE_RPC_ICMD_INVOKE,
- &inv, sizeof(inv));
- if (ret == TEEC_RPC_OK)
- arg32->ret = inv.res;
-
- for (n = 0; n < arg32->num_params; n++) {
- switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
- case TEESMC_ATTR_TYPE_VALUE_INPUT:
- case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
- case TEESMC_ATTR_TYPE_VALUE_INOUT:
- case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
- case TEESMC_ATTR_TYPE_MEMREF_INOUT:
- /*
- * Allow supplicant to assign a new pointer
- * to an out-buffer. Needed when the
- * supplicant allocates a new buffer, for
- * instance when loading a TA.
- */
- params[n].u.memref.buf_ptr =
- (uint32_t)inv.cmds[n].buffer;
- params[n].u.memref.size = inv.cmds[n].size;
- break;
- default:
- break;
- }
- }
-}
-
-static void handle_rpc_func_cmd(u32 parg32)
-{
- struct teesmc32_arg *arg32;
-
- arg32 = tee_shm_pool_p2v(DEV, TZop.Allocator, parg32);
- if (!arg32)
- return;
-
- switch (arg32->cmd) {
- case TEE_RPC_MUTEX_WAIT:
- handle_rpc_func_cmd_mutex_wait(arg32);
- break;
- case TEE_RPC_WAIT:
- handle_rpc_func_cmd_wait(arg32);
- break;
- default:
- handle_rpc_func_cmd_to_supplicant(arg32);
- }
-}
-
-static u32 handle_rpc(struct smc_param *param)
-{
- switch (TEESMC_RETURN_GET_RPC_FUNC(param->a0)) {
- case TEESMC_RPC_FUNC_ALLOC_ARG:
- param->a1 = tee_shm_pool_alloc(DEV, TZop.Allocator,
- param->a1, 4);
- break;
- case TEESMC_RPC_FUNC_ALLOC_PAYLOAD:
- /* Can't support payload shared memory with this interface */
- param->a2 = 0;
- break;
- case TEESMC_RPC_FUNC_FREE_ARG:
- tee_shm_pool_free(DEV, TZop.Allocator, param->a1, 0);
- break;
- case TEESMC_RPC_FUNC_FREE_PAYLOAD:
- /* Can't support payload shared memory with this interface */
- break;
- case TEESMC_ST_RPC_FUNC_ALLOC_PAYLOAD:
- {
- struct tee_shm *shm;
-
- shm = tee_shm_allocate(&TZop, 0, param->a1, 0);
- if (!shm) {
- param->a1 = 0;
- break;
- }
- param->a1 = shm->paddr;
- param->a2 = (uint32_t)shm;
- break;
- }
- case TEESMC_ST_RPC_FUNC_FREE_PAYLOAD:
- if (param->a1)
- tee_shm_unallocate((struct tee_shm *)param->a1);
- break;
- case TEESMC_RPC_FUNC_IRQ:
- break;
- case TEESMC_RPC_FUNC_CMD:
- handle_rpc_func_cmd(param->a1);
- break;
- default:
- dev_warn(DEV, "Unknown RPC func 0x%x\n",
- TEESMC_RETURN_GET_RPC_FUNC(param->a0));
- break;
- }
-
- if (irqs_disabled())
- return TEESMC32_FASTCALL_RETURN_FROM_RPC;
- else
- return TEESMC32_CALL_RETURN_FROM_RPC;
-}
-
-static void call_tee(uintptr_t parg32, struct teesmc32_arg *arg32)
-{
- u32 ret;
- u32 funcid;
- struct smc_param param = { 0 };
-
- if (irqs_disabled())
- funcid = TEESMC32_FASTCALL_WITH_ARG;
- else
- funcid = TEESMC32_CALL_WITH_ARG;
-
- param.a1 = parg32;
- e_lock_teez();
- while (true) {
- param.a0 = funcid;
-
- tee_smc_call(&param);
- ret = param.a0;
-
- if (ret == TEESMC_RETURN_EBUSY) {
- /*
- * Since secure world returned busy, release the
- * lock we had when entering this function and wait
- * for "something to happen" (something else to
- * exit from secure world and needed resources may
- * have become available).
- */
- e_lock_wait_completion_teez();
- } else if (TEESMC_RETURN_IS_RPC(ret)) {
- /* Process the RPC. */
- e_unlock_teez();
- funcid = handle_rpc(&param);
- e_lock_teez();
- } else {
- break;
- }
- }
- e_unlock_teez();
-
- switch (ret) {
- case TEESMC_RETURN_UNKNOWN_FUNCTION:
- arg32->ret = TEEC_ERROR_NOT_IMPLEMENTED;
- arg32->ret_origin = TEEC_ORIGIN_COMMS;
- break;
- case TEESMC_RETURN_OK:
- /* arg32->ret set by secure world */
- break;
- default:
- /* Should not happen */
- arg32->ret = TEEC_ERROR_COMMUNICATION;
- arg32->ret_origin = TEEC_ORIGIN_COMMS;
- break;
- }
-}
-
-/*******************************************************************
- * TEE service invoke formating
- *******************************************************************/
-
-/* allocate tee service argument buffer and return virtual address */
-static void *alloc_tee_arg(unsigned long *p, size_t l)
-{
- if ((p == NULL) || (l == 0))
- return NULL;
-
- /* assume a 4 bytes aligned is sufficient */
- *p = tee_shm_pool_alloc(DEV, TZop.Allocator, l, 4);
- if (*p == 0)
- return NULL;
-
- return tee_shm_pool_p2v(DEV, TZop.Allocator, *p);
-}
-
-/* free tee service argument buffer (from its physical address) */
-static void free_tee_arg(unsigned long p)
-{
- if (p)
- tee_shm_pool_free(DEV, TZop.Allocator, p, 0);
-}
-
-static uint32_t get_cache_attrs(void)
-{
- if (tee_shm_pool_is_cached(TZop.Allocator))
- return TEESMC_ATTR_CACHE_DEFAULT << TEESMC_ATTR_CACHE_SHIFT;
- else
- return 0;
-}
-
-static void set_params(
- struct teesmc32_param params32[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t param_types,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT])
-{
- size_t n;
-
- for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
- uint8_t a = TEEC_PARAM_TYPE_GET(param_types, n);
-
- if (a == TEEC_MEMREF_TEMP_INPUT ||
- a == TEEC_MEMREF_TEMP_OUTPUT ||
- a == TEEC_MEMREF_TEMP_INOUT)
- a |= get_cache_attrs();
-
- params32[n].attr = a;
- params32[n].u.value.a = params[n].a;
- params32[n].u.value.b = params[n].b;
- }
-}
-
-static void get_params(TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- struct teesmc32_param params32[TEEC_CONFIG_PAYLOAD_REF_COUNT])
-{
- size_t n;
-
- for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
- params[n].a = params32[n].u.value.a;
- params[n].b = params32[n].u.value.b;
- }
-}
-
-/*
- * tee_open_session - invoke TEE to open a GP TEE session
- */
-static TEEC_Result tee_open_session(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- uint32_t ta_cmd,
- uint32_t param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *origin)
-{
- TEEC_Result ret_tee;
- struct teesmc32_arg *arg32;
- uintptr_t parg32;
- struct teesmc32_param *params32;
- struct teesmc_meta_open_session *meta;
- uintptr_t pmeta;
- size_t num_meta = 1;
-
-
- dev_dbg(DEV, "> uuid=%08x-%04x-%04x\n",
- ((ts->uuid) ? ts->uuid->timeLow : 0xDEAD),
- ((ts->uuid) ? ts->uuid->timeMid : 0xDEAD),
- ((ts->uuid) ? ts->uuid->
- timeHiAndVersion : 0xDEAD));
-
- if (tee_tz_ready == false)
- return TEEC_ERROR_BUSY;
-
- if (ts->ta)
- num_meta++;
-
- arg32 = (typeof(arg32))alloc_tee_arg(&parg32, TEESMC32_GET_ARG_SIZE(
- TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta));
- meta = (typeof(meta))alloc_tee_arg(&pmeta, sizeof(*meta));
-
- if ((arg32 == NULL) || (meta == NULL)) {
- free_tee_arg(parg32);
- free_tee_arg(pmeta);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- memset(arg32, 0, sizeof(*arg32));
- memset(meta, 0, sizeof(*meta));
- arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta;
- params32 = TEESMC32_GET_PARAMS(arg32);
-
- arg32->cmd = TEESMC_CMD_OPEN_SESSION;
-
- params32[0].u.memref.buf_ptr = pmeta;
- params32[0].u.memref.size = sizeof(*meta);
- params32[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
- TEESMC_ATTR_META | get_cache_attrs();
-
- if (ts->ta != NULL) {
- params32[1].u.memref.buf_ptr =
- tee_shm_pool_v2p(DEV, TZop.Allocator, ts->ta);
- params32[1].u.memref.size = ts->tasize;
- params32[1].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
- TEESMC_ATTR_META | get_cache_attrs();
- }
-
- if (ts->uuid != NULL)
- memcpy(meta->uuid, ts->uuid, TEESMC_UUID_LEN);
- meta->clnt_login = ts->login;
-
- set_params(params32 + num_meta, param_type, params);
-
- call_tee(parg32, arg32);
-
- ts->id = arg32->session;
- ret_tee = arg32->ret;
- if (origin)
- *origin = arg32->ret_origin;
-
- get_params(params, params32 + num_meta);
-
- free_tee_arg(parg32);
- free_tee_arg(pmeta);
- dev_dbg(DEV, "< [%d]\n", ret_tee);
- return ret_tee;
-}
-
-/*
- * tee_invoke_command - invoke TEE to invoke a GP TEE command
- */
-static TEEC_Result tee_invoke_command(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- uint32_t ta_cmd,
- uint32_t param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *origin)
-{
- TEEC_Result ret_tee;
- struct teesmc32_arg *arg32;
- uintptr_t parg32;
- struct teesmc32_param *params32;
-
- dev_dbg(DEV, "> [%p] [%d]\n", (void *)ts->id, ta_cmd);
-
- arg32 = (typeof(arg32))alloc_tee_arg(&parg32,
- TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT));
- if (!arg32) {
- free_tee_arg(parg32);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- memset(arg32, 0, sizeof(*arg32));
- arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
- params32 = TEESMC32_GET_PARAMS(arg32);
-
- arg32->cmd = TEESMC_CMD_INVOKE_COMMAND;
- arg32->session = ts->id;
- arg32->ta_func = ta_cmd;
-
- set_params(params32, param_type, params);
-
- call_tee(parg32, arg32);
-
- ret_tee = arg32->ret;
-
- get_params(params, params32);
-
- if (origin)
- *origin = arg32->ret_origin;
-
- free_tee_arg(parg32);
- dev_dbg(DEV, "< [%p]\n", (void *)ret_tee);
- return ret_tee;
-}
-
-/*
- * tee_cancel_command - invoke TEE to cancel a GP TEE command
- */
-static TEEC_Result tee_cancel_command(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- uint32_t ta_cmd,
- uint32_t param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *origin)
-{
- TEEC_Result ret_tee = TEEC_SUCCESS;
- struct teesmc32_arg *arg32;
- uintptr_t parg32;
-
- arg32 = (typeof(arg32))alloc_tee_arg(&parg32, TEESMC32_GET_ARG_SIZE(0));
- if (arg32 == NULL) {
- free_tee_arg(parg32);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- dev_dbg(DEV, "> [%p] [%d] [%d]\n",
- (void *)ts->id, ta_cmd, mutex_is_locked(&g_mutex_teez));
-
- memset(arg32, 0, sizeof(*arg32));
- arg32->cmd = TEESMC_CMD_CANCEL;
- arg32->session = ts->id;
-
- call_tee(parg32, arg32);
-
- ret_tee = arg32->ret;
- if (origin)
- *origin = arg32->ret_origin;
-
- free_tee_arg(parg32);
- dev_dbg(DEV, "< [%p]\n", (void *)ret_tee);
- return ret_tee;
-}
-
-/*
- * tee_close_session - invoke TEE to close a GP TEE session
- */
-static TEEC_Result tee_close_session(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- u32 ta_cmd,
- u32 param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- u32 *origin)
-{
- TEEC_Result ret_tee;
- struct teesmc32_arg *arg32;
- uintptr_t parg32;
-
- arg32 = (typeof(arg32))alloc_tee_arg(&parg32, TEESMC32_GET_ARG_SIZE(0));
- if (arg32 == NULL) {
- free_tee_arg(parg32);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- dev_dbg(DEV, "> [%p]\n", (void *)ts->id);
-
- memset(arg32, 0, sizeof(*arg32));
- arg32->cmd = TEESMC_CMD_CLOSE_SESSION;
- arg32->session = ts->id;
-
- call_tee(parg32, arg32);
-
- ret_tee = arg32->ret;
- if (origin)
- *origin = arg32->ret_origin;
-
- free_tee_arg(parg32);
- dev_dbg(DEV, "< [%p]\n", (void *)ret_tee);
- return ret_tee;
-}
-
-/*
- * Synchronised L2 cache maintenance support
- */
-#ifndef CONFIG_ARM_TZ_SUPPORT
-/* weak outer_tz_mutex in case not supported by kernel */
-bool __weak outer_tz_mutex(unsigned long *p)
-{
- return !p;
-}
-#endif
-
-/* register_l2cc_mutex - Negotiate/Disable outer cache shared mutex */
-static int register_l2cc_mutex(bool reg)
-{
- unsigned long *vaddr = NULL;
- int ret = 0;
- struct smc_param param;
- uintptr_t paddr = 0;
-
- if ((reg == true) && (tz_outer_cache_mutex != NULL)) {
- dev_err(DEV, "outer cache shared mutex already registered\n");
- return -EINVAL;
- }
- if ((reg == false) && (tz_outer_cache_mutex == NULL))
- return 0;
-
- if (reg == false) {
- vaddr = tz_outer_cache_mutex;
- tz_outer_cache_mutex = NULL;
- goto out;
- }
-
- memset(&param, 0, sizeof(param));
- param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
- param.a1 = TEESMC_ST_L2CC_MUTEX_GET_ADDR;
- tee_smc_call(&param);
-
- if (param.a0 != TEESMC_RETURN_OK) {
- dev_warn(DEV, "no TZ l2cc mutex service supported\n");
- goto out;
- }
- paddr = param.a2;
-
- vaddr = ioremap_cache(paddr, sizeof(u32));
- if (vaddr == NULL) {
- dev_warn(DEV, "TZ l2cc mutex disabled: ioremap failed\n");
- ret = -ENOMEM;
- goto out;
- }
-
- if (outer_tz_mutex(vaddr) == false) {
- dev_warn(DEV, "TZ l2cc mutex disabled: outer cache refused\n");
- goto out;
- }
-
- memset(&param, 0, sizeof(param));
- param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
- param.a1 = TEESMC_ST_L2CC_MUTEX_ENABLE;
- tee_smc_call(&param);
-
- if (param.a0 != TEESMC_RETURN_OK) {
- dev_warn(DEV, "TZ l2cc mutex disabled: TZ enable failed\n");
- goto out;
- }
- tz_outer_cache_mutex = vaddr;
-
-out:
- if (tz_outer_cache_mutex == NULL) {
- memset(&param, 0, sizeof(param));
- param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
- param.a1 = TEESMC_ST_L2CC_MUTEX_DISABLE;
- tee_smc_call(&param);
- outer_tz_mutex(NULL);
- if (vaddr)
- iounmap(vaddr);
- dev_info(DEV, "outer cache shared mutex disabled\n");
- }
-
- dev_dbg(DEV, "teetz outer mutex: ret=%d pa=0x%lX va=0x%p %sabled\n",
- ret, paddr, vaddr, tz_outer_cache_mutex ? "en" : "dis");
- return ret;
-}
-
-/* configure_shm - Negotiate Shared Memory configuration with teetz. */
-static int configure_shm(void)
-{
- struct smc_param param = { 0 };
- int ret = 0;
-
- if (shm_paddr)
- return -EINVAL;
-
- param.a0 = TEESMC32_ST_FASTCALL_GET_SHM_CONFIG;
- tee_smc_call(&param);
-
- if (param.a0 != TEESMC_RETURN_OK) {
- dev_err(DEV, "shm service not available: %X", (uint)param.a0);
- ret = -EINVAL;
- goto out;
- }
-
- shm_paddr = param.a1;
- shm_size = param.a2;
- shm_cached = (bool)param.a3;
-
- if (shm_cached)
- shm_vaddr = ioremap_cache(shm_paddr, shm_size);
- else
- shm_vaddr = ioremap_nocache(shm_paddr, shm_size);
-
- if (shm_vaddr == NULL) {
- dev_err(DEV, "shm ioremap failed\n");
- ret = -ENOMEM;
- goto out;
- }
-
- TZop.Allocator = tee_shm_pool_create(
- DEV, shm_size, shm_vaddr, shm_paddr);
-
- if (!TZop.Allocator) {
- dev_err(DEV, "shm pool creation failed (%d)", shm_size);
- ret = -EINVAL;
- goto out;
- }
-
- if (shm_cached)
- tee_shm_pool_set_cached(TZop.Allocator);
-out:
- if (ret)
- shm_paddr = 0;
-
- dev_dbg(DEV, "teetz shm: ret=%d pa=0x%lX va=0x%p size=%d, %scached",
- ret, shm_paddr, shm_vaddr, shm_size,
- shm_cached == 1 ? "" : "un");
- return ret;
-}
-/*
- * call_tz_sec_world - wrapper for invoking TEE services
- */
-static TEEC_Result call_tz_sec_world(struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- u32 ta_cmd,
- u32 param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- u32 *origin)
-{
- int ret;
-
- switch (sec_cmd) {
-
- case CMD_TEEC_OPEN_SESSION:
- ret = tee_open_session(ts, sec_cmd, ta_cmd, param_type,
- params, origin);
- break;
-
- case CMD_TEEC_INVOKE_COMMAND:
- ret = tee_invoke_command(ts, sec_cmd, ta_cmd, param_type,
- params, origin);
- break;
-
- case CMD_TEEC_CANCEL_COMMAND:
- ret = tee_cancel_command(ts, sec_cmd, ta_cmd, param_type,
- params, origin);
- break;
-
- case CMD_TEEC_CLOSE_SESSION:
- ret = tee_close_session(ts, sec_cmd, ta_cmd, param_type,
- params, origin);
- break;
-
- case CMD_TEEC_REGISTER_MEMORY:
- case CMD_TEEC_UNREGISTER_MEMORY:
- ret = TEEC_SUCCESS;
- break; /* TODO: check if these shall be transfered to TEE */
-
- default:
- ret = TEEC_ERROR_BAD_PARAMETERS;
- }
-
- return ret;
-}
-
-static TEEC_Result TZ_register_shm(ulong paddr, ulong size, void **handle)
-{
- return TEEC_SUCCESS; /* nothing to do ? */
-}
-
-static TEEC_Result TZ_unregister_shm(void *handle)
-{
- return TEEC_SUCCESS; /* nothing to do ! */
-}
-
-static struct miscdevice tee_tz_miscdev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = TEE_TZ_NAME,
- .fops = &tee_fops,
-};
-
-struct tee_targetop TZop = {
- .miscdev = &tee_tz_miscdev,
- .call_sec_world = call_tz_sec_world,
- .register_shm = TZ_register_shm,
- .unregister_shm = TZ_unregister_shm,
- .page_size = SZ_4K, /* min size alignment */
- .Allocator = NULL,
-};
-
-/*******************************************************************
- * Starting TEE support
- *******************************************************************/
-
-static bool teesmc_api_uid_is_st(void)
-{
- struct smc_param param = { .a0 = TEESMC32_CALLS_UID };
-
- tee_smc_call(&param);
-
- if (param.a0 == TEESMC_ST_UID_R0 && param.a1 == TEESMC_ST_UID_R1 &&
- param.a2 == TEESMC_ST_UID_R2 && (param.a3 == TEESMC_ST_UID32_R3 ||
- param.a3 == TEESMC_ST_UID64_R3))
- return true;
-
- return false;
-}
-
-static bool teesmc_os_uuid_is_optee(void)
-{
- struct smc_param param = { .a0 = TEESMC32_CALL_GET_OS_UUID };
-
- tee_smc_call(&param);
-
- if (param.a0 == TEESMC_OS_OPTEE_UUID_R0 &&
- param.a1 == TEESMC_OS_OPTEE_UUID_R1 &&
- param.a2 == TEESMC_OS_OPTEE_UUID_R2 &&
- param.a3 == TEESMC_OS_OPTEE_UUID_R3)
- return true;
-
- return false;
-}
-
-static int start_tz_world(void)
-{
- int ret;
-
- /* allow SMC call, mutex will prevent any other access */
- mutex_lock(&g_mutex_teez);
- tee_tz_ready = true;
-
- /* Check that we're talking to the expected TEE */
- if (!teesmc_api_uid_is_st() || !teesmc_os_uuid_is_optee()) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = configure_shm();
- if (ret)
- goto out;
-
- ret = register_l2cc_mutex(true);
-
-out:
- if (ret)
- tee_tz_ready = false;
-
- mutex_unlock(&g_mutex_teez);
- return ret;
-}
-
-static void stop_tz_world(void)
-{
- mutex_lock(&g_mutex_teez);
- register_l2cc_mutex(false);
- tee_shm_pool_destroy(DEV, TZop.Allocator);
- iounmap(shm_vaddr);
- mutex_unlock(&g_mutex_teez);
-}
-
-/*******************************************************************
- * TEE TZ driver inits
- *******************************************************************/
-
-int __init tee_tz_init(void)
-{
- int ret;
-
- mutex_init(&tee_tz_data.mutex_tee);
-
- tee_tz_data.memory_pool = NULL;
-
- ret = misc_register(&tee_tz_miscdev);
- if (ret) {
- pr_err("Can't register tee_tz\n");
- goto exit;
- }
-
-#if (CFG_TEE_DRV_DEBUGFS == 1)
- ret = tee_debug_init(DEV);
- if (ret)
- goto err_deregister;
-#endif
-
- ret = start_tz_world();
- if (ret) {
- dev_err(DEV, "Can't start tee-tz\n");
- goto err_dbg;
- }
-
- return 0;
-
-err_dbg:
-#if (CFG_TEE_DRV_DEBUGFS == 1)
- tee_debug_remove(DEV);
-err_deregister:
-#endif
- misc_deregister(&tee_tz_miscdev);
-exit:
- /*
- * Temporary workaround: TEE TZ firmware may not be available.
- * In case TZ driver fails, just forbid access to TZ-TEE.
- */
- if (ret) {
- pr_err("TEE/TZ driver failed. It is now disabled.\n");
- ret = 0;
- }
- return ret;
-}
-
-void tee_tz_exit(void)
-{
- if (tee_tz_ready == false)
- return;
-
- stop_tz_world();
-#if (CFG_TEE_DRV_DEBUGFS == 1)
- tee_debug_remove(DEV);
-#endif
- misc_deregister(&tee_tz_miscdev);
-}
diff --git a/core/armv7/tee_tz.h b/core/armv7/tee_tz.h
deleted file mode 100644
index caeda0b..0000000
--- a/core/armv7/tee_tz.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#ifndef TEE_TZ_H
-#define TEE_TZ_H
-
-struct smc_param {
- uint32_t a0;
- uint32_t a1;
- uint32_t a2;
- uint32_t a3;
- uint32_t a4;
- uint32_t a5;
- uint32_t a6;
- uint32_t a7;
-};
-
-int __init tee_tz_init(void);
-void tee_tz_exit(void);
-
-const char *tee_tz_get_memory_pool(void);
-int tee_smc_call(struct smc_param *param);
-
-extern struct tee_driver tee_tz_data;
-extern struct tee_targetop TZop;
-
-#endif /* TEE_TZ_H */
-
diff --git a/core/armv7/tee_tz_debug.c b/core/armv7/tee_tz_debug.c
deleted file mode 100644
index c116d81..0000000
--- a/core/armv7/tee_tz_debug.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/device.h>
-
-#include "generic/tee-op.h"
-#include "generic/tee_driver.h"
-#include "generic/tee_debug.h"
-#include "tee_tz.h"
-
-static const char STR_CMD_HIST[] = "hist";
-static const char STR_CMD_HIST_HELP[] = "cmd";
-static const char STR_DUMP_ALLOCATOR[] = "dump";
-static const char STR_DUMP_ALLOCATOR_HELP[] = "shared memory";
-
-/*****************************************************************************/
-
-static ssize_t tee_write_file_settings_tz(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct device *dev = file->private_data;
- char *buf;
- char *str;
- int val;
-
- buf = devm_kzalloc(dev, count, GFP_KERNEL);
- if (!buf) {
- dev_err(dev, "can't allocate work buffer\n");
- return count;
- }
-
- val = simple_write_to_buffer(buf, count, ppos, user_buf, count);
- if (!val) {
- dev_err(dev, "no user data\n");
- goto out;
- }
-
- str = strstr(buf, STR_DUMP_ALLOCATOR);
- if (str)
- tee_shm_pool_dump(dev, TZop.Allocator, true);
-
- str = strstr(buf, STR_CMD_HIST);
- if (str)
- tee_debug_dump_cmd_hist(dev, NULL, 0);
-
-out:
- devm_kfree(dev, buf);
- return count;
-}
-
-static ssize_t tee_read_file_settings_tz(
- struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
-{
- ssize_t ret = 0;
- struct device *dev = file->private_data;
- static const int MAX_SIZE = 2 * PAGE_SIZE;
- char *buf;
-
- buf = devm_kzalloc(dev, MAX_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ret = snprintf(buf, MAX_SIZE, "teetz debug:\n=========\n");
-
- ret += snprintf(buf + ret, MAX_SIZE - ret, "Status:\n");
-
- ret += snprintf(buf + ret, MAX_SIZE - ret,
- "\tOpened session:\t\t[%d]\n", tee_tz_data.count_session);
-
- ret += snprintf(buf + ret, MAX_SIZE - ret,
- "\tMemory pool:\t[%s]\n", tee_tz_get_memory_pool());
-
- ret += snprintf(buf + ret, MAX_SIZE - ret,
- "\nAvailable cmd:\n\t[%s] (%s)\n\t[%s] (%s)\n",
- STR_CMD_HIST, STR_CMD_HIST_HELP,
- STR_DUMP_ALLOCATOR, STR_DUMP_ALLOCATOR_HELP);
-
- ret += snprintf(buf + ret, MAX_SIZE - ret,
- "\n\ti.e.: 'echo dump > /sys/kernel/debug/tee/teetz'\n");
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-
- devm_kfree(dev, buf);
-
- return ret;
-}
-
-
-const struct file_operations tee_debug_fops_tee_tz = {
- .open = simple_open,
- .read = tee_read_file_settings_tz,
- .write = tee_write_file_settings_tz,
- .llseek = default_llseek,
-};
-
-/*****************************************************************************/
-
diff --git a/core/tee_context.c b/core/tee_context.c
new file mode 100644
index 0000000..30615c0
--- /dev/null
+++ b/core/tee_context.c
@@ -0,0 +1,299 @@
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/file.h>
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#include "tee_shm.h"
+#include "tee_core_priv.h"
+
+
+/**
+ * tee_context_dump - Dump in a buffer the informations (ctx, sess & shm)
+ * associated to a tee.
+ */
+int tee_context_dump(struct tee *tee, char *buff, size_t len)
+{
+ struct list_head *ptrCtx, *ptrSess, *ptrShm;
+ struct tee_context *ctx;
+ struct tee_session *sess;
+ struct tee_shm *shm;
+ int i = 0;
+ int j = 0;
+
+ int pos = 0;
+
+ BUG_ON(!tee);
+
+ if (len < 80)
+ return 0;
+
+ mutex_lock(&tee->lock);
+ if (!list_empty(&tee->list_ctx)) {
+ list_for_each(ptrCtx, &tee->list_ctx) {
+ ctx = list_entry(ptrCtx, struct tee_context, entry);
+
+ pos += sprintf(buff + pos,
+ "[%02d] ctx=%p (refcount=%d) (usr=%d) "
+ "name=\"%s\" (tgid=%d)\n",
+ i, ctx,
+ (int)atomic_read(&ctx->refcount.
+ refcount),
+ ctx->usr_client, ctx->name, ctx->tgid);
+
+ if ((len - pos) < 80) {
+ pos = 0;
+ goto out;
+ }
+
+ j = 0;
+ if (!list_empty(&ctx->list_sess)) {
+ list_for_each(ptrSess, &ctx->list_sess) {
+ sess = list_entry(ptrSess,
+ struct tee_session,
+ entry);
+
+ pos += sprintf(buff + pos,
+ " [%02d.%d] sess=%p sessid=%08x\n",
+ i, j, sess,
+ sess->sessid);
+
+ if ((len - pos) < 80) {
+ pos = 0;
+ goto out;
+ }
+
+ j++;
+ }
+ }
+
+ j = 0;
+ if (!list_empty(&ctx->list_shm)) {
+ list_for_each(ptrShm, &ctx->list_shm) {
+ shm =
+ list_entry(ptrShm, struct tee_shm,
+ entry);
+
+ pos += sprintf(buff + pos,
+ " [%02d.%d] shm=%p paddr=%pad "
+ "kaddr=%p s=%zu(%zu)\n",
+ i, j, shm,
+ &shm->paddr,
+ shm->kaddr,
+ shm->size_req,
+ shm->size_alloc);
+
+ if ((len - pos) < 80) {
+ pos = 0;
+ goto out;
+ }
+
+ j++;
+ }
+ }
+ i++;
+ }
+ }
+
+out:
+ mutex_unlock(&tee->lock);
+ return pos;
+}
+
+/**
+ * tee_context_create - Allocate and create a new context.
+ * Reference on the back-end is requested.
+ */
+struct tee_context *tee_context_create(struct tee *tee)
+{
+ int ret;
+ struct tee_context *ctx;
+
+ dev_dbg(_DEV(tee), "%s: >\n", __func__);
+
+ ctx = devm_kzalloc(_DEV(tee), sizeof(struct tee_context), GFP_KERNEL);
+ if (!ctx) {
+ dev_err(_DEV(tee), "%s: tee_context allocation failed\n",
+ __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ kref_init(&ctx->refcount);
+ INIT_LIST_HEAD(&ctx->list_sess);
+ INIT_LIST_HEAD(&ctx->list_shm);
+
+ ctx->tee = tee;
+ snprintf(ctx->name, sizeof(ctx->name), "%s", current->comm);
+ ctx->tgid = current->tgid;
+
+ ret = tee_get(tee);
+ if (ret) {
+ devm_kfree(_DEV(tee), ctx);
+ return ERR_PTR(ret);
+ }
+
+ mutex_lock(&tee->lock);
+ tee_inc_stats(&tee->stats[TEE_STATS_CONTEXT_IDX]);
+ list_add_tail(&ctx->entry, &tee->list_ctx);
+ mutex_unlock(&tee->lock);
+
+ dev_dbg(_DEV(ctx->tee), "%s: < ctx=%p is created\n", __func__, ctx);
+ return ctx;
+}
+
+/**
+ * _tee_context_do_release - Final function to release
+ * and free a context.
+ */
+static void _tee_context_do_release(struct kref *kref)
+{
+ struct tee_context *ctx;
+ struct tee *tee;
+
+ ctx = container_of(kref, struct tee_context, refcount);
+
+ BUG_ON(!ctx || !ctx->tee);
+
+ tee = ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > ctx=%p\n", __func__, ctx);
+
+ mutex_lock(&tee->lock);
+ tee_dec_stats(&tee->stats[TEE_STATS_CONTEXT_IDX]);
+ list_del(&ctx->entry);
+ mutex_unlock(&tee->lock);
+
+ devm_kfree(_DEV(tee), ctx);
+ tee_put(tee);
+
+ dev_dbg(_DEV(tee), "%s: < ctx=%p is destroyed\n", __func__, ctx);
+}
+
+/**
+ * tee_context_get - Increase the reference count of
+ * the context.
+ */
+void tee_context_get(struct tee_context *ctx)
+{
+ BUG_ON(!ctx || !ctx->tee);
+
+ kref_get(&ctx->refcount);
+
+ dev_dbg(_DEV(ctx->tee), "%s: ctx=%p, kref=%d\n", __func__,
+ ctx, (int)atomic_read(&ctx->refcount.refcount));
+}
+
+static int is_in_list(struct tee *tee, struct list_head *entry)
+{
+ int present = 1;
+ mutex_lock(&tee->lock);
+ if ((entry->next == LIST_POISON1) && (entry->prev == LIST_POISON2))
+ present = 0;
+ mutex_unlock(&tee->lock);
+ return present;
+}
+
+/**
+ * tee_context_put - Decreases the reference count of
+ * the context. If 0, the final
+ * release function is called.
+ */
+void tee_context_put(struct tee_context *ctx)
+{
+ struct tee_context *_ctx = ctx;
+ struct tee *tee;
+ BUG_ON(!ctx || !ctx->tee);
+ tee = ctx->tee;
+
+ if (!is_in_list(tee, &ctx->entry))
+ return;
+
+ kref_put(&ctx->refcount, _tee_context_do_release);
+
+ dev_dbg(_DEV(tee), "%s: ctx=%p, kref=%d\n", __func__,
+ _ctx, (int)atomic_read(&ctx->refcount.refcount));
+}
+
+/**
+ * tee_context_destroy - Request to destroy a context.
+ */
+void tee_context_destroy(struct tee_context *ctx)
+{
+ struct tee *tee;
+
+ if (!ctx || !ctx->tee)
+ return;
+
+ tee = ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: ctx=%p\n", __func__, ctx);
+
+ tee_context_put(ctx);
+}
+
+int tee_context_copy_from_client(const struct tee_context *ctx,
+ void *dest, const void *src, size_t size)
+{
+ int res = 0;
+ if (dest && src && (size > 0)) {
+ if (ctx->usr_client)
+ res = copy_from_user(dest, src, size);
+ else
+ memcpy(dest, src, size);
+ }
+ return res;
+}
+
+struct tee_shm *tee_context_alloc_shm_tmp(struct tee_context *ctx,
+ size_t size, const void *data,
+ int type)
+{
+ struct tee_shm *shm;
+
+ type &= (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT);
+
+ shm = tee_shm_alloc(ctx, size, TEE_SHM_MAPPED | TEE_SHM_TEMP | type);
+ if (IS_ERR_OR_NULL(shm)) {
+ dev_err(_DEV(ctx->tee), "%s: buffer allocation failed (%ld)\n",
+ __func__, PTR_ERR(shm));
+ return shm;
+ }
+
+ if (shm && (type & TEEC_MEM_INPUT)) {
+ if (tee_context_copy_from_client(ctx, shm->kaddr, data, size)) {
+ dev_err(_DEV(ctx->tee),
+ "%s: tee_context_copy_from_client failed\n",
+ __func__);
+ tee_shm_free(shm);
+ shm = NULL;
+ }
+ }
+ return shm;
+}
+
+struct tee_shm *tee_context_create_tmpref_buffer(struct tee_context *ctx,
+ size_t size,
+ const void *buffer, int type)
+{
+ struct tee_shm *shm = NULL;
+ int flags;
+
+ switch (type) {
+ case TEEC_MEMREF_TEMP_OUTPUT:
+ flags = TEEC_MEM_OUTPUT;
+ break;
+ case TEEC_MEMREF_TEMP_INPUT:
+ flags = TEEC_MEM_INPUT;
+ break;
+ case TEEC_MEMREF_TEMP_INOUT:
+ flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
+ break;
+ default:
+ BUG_ON(1);
+ };
+ shm = tee_context_alloc_shm_tmp(ctx, size, buffer, flags);
+ return shm;
+}
diff --git a/core/tee_core.c b/core/tee_core.c
new file mode 100644
index 0000000..5fd3d3b
--- /dev/null
+++ b/core/tee_core.c
@@ -0,0 +1,524 @@
+/*
+ * tee_driver.c - TEE core kernel module.
+ *
+ */
+
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/idr.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <asm-generic/ioctl.h>
+#include <linux/sched.h>
+
+#include "linux/tee_core.h"
+#include "linux/tee_ioc.h"
+
+#include "tee_core_priv.h"
+
+#include "tee_sysfs.h"
+#include "tee_debugfs.h"
+#include "tee_shm.h"
+#include "tee_supp_com.h"
+
+#define _TEE_CORE_FW_VER "1:0.1"
+
+static char *_tee_supp_app_name = "tee-supplicant";
+
+/* Store the class misc reference */
+static struct class *misc_class;
+
+static int device_match(struct device *device, const void *devname)
+{
+ struct tee *tee = dev_get_drvdata(device);
+ int ret = strncmp(devname, tee->name, sizeof(tee->name));
+ BUG_ON(!tee);
+ if (ret == 0)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * For the kernel api.
+ * Get a reference on a device tee from the device needed
+ */
+struct tee *tee_get_tee(const char *devname)
+{
+ struct device *device;
+ if (!devname)
+ return NULL;
+ device = class_find_device(misc_class, NULL, devname, device_match);
+ if (!device) {
+ pr_err("%s:%d - can't find device [%s]\n", __func__, __LINE__,
+ devname);
+ return NULL;
+ }
+
+ return dev_get_drvdata(device);
+}
+
+void tee_inc_stats(struct tee_stats_entry *entry)
+{
+ entry->count++;
+ if (entry->count > entry->max)
+ entry->max = entry->count;
+}
+
+void tee_dec_stats(struct tee_stats_entry *entry)
+{
+ entry->count--;
+}
+
+/**
+ * tee_get - increases refcount of the tee
+ * @tee: [in] tee to increase refcount of
+ *
+ * @note: If tee.ops.start() callback function is available,
+ * it is called when refcount is equal at 1.
+ */
+int tee_get(struct tee *tee)
+{
+ int ret = 0;
+
+ BUG_ON(!tee);
+
+ if (atomic_inc_return(&tee->refcount) == 1) {
+ BUG_ON(!try_module_get(tee->ops->owner));
+ dev_dbg(_DEV(tee), "%s: refcount=1 call %s::start()...\n",
+ __func__, tee->name);
+ get_device(tee->dev);
+ if (tee->ops->start)
+ ret = tee->ops->start(tee);
+ }
+ if (ret) {
+ put_device(tee->dev);
+ module_put(tee->ops->owner);
+ dev_err(_DEV(tee), "%s: %s::start() failed, err=%d\n",
+ __func__, tee->name, ret);
+ atomic_dec(&tee->refcount);
+ } else {
+ int count = (int)atomic_read(&tee->refcount);
+ dev_dbg(_DEV(tee), "%s: refcount=%d\n", __func__, count);
+ if (count > tee->max_refcount)
+ tee->max_refcount = count;
+ }
+ return ret;
+}
+
+/**
+ * tee_put - decreases refcount of the tee
+ * @tee: [in] tee to reduce refcount of
+ *
+ * @note: If tee.ops.stop() callback function is available,
+ * it is called when refcount is equal at 0.
+ */
+int tee_put(struct tee *tee)
+{
+ int ret = 0;
+ int count;
+
+ BUG_ON(!tee);
+
+ if (atomic_dec_and_test(&tee->refcount)) {
+ dev_dbg(_DEV(tee), "%s: refcount=0 call %s::stop()...\n",
+ __func__, tee->name);
+ if (tee->ops->stop)
+ ret = tee->ops->stop(tee);
+ module_put(tee->ops->owner);
+ put_device(tee->dev);
+ }
+ if (ret) {
+ dev_err(_DEV(tee), "%s: %s::stop() has failed, ret=%d\n",
+ __func__, tee->name, ret);
+ }
+
+ count = (int)atomic_read(&tee->refcount);
+ dev_dbg(_DEV(tee), "%s: refcount=%d\n", __func__, count);
+ return ret;
+}
+
+static int tee_supp_open(struct tee *tee)
+{
+ int ret = 0;
+ dev_dbg(_DEV(tee), "%s: appclient=\"%s\" pid=%d\n", __func__,
+ current->comm, current->pid);
+
+ BUG_ON(!tee->rpc);
+
+ if (strncmp(_tee_supp_app_name, current->comm,
+ strlen(_tee_supp_app_name)) == 0) {
+ if (atomic_add_return(1, &tee->rpc->used) > 1) {
+ ret = -EBUSY;
+ dev_err(tee->dev, "%s: ERROR Only one Supplicant is allowed\n",
+ __func__);
+ atomic_sub(1, &tee->rpc->used);
+ }
+ }
+
+ return ret;
+}
+
+static void tee_supp_release(struct tee *tee)
+{
+ dev_dbg(_DEV(tee), "%s: appclient=\"%s\" pid=%d\n", __func__,
+ current->comm, current->pid);
+
+ BUG_ON(!tee->rpc);
+
+ if ((atomic_read(&tee->rpc->used) == 1) &&
+ (strncmp(_tee_supp_app_name, current->comm,
+ strlen(_tee_supp_app_name)) == 0))
+ atomic_sub(1, &tee->rpc->used);
+}
+
+static int tee_ctx_open(struct inode *inode, struct file *filp)
+{
+ struct tee_context *ctx;
+ struct tee *tee;
+ int ret;
+
+ tee = container_of(filp->private_data, struct tee, miscdev);
+
+ BUG_ON(!tee);
+ BUG_ON(tee->miscdev.minor != iminor(inode));
+
+ dev_dbg(_DEV(tee), "%s: > name=\"%s\"\n", __func__, tee->name);
+
+ ret = tee_supp_open(tee);
+ if (ret)
+ return ret;
+
+ ctx = tee_context_create(tee);
+ if (IS_ERR_OR_NULL(ctx))
+ return PTR_ERR(ctx);
+
+ ctx->usr_client = 1;
+ filp->private_data = ctx;
+
+ dev_dbg(_DEV(tee), "%s: < ctx=%p is created\n", __func__, (void *)ctx);
+
+ return 0;
+}
+
+static int tee_ctx_release(struct inode *inode, struct file *filp)
+{
+ struct tee_context *ctx = filp->private_data;
+ struct tee *tee;
+
+ if (!ctx)
+ return -EINVAL;
+
+ BUG_ON(!ctx->tee);
+ tee = ctx->tee;
+ BUG_ON(tee->miscdev.minor != iminor(inode));
+
+ dev_dbg(_DEV(tee), "%s: > ctx=%p\n", __func__, ctx);
+
+ tee_context_destroy(ctx);
+ tee_supp_release(tee);
+
+ dev_dbg(_DEV(tee), "%s: < ctx=%p is destroyed\n", __func__, ctx);
+ return 0;
+}
+
+static int tee_do_create_session(struct tee_context *ctx,
+ struct tee_cmd_io __user *u_cmd)
+{
+ int ret = -EINVAL;
+ struct tee_cmd_io k_cmd;
+ struct tee *tee;
+
+ tee = ctx->tee;
+ BUG_ON(!ctx->usr_client);
+
+ dev_dbg(_DEV(tee), "%s: >\n", __func__);
+
+ if (copy_from_user(&k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) {
+ dev_err(_DEV(tee), "%s: copy_from_user failed\n", __func__);
+ goto exit;
+ }
+
+ if (k_cmd.fd_sess > 0) {
+ dev_err(_DEV(tee), "%s: invalid fd_sess %d\n", __func__,
+ k_cmd.fd_sess);
+ goto exit;
+ }
+
+ if ((k_cmd.op == NULL) || (k_cmd.uuid == NULL) ||
+ ((k_cmd.data != NULL) && (k_cmd.data_size == 0)) ||
+ ((k_cmd.data == NULL) && (k_cmd.data_size != 0))) {
+ dev_err(_DEV(tee),
+ "%s: op or/and data parameters are not valid\n",
+ __func__);
+ goto exit;
+ }
+
+ ret = tee_session_create_fd(ctx, &k_cmd);
+ put_user(k_cmd.err, &u_cmd->err);
+ put_user(k_cmd.origin, &u_cmd->origin);
+ if (ret)
+ goto exit;
+
+ put_user(k_cmd.fd_sess, &u_cmd->fd_sess);
+
+exit:
+ dev_dbg(_DEV(tee), "%s: < ret=%d, sessfd=%d\n", __func__, ret,
+ k_cmd.fd_sess);
+ return ret;
+}
+
+static int tee_do_shm_alloc(struct tee_context *ctx,
+ struct tee_shm_io __user *u_shm)
+{
+ int ret = -EINVAL;
+ struct tee_shm_io k_shm;
+ struct tee *tee = ctx->tee;
+ BUG_ON(!ctx->usr_client);
+
+ dev_dbg(_DEV(tee), "%s: >\n", __func__);
+
+ if (copy_from_user(&k_shm, (void *)u_shm, sizeof(struct tee_shm_io))) {
+ dev_err(_DEV(tee), "%s: copy_from_user failed\n", __func__);
+ goto exit;
+ }
+
+ if ((k_shm.buffer != NULL) || (k_shm.fd_shm != 0) ||
+ /*(k_shm.flags & ~(tee->shm_flags)) ||*/
+ ((k_shm.flags & tee->shm_flags) == 0) || (k_shm.registered != 0)) {
+ dev_err(_DEV(tee),
+ "%s: shm parameters are not valid %p %d %08x %08x %d\n",
+ __func__, (void *)k_shm.buffer, k_shm.fd_shm,
+ (unsigned int)k_shm.flags, (unsigned int)tee->shm_flags,
+ k_shm.registered);
+ goto exit;
+ }
+
+ ret = tee_shm_alloc_fd(ctx, &k_shm);
+ if (ret)
+ goto exit;
+
+ put_user(k_shm.fd_shm, &u_shm->fd_shm);
+
+exit:
+ dev_dbg(_DEV(tee), "%s: < ret=%d, shmfd=%d\n", __func__, ret,
+ k_shm.fd_shm);
+ return ret;
+}
+
+static int tee_do_get_fd_for_rpc_shm(struct tee_context *ctx,
+ struct tee_shm_io __user *u_shm)
+{
+ int ret = -EINVAL;
+ struct tee_shm_io k_shm;
+ struct tee *tee = ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: >\n", __func__);
+ BUG_ON(!ctx->usr_client);
+
+ if (copy_from_user(&k_shm, (void *)u_shm, sizeof(struct tee_shm_io))) {
+ dev_err(_DEV(tee), "%s: copy_from_user failed\n", __func__);
+ goto exit;
+ }
+
+ if ((k_shm.buffer == NULL) || (k_shm.size == 0) || (k_shm.fd_shm != 0)
+ || (k_shm.flags & ~(tee->shm_flags))
+ || ((k_shm.flags & tee->shm_flags) == 0)
+ || (k_shm.registered != 0)) {
+ dev_err(_DEV(tee), "%s: shm parameters are not valid\n",
+ __func__);
+ goto exit;
+ }
+
+ ret = tee_shm_get_fd(ctx, &k_shm);
+ if (ret)
+ goto exit;
+
+ put_user(k_shm.fd_shm, &u_shm->fd_shm);
+
+exit:
+ dev_dbg(_DEV(tee), "%s: < ret=%d, shmfd=%d\n", __func__, ret,
+ k_shm.fd_shm);
+ return ret;
+}
+
+static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = -EINVAL;
+ struct tee_context *ctx = filp->private_data;
+
+ BUG_ON(!ctx);
+ BUG_ON(!ctx->tee);
+
+ dev_dbg(_DEV(ctx->tee), "%s: > cmd nr=%d\n", __func__, _IOC_NR(cmd));
+
+ switch (cmd) {
+ case TEE_OPEN_SESSION_IOC:
+ ret =
+ tee_do_create_session(ctx, (struct tee_cmd_io __user *)arg);
+ break;
+ case TEE_ALLOC_SHM_IOC:
+ ret = tee_do_shm_alloc(ctx, (struct tee_shm_io __user *)arg);
+ break;
+ case TEE_GET_FD_FOR_RPC_SHM_IOC:
+ ret =
+ tee_do_get_fd_for_rpc_shm(ctx,
+ (struct tee_shm_io __user *)arg);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ dev_dbg(_DEV(ctx->tee), "%s: < ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+const struct file_operations tee_fops = {
+ .owner = THIS_MODULE,
+ .read = tee_supp_read,
+ .write = tee_supp_write,
+ .open = tee_ctx_open,
+ .release = tee_ctx_release,
+ .unlocked_ioctl = tee_ioctl
+};
+
+static void tee_plt_device_release(struct device *dev)
+{
+ pr_debug("%s: (dev=%p)....\n", __func__, dev);
+}
+
+struct tee *tee_core_alloc(struct device *dev, char *name, int id,
+ const struct tee_ops *ops, size_t len)
+{
+ struct tee *tee;
+
+ if (!dev || !name || !ops ||
+ !ops->open || !ops->close || !ops->alloc || !ops->free)
+ return NULL;
+
+ tee = devm_kzalloc(dev, sizeof(struct tee) + len, GFP_KERNEL);
+ if (!tee) {
+ dev_err(dev, "%s: kzalloc failed\n", __func__);
+ return NULL;
+ }
+
+ if (!dev->release)
+ dev->release = tee_plt_device_release;
+
+ tee->dev = dev;
+ tee->id = id;
+ tee->ops = ops;
+ tee->priv = &tee[1];
+
+ snprintf(tee->name, sizeof(tee->name), "optee%s%02d", name, tee->id);
+ pr_info("TEE core: Alloc the misc device \"%s\" (id=%d)\n", tee->name,
+ tee->id);
+
+ tee->miscdev.parent = dev;
+ tee->miscdev.minor = MISC_DYNAMIC_MINOR;
+ tee->miscdev.name = tee->name;
+ tee->miscdev.fops = &tee_fops;
+
+ mutex_init(&tee->lock);
+ atomic_set(&tee->refcount, 0);
+ INIT_LIST_HEAD(&tee->list_ctx);
+ INIT_LIST_HEAD(&tee->list_rpc_shm);
+
+ tee->state = TEE_OFFLINE;
+
+ tee_supp_init(tee);
+
+ return tee;
+}
+EXPORT_SYMBOL(tee_core_alloc);
+
+int tee_core_add(struct tee *tee)
+{
+ int rc = 0;
+
+ if (!tee)
+ return -EINVAL;
+
+ rc = misc_register(&tee->miscdev);
+ if (rc != 0) {
+ pr_err("TEE Core: misc_register() failed name=\"%s\"\n",
+ tee->name);
+ return rc;
+ }
+
+ dev_set_drvdata(tee->miscdev.this_device, tee);
+
+ tee_init_sysfs(tee);
+ tee_create_debug_dir(tee);
+
+ /* Register a static reference on the class misc
+ * to allow finding device by class */
+ BUG_ON(!tee->miscdev.this_device->class);
+ if (misc_class)
+ BUG_ON(misc_class != tee->miscdev.this_device->class);
+ else
+ misc_class = tee->miscdev.this_device->class;
+
+ pr_info("TEE Core: Register the misc device \"%s\" (id=%d,minor=%d)\n",
+ dev_name(tee->miscdev.this_device), tee->id,
+ tee->miscdev.minor);
+ return rc;
+}
+EXPORT_SYMBOL(tee_core_add);
+
+int tee_core_del(struct tee *tee)
+{
+ if (tee) {
+ pr_info("TEE Core: Destroy the misc device \"%s\" (id=%d)\n",
+ dev_name(tee->miscdev.this_device), tee->id);
+
+ tee_supp_deinit(tee);
+
+ tee_cleanup_sysfs(tee);
+ tee_delete_debug_dir(tee);
+
+ if (tee->miscdev.minor != MISC_DYNAMIC_MINOR) {
+ pr_info("TEE Core: Deregister the misc device \"%s\" (id=%d)\n",
+ dev_name(tee->miscdev.this_device), tee->id);
+ misc_deregister(&tee->miscdev);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(tee_core_del);
+
+static int __init tee_core_init(void)
+{
+ pr_info("\nTEE Core Framework initialization (ver %s)\n",
+ _TEE_CORE_FW_VER);
+ tee_init_debugfs();
+
+ return 0;
+}
+
+static void __exit tee_core_exit(void)
+{
+ tee_exit_debugfs();
+ pr_info("TEE Core Framework unregistered\n");
+}
+
+module_init(tee_core_init);
+module_exit(tee_core_exit);
+
+MODULE_AUTHOR("STMicroelectronics");
+MODULE_DESCRIPTION("STM Secure TEE Framework/Core TEEC v1.0");
+MODULE_SUPPORTED_DEVICE("");
+MODULE_VERSION(_TEE_CORE_FW_VER);
+MODULE_LICENSE("GPL");
diff --git a/core/tee_core_priv.h b/core/tee_core_priv.h
new file mode 100644
index 0000000..9032ece
--- /dev/null
+++ b/core/tee_core_priv.h
@@ -0,0 +1,41 @@
+
+#ifndef __TEE_CORE_PRIV_H__
+#define __TEE_CORE_PRIV_H__
+
+#include "linux/tee_core.h"
+#include "linux/tee_ioc.h"
+
+/* from tee_core_module.c */
+int tee_get(struct tee *tee);
+int tee_put(struct tee *tee);
+
+void tee_inc_stats(struct tee_stats_entry *entry);
+void tee_dec_stats(struct tee_stats_entry *entry);
+
+/* from tee_context.c */
+int tee_context_dump(struct tee *tee, char *buff, size_t len);
+
+struct tee_context *tee_context_create(struct tee *tee);
+void tee_context_destroy(struct tee_context *ctx);
+
+void tee_context_get(struct tee_context *ctx);
+void tee_context_put(struct tee_context *ctx);
+
+struct tee_shm *tee_context_create_tmpref_buffer(struct tee_context *ctx,
+ size_t size,
+ const void *buffer, int type);
+struct tee_shm *tee_context_alloc_shm_tmp(struct tee_context *ctx, size_t size,
+ const void *data, int type);
+int tee_context_copy_from_client(const struct tee_context *ctx, void *dest,
+ const void *src, size_t size);
+
+/* from tee_session.c */
+int tee_session_create_fd(struct tee_context *ctx, struct tee_cmd_io *cmd_io);
+struct tee_session *tee_session_create_and_open(struct tee_context *ctx,
+ struct tee_cmd_io *cmd_io);
+int tee_session_close_and_destroy(struct tee_session *sess);
+
+struct tee *tee_get_tee(const char *devname);
+int tee_session_invoke_be(struct tee_session *sess, struct tee_cmd_io *cmd_io);
+
+#endif
diff --git a/core/tee_debugfs.c b/core/tee_debugfs.c
new file mode 100644
index 0000000..8bb7307
--- /dev/null
+++ b/core/tee_debugfs.c
@@ -0,0 +1,74 @@
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+
+#include "linux/tee_core.h"
+#include "tee_debugfs.h"
+
+static struct dentry *tee_debugfs_dir;
+
+static ssize_t tee_trace_read(struct file *filp, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct tee *tee = filp->private_data;
+
+ char buff[258];
+ int len = sprintf(buff, "device=%s\n NO LOG AVAILABLE\n", tee->name);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buff, len);
+}
+
+static const struct file_operations log_tee_ops = {
+ .read = tee_trace_read,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
+void tee_create_debug_dir(struct tee *tee)
+{
+ struct dentry *entry;
+ struct device *dev = tee->miscdev.this_device;
+
+ if (!tee_debugfs_dir)
+ return;
+
+ tee->dbg_dir = debugfs_create_dir(dev_name(dev), tee_debugfs_dir);
+ if (!tee->dbg_dir)
+ goto error_create_file;
+
+ entry = debugfs_create_file("log", S_IRUGO, tee->dbg_dir,
+ tee, &log_tee_ops);
+ if (!entry)
+ goto error_create_file;
+
+ return;
+
+error_create_file:
+ dev_err(dev, "can't create debugfs file\n");
+ tee_delete_debug_dir(tee);
+}
+
+void tee_delete_debug_dir(struct tee *tee)
+{
+ if (!tee || !tee->dbg_dir)
+ return;
+
+ debugfs_remove_recursive(tee->dbg_dir);
+}
+
+void __init tee_init_debugfs(void)
+{
+ if (debugfs_initialized()) {
+ tee_debugfs_dir = debugfs_create_dir("tee", NULL);
+ if (IS_ERR(tee_debugfs_dir))
+ pr_err("can't create debugfs dir\n");
+ }
+}
+
+void __exit tee_exit_debugfs(void)
+{
+ if (tee_debugfs_dir)
+ debugfs_remove(tee_debugfs_dir);
+}
diff --git a/core/tee_debugfs.h b/core/tee_debugfs.h
new file mode 100644
index 0000000..d712987
--- /dev/null
+++ b/core/tee_debugfs.h
@@ -0,0 +1,13 @@
+
+#ifndef __TEE_DEBUGFS_H__
+#define __TEE_DEBUGFS_H__
+
+struct tee;
+
+void tee_create_debug_dir(struct tee *tee);
+void tee_delete_debug_dir(struct tee *tee);
+
+void __init tee_init_debugfs(void);
+void __exit tee_exit_debugfs(void);
+
+#endif /* __TEE_DEBUGFS_H__ */
diff --git a/core/tee_kernel_api.c b/core/tee_kernel_api.c
new file mode 100644
index 0000000..d3242ec
--- /dev/null
+++ b/core/tee_kernel_api.c
@@ -0,0 +1,264 @@
+/*
+* Copyright (C) STMicroelectronics 2014. All rights reserved.
+*
+* This code is STMicroelectronics proprietary and confidential.
+* Any use of the code for whatever purpose is subject to
+* specific written permission of STMicroelectronics SA.
+*/
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+
+#include "linux/tee_kernel_api.h"
+#include "linux/tee_core.h"
+#include "linux/tee_ioc.h"
+
+#include "tee_core_priv.h"
+#include "tee_shm.h"
+#include "tee_supp_com.h"
+
+#define TEE_TZ_DEVICE_NAME "opteearm3200"
+
+static void reset_tee_cmd(struct tee_cmd_io *cmd)
+{
+ cmd->fd_sess = -1;
+ cmd->cmd = 0;
+ cmd->uuid = NULL;
+ cmd->origin = TEEC_ORIGIN_API;
+ cmd->err = TEEC_SUCCESS;
+ cmd->data = NULL;
+ cmd->data_size = 0;
+ cmd->op = NULL;
+}
+
+TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context)
+{
+ struct tee *tee;
+ struct tee_context *ctx;
+ pr_cont("%s: > name=\"%s\"\n", __func__, name);
+
+ if (!context)
+ return TEEC_ERROR_BAD_PARAMETERS;
+
+ context->fd = 0;
+
+ if (name == NULL)
+ strncpy(context->devname, TEE_TZ_DEVICE_NAME,
+ sizeof(context->devname));
+ else
+ strncpy(context->devname, name, sizeof(context->devname));
+
+ tee = tee_get_tee(context->devname);
+ if (!tee) {
+ pr_err("%s - can't get device [%s]\n", __func__, name);
+ return TEEC_ERROR_BAD_PARAMETERS;
+ }
+
+ ctx = tee_context_create(tee);
+ if (IS_ERR_OR_NULL(ctx))
+ return TEEC_ERROR_BAD_PARAMETERS;
+
+ ctx->usr_client = 0;
+
+ /* TODO fixme will not work on 64-bit platform */
+ context->fd = (int)(uintptr_t)ctx;
+ BUG_ON(ctx != (struct tee_context *)(uintptr_t)context->fd);
+
+ pr_cont("%s: < ctx=%p is created\n", __func__, (void *)ctx);
+ return TEEC_SUCCESS;
+}
+EXPORT_SYMBOL(TEEC_InitializeContext);
+
+TEEC_Result TEEC_FinalizeContext(TEEC_Context *context)
+{
+ if (!context || !context->fd) {
+ pr_err("%s - can't release context %p:[%s]\n", __func__,
+ context, (context
+ && context->devname) ? context->devname : "");
+ return TEEC_ERROR_BAD_PARAMETERS;
+ }
+ /* TODO fixme will not work on 64-bit platform */
+ tee_context_destroy((struct tee_context *)(uintptr_t)context->fd);
+ return TEEC_SUCCESS;
+}
+EXPORT_SYMBOL(TEEC_FinalizeContext);
+
+TEEC_Result TEEC_OpenSession(TEEC_Context *context,
+ TEEC_Session *session,
+ const TEEC_UUID *destination,
+ uint32_t connectionMethod,
+ const void *connectionData,
+ TEEC_Operation *operation,
+ uint32_t *return_origin)
+{
+ TEEC_Operation dummy_op;
+ struct tee_cmd_io cmd;
+ struct tee_session *sess;
+ struct tee_context *ctx;
+
+ if (!operation) {
+ /*
+ * The code here exist because Global Platform API states that
+ * it is allowed to give operation as a NULL pointer.
+ * In kernel and secure world we in most cases don't want
+ * this to be NULL, hence we use this dummy operation when
+ * a client doesn't provide any operation.
+ */
+ memset(&dummy_op, 0, sizeof(TEEC_Operation));
+ operation = &dummy_op;
+ }
+
+ if (!context || !session || !destination || !operation
+ || !return_origin)
+ return TEEC_ERROR_BAD_PARAMETERS;
+
+ session->fd = 0;
+
+ /* TODO fixme will not work on 64-bit platform */
+ ctx = (struct tee_context *)(uintptr_t)context->fd;
+ reset_tee_cmd(&cmd);
+ cmd.op = operation;
+ cmd.uuid = (TEEC_UUID *) destination;
+
+ sess = tee_session_create_and_open(ctx, &cmd);
+ if (IS_ERR_OR_NULL(sess)) {
+ if (cmd.origin)
+ *return_origin = cmd.origin;
+ else
+ *return_origin = TEEC_ORIGIN_COMMS;
+ if (cmd.err)
+ return cmd.err;
+ else
+ return TEEC_ERROR_COMMUNICATION;
+ } else {
+ *return_origin = cmd.origin;
+ /* TODO fixme will not work on 64-bit platform */
+ session->fd = (int)(uintptr_t)sess;
+ BUG_ON(sess != (struct tee_session *)(uintptr_t)session->fd);
+ return cmd.err;
+ }
+}
+EXPORT_SYMBOL(TEEC_OpenSession);
+
+void TEEC_CloseSession(TEEC_Session *session)
+{
+ if (session && session->fd) {
+ /* TODO fixme will not work on 64-bit platform */
+ struct tee_session *sess =
+ (struct tee_session *)(uintptr_t)session->fd;
+ tee_session_close_and_destroy(sess);
+ }
+}
+EXPORT_SYMBOL(TEEC_CloseSession);
+
+TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
+ uint32_t commandID,
+ TEEC_Operation *operation,
+ uint32_t *return_origin)
+{
+ int ret = 0;
+ struct tee_cmd_io cmd;
+ struct tee_session *sess;
+
+ if (!session || !operation || !return_origin || !session->fd)
+ return TEEC_ERROR_BAD_PARAMETERS;
+
+ /* TODO fixme will not work on 64-bit platform */
+ sess = (struct tee_session *)(uintptr_t)session->fd;
+ reset_tee_cmd(&cmd);
+ cmd.cmd = commandID;
+ cmd.op = operation;
+
+ ret = tee_session_invoke_be(sess, &cmd);
+ if (ret) {
+ if (cmd.origin)
+ *return_origin = cmd.origin;
+ else
+ *return_origin = TEEC_ORIGIN_COMMS;
+ if (cmd.err)
+ return cmd.err;
+ else
+ return TEEC_ERROR_COMMUNICATION;
+ } else {
+ *return_origin = cmd.origin;
+ return cmd.err;
+ }
+}
+EXPORT_SYMBOL(TEEC_InvokeCommand);
+
+TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
+ TEEC_SharedMemory *sharedMem)
+{
+ if (!sharedMem)
+ return TEEC_ERROR_BAD_PARAMETERS;
+
+ sharedMem->registered = 1;
+ return TEEC_SUCCESS;
+}
+EXPORT_SYMBOL(TEEC_RegisterSharedMemory);
+
+TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
+ TEEC_SharedMemory *sharedMem)
+{
+ struct tee_shm *tee_shm;
+ struct tee_context *ctx;
+
+ if (!context || !sharedMem)
+ return TEEC_ERROR_BAD_PARAMETERS;
+
+ /* TODO fixme will not work on 64-bit platform */
+ ctx = (struct tee_context *)(uintptr_t)context->fd;
+
+ tee_shm = tee_shm_alloc(ctx, sharedMem->size, sharedMem->flags);
+ if (IS_ERR_OR_NULL(tee_shm)) {
+ pr_err
+ ("TEEC_AllocateSharedMemory: tee_shm_allocate(%zu) failed\n",
+ sharedMem->size);
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ }
+
+ pr_info("TEEC_AllocateSharedMemory (%zu) => paddr = %p, flags %x\n",
+ sharedMem->size, (void *)tee_shm->paddr, tee_shm->flags);
+
+ sharedMem->buffer = ioremap_nocache(tee_shm->paddr, sharedMem->size);
+ if (!sharedMem->buffer) {
+ pr_err("TEEC_AllocateSharedMemory: ioremap_nocache(%p, %zu) failed\n",
+ (void *)tee_shm->paddr, sharedMem->size);
+ tee_shm_free(tee_shm);
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ }
+
+ sharedMem->registered = 0;
+ sharedMem->flags |= tee_shm->flags;
+ /* TODO fixme will not work on 64-bit platform */
+ sharedMem->d.fd = (int)(uintptr_t)tee_shm;
+ BUG_ON(tee_shm != (struct tee_shm *)(uintptr_t)sharedMem->d.fd);
+
+ return TEEC_SUCCESS;
+}
+EXPORT_SYMBOL(TEEC_AllocateSharedMemory);
+
+void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory)
+{
+ struct tee_shm *shm;
+
+ if (!sharedMemory)
+ return;
+
+ if (sharedMemory->registered)
+ return;
+
+ /* TODO fixme will not work on 64-bit platform */
+ shm = (struct tee_shm *)(uintptr_t)sharedMemory->d.fd;
+
+ pr_info("TEEC_ReleaseSharedMemory (vaddr = %p)\n",
+ sharedMemory->buffer);
+
+ iounmap(sharedMemory->buffer);
+ sharedMemory->buffer = NULL;
+ tee_shm_free(shm);
+}
+EXPORT_SYMBOL(TEEC_ReleaseSharedMemory);
diff --git a/generic/tee_mutex_wait.c b/core/tee_mutex_wait.c
index 3648588..0574726 100644
--- a/generic/tee_mutex_wait.c
+++ b/core/tee_mutex_wait.c
@@ -16,8 +16,6 @@
*/
#include <linux/slab.h>
#include "tee_mutex_wait.h"
-#include "tee-op.h"
-#include "tee_driver.h"
struct tee_mutex_wait {
struct list_head link;
@@ -69,10 +67,10 @@ static void tee_mutex_wait_delete_entry(struct tee_mutex_wait *w)
kfree(w);
}
-void tee_mutex_wait_delete(struct device *dev, u32 key)
+void tee_mutex_wait_delete(struct device *dev,
+ struct tee_mutex_wait_private *priv,
+ u32 key)
{
- struct tee_mutex_wait_private *priv =
- &tee_get_drvdata(dev)->mutex_wait;
struct tee_mutex_wait *w;
mutex_lock(&priv->mu);
@@ -86,11 +84,12 @@ void tee_mutex_wait_delete(struct device *dev, u32 key)
mutex_unlock(&priv->mu);
}
+EXPORT_SYMBOL(tee_mutex_wait_delete);
-void tee_mutex_wait_wakeup(struct device *dev, u32 key, u32 wait_after)
+void tee_mutex_wait_wakeup(struct device *dev,
+ struct tee_mutex_wait_private *priv,
+ u32 key, u32 wait_after)
{
- struct tee_mutex_wait_private *priv =
- &tee_get_drvdata(dev)->mutex_wait;
struct tee_mutex_wait *w = tee_mutex_wait_get(dev, priv, key);
if (!w)
@@ -101,11 +100,12 @@ void tee_mutex_wait_wakeup(struct device *dev, u32 key, u32 wait_after)
mutex_unlock(&w->mu);
complete(&w->comp);
}
+EXPORT_SYMBOL(tee_mutex_wait_wakeup);
-void tee_mutex_wait_sleep(struct device *dev, u32 key, u32 wait_tick)
+void tee_mutex_wait_sleep(struct device *dev,
+ struct tee_mutex_wait_private *priv,
+ u32 key, u32 wait_tick)
{
- struct tee_mutex_wait_private *priv =
- &tee_get_drvdata(dev)->mutex_wait;
struct tee_mutex_wait *w = tee_mutex_wait_get(dev, priv, key);
u32 wait_after;
@@ -119,6 +119,7 @@ void tee_mutex_wait_sleep(struct device *dev, u32 key, u32 wait_tick)
if (TICK_GT(wait_tick, wait_after))
wait_for_completion_timeout(&w->comp, HZ);
}
+EXPORT_SYMBOL(tee_mutex_wait_sleep);
int tee_mutex_wait_init(struct tee_mutex_wait_private *priv)
{
@@ -126,6 +127,7 @@ int tee_mutex_wait_init(struct tee_mutex_wait_private *priv)
INIT_LIST_HEAD(&priv->db);
return 0;
}
+EXPORT_SYMBOL(tee_mutex_wait_init);
void tee_mutex_wait_exit(struct tee_mutex_wait_private *priv)
{
@@ -143,3 +145,4 @@ void tee_mutex_wait_exit(struct tee_mutex_wait_private *priv)
tee_mutex_wait_delete_entry(w);
}
}
+EXPORT_SYMBOL(tee_mutex_wait_exit);
diff --git a/generic/tee_mutex_wait.h b/core/tee_mutex_wait.h
index 0c359ac..20bd09d 100644
--- a/generic/tee_mutex_wait.h
+++ b/core/tee_mutex_wait.h
@@ -28,8 +28,15 @@ struct tee_mutex_wait_private {
int tee_mutex_wait_init(struct tee_mutex_wait_private *priv);
void tee_mutex_wait_exit(struct tee_mutex_wait_private *priv);
-void tee_mutex_wait_delete(struct device *dev, u32 key);
-void tee_mutex_wait_wakeup(struct device *dev, u32 key, u32 wait_after);
-void tee_mutex_wait_sleep(struct device *dev, u32 key, u32 wait_tick);
+
+void tee_mutex_wait_delete(struct device *dev,
+ struct tee_mutex_wait_private *priv,
+ u32 key);
+void tee_mutex_wait_wakeup(struct device *dev,
+ struct tee_mutex_wait_private *priv,
+ u32 key, u32 wait_after);
+void tee_mutex_wait_sleep(struct device *dev,
+ struct tee_mutex_wait_private *priv,
+ u32 key, u32 wait_tick);
#endif /*TEE_MUTEX_WAIT_H*/
diff --git a/core/tee_session.c b/core/tee_session.c
new file mode 100644
index 0000000..70166f2
--- /dev/null
+++ b/core/tee_session.c
@@ -0,0 +1,1042 @@
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/file.h>
+#include <linux/atomic.h>
+#include <linux/uaccess.h>
+#include <linux/anon_inodes.h>
+
+#include "tee_shm.h"
+#include "tee_core_priv.h"
+
+static int _init_tee_cmd(struct tee_session *sess, struct tee_cmd_io *cmd_io,
+ struct tee_cmd *cmd);
+static void _update_client_tee_cmd(struct tee_session *sess,
+ struct tee_cmd_io *cmd_io,
+ struct tee_cmd *cmd);
+static void _release_tee_cmd(struct tee_session *sess, struct tee_cmd *cmd);
+
+#define _DEV_TEE _DEV(sess->ctx->tee)
+
+#define INMSG dev_dbg(_DEV_TEE, "%s: >\n", __func__)
+#define OUTMSG(val) dev_dbg(_DEV_TEE, "%s: < %d\n", __func__, (int)val)
+
+#define _UUID_STR_SIZE 35
+static char *_uuid_to_str(const TEEC_UUID *uuid)
+{
+ static char uuid_str[_UUID_STR_SIZE];
+
+ if (uuid) {
+ sprintf(uuid_str,
+ "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
+ uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
+ uuid->clockSeqAndNode[0], uuid->clockSeqAndNode[1],
+ uuid->clockSeqAndNode[2], uuid->clockSeqAndNode[3],
+ uuid->clockSeqAndNode[4], uuid->clockSeqAndNode[5],
+ uuid->clockSeqAndNode[6], uuid->clockSeqAndNode[7]);
+ } else {
+ sprintf(uuid_str, "NULL");
+ }
+
+ return uuid_str;
+}
+
+static int tee_copy_from_user(struct tee_context *ctx, void *to, void *from,
+ size_t size)
+{
+ if (ctx->usr_client)
+ return copy_from_user(to, from, size);
+ else {
+ memcpy(to, from, size);
+ return 0;
+ }
+}
+
+static int tee_copy_to_user(struct tee_context *ctx, void *to, void *from,
+ size_t size)
+{
+ if (ctx->usr_client)
+ return copy_to_user(to, from, size);
+ else {
+ memcpy(to, from, size);
+ return 0;
+ }
+}
+
+/* Defined as macro to let the put_user macro see the types */
+#define tee_put_user(ctx, from, to) \
+ do { \
+ if ((ctx)->usr_client) \
+ put_user(from, to); \
+ else \
+ *to = from; \
+ } while (0)
+
+static inline int tee_session_is_opened(struct tee_session *sess)
+{
+ if (sess && sess->sessid)
+ return (sess->sessid != 0);
+ return 0;
+}
+
+static int tee_session_open_be(struct tee_session *sess,
+ struct tee_cmd_io *cmd_io)
+{
+ int ret = -EINVAL;
+ struct tee *tee;
+ struct tee_cmd cmd;
+
+ BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
+
+ tee = sess->ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > open a new session", __func__);
+
+ sess->sessid = 0;
+ ret = _init_tee_cmd(sess, cmd_io, &cmd);
+ if (ret)
+ goto out;
+
+ if (cmd.uuid) {
+ dev_dbg(_DEV(tee), "%s: UUID=%s\n", __func__,
+ _uuid_to_str((TEEC_UUID *) cmd.uuid->kaddr));
+ }
+
+ ret = tee->ops->open(sess, &cmd);
+ if (ret == 0)
+ _update_client_tee_cmd(sess, cmd_io, &cmd);
+ else {
+ /* propagate the reason of the error */
+ cmd_io->origin = cmd.origin;
+ cmd_io->err = cmd.err;
+ }
+
+out:
+ _release_tee_cmd(sess, &cmd);
+ dev_dbg(_DEV(tee), "%s: < ret=%d, sessid=%08x", __func__, ret,
+ sess->sessid);
+ return ret;
+}
+
+int tee_session_invoke_be(struct tee_session *sess, struct tee_cmd_io *cmd_io)
+{
+ int ret = -EINVAL;
+ struct tee *tee;
+ struct tee_cmd cmd;
+
+ BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
+
+ tee = sess->ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > sessid=%08x, cmd=0x%08x\n", __func__,
+ sess->sessid, cmd_io->cmd);
+
+ ret = _init_tee_cmd(sess, cmd_io, &cmd);
+ if (ret)
+ goto out;
+
+ ret = tee->ops->invoke(sess, &cmd);
+ if (!ret)
+ _update_client_tee_cmd(sess, cmd_io, &cmd);
+ else {
+ /* propagate the reason of the error */
+ cmd_io->origin = cmd.origin;
+ cmd_io->err = cmd.err;
+ }
+
+out:
+ _release_tee_cmd(sess, &cmd);
+ dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
+ return ret;
+}
+
+static int tee_session_close_be(struct tee_session *sess)
+{
+ int ret = -EINVAL;
+ struct tee *tee;
+
+ BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
+
+ tee = sess->ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > sessid=%08x", __func__, sess->sessid);
+
+ ret = tee->ops->close(sess);
+ sess->sessid = 0;
+
+ dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
+ return ret;
+}
+
+static int tee_session_cancel_be(struct tee_session *sess,
+ struct tee_cmd_io *cmd_io)
+{
+ int ret = -EINVAL;
+ struct tee *tee;
+ struct tee_cmd cmd;
+
+ BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
+
+ tee = sess->ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > sessid=%08x, cmd=0x%08x\n", __func__,
+ sess->sessid, cmd_io->cmd);
+
+ ret = _init_tee_cmd(sess, cmd_io, &cmd);
+ if (ret)
+ goto out;
+
+ ret = tee->ops->cancel(sess, &cmd);
+
+out:
+ _release_tee_cmd(sess, &cmd);
+ dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
+ return ret;
+}
+
+static int tee_do_invoke_command(struct tee_session *sess,
+ struct tee_cmd_io __user *u_cmd)
+{
+ int ret = -EINVAL;
+ struct tee *tee;
+ struct tee_cmd_io k_cmd;
+ struct tee_context *ctx;
+
+ BUG_ON(!sess->ctx);
+ BUG_ON(!sess->ctx->tee);
+ ctx = sess->ctx;
+ tee = sess->ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > sessid=%08x\n", __func__, sess->sessid);
+
+ BUG_ON(!sess->sessid);
+
+ if (tee_copy_from_user
+ (ctx, &k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) {
+ dev_err(_DEV(tee), "%s: tee_copy_from_user failed\n", __func__);
+ goto exit;
+ }
+
+ if ((k_cmd.op == NULL) || (k_cmd.uuid != NULL) ||
+ (k_cmd.data != NULL) || (k_cmd.data_size != 0)) {
+ dev_err(_DEV(tee),
+ "%s: op or/and data parameters are not valid\n",
+ __func__);
+ goto exit;
+ }
+
+ ret = tee_session_invoke_be(sess, &k_cmd);
+ if (ret)
+ dev_err(_DEV(tee), "%s: tee_invoke_command failed\n", __func__);
+
+ tee_put_user(ctx, k_cmd.err, &u_cmd->err);
+ tee_put_user(ctx, k_cmd.origin, &u_cmd->origin);
+
+exit:
+ dev_dbg(_DEV(tee), "%s: < ret=%d\n", __func__, ret);
+ return ret;
+}
+
+static int tee_do_cancel_cmd(struct tee_session *sess,
+ struct tee_cmd_io __user *u_cmd)
+{
+ int ret = -EINVAL;
+ struct tee *tee;
+ struct tee_cmd_io k_cmd;
+ struct tee_context *ctx;
+
+ BUG_ON(!sess->ctx);
+ BUG_ON(!sess->ctx->tee);
+ ctx = sess->ctx;
+ tee = sess->ctx->tee;
+
+ dev_dbg(sess->ctx->tee->dev, "%s: > sessid=%08x\n", __func__,
+ sess->sessid);
+
+ BUG_ON(!sess->sessid);
+
+ if (tee_copy_from_user
+ (ctx, &k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) {
+ dev_err(_DEV(tee), "%s: tee_copy_from_user failed\n", __func__);
+ goto exit;
+ }
+
+ if ((k_cmd.op == NULL) || (k_cmd.uuid != NULL) ||
+ (k_cmd.data != NULL) || (k_cmd.data_size != 0)) {
+ dev_err(_DEV(tee),
+ "%s: op or/and data parameters are not valid\n",
+ __func__);
+ goto exit;
+ }
+
+ ret = tee_session_cancel_be(sess, &k_cmd);
+ if (ret)
+ dev_err(_DEV(tee), "%s: tee_invoke_command failed\n", __func__);
+
+ tee_put_user(ctx, k_cmd.err, &u_cmd->err);
+ tee_put_user(ctx, k_cmd.origin, &u_cmd->origin);
+
+exit:
+ dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
+ return ret;
+}
+
+static long tee_session_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct tee *tee;
+ struct tee_session *sess = filp->private_data;
+ int ret;
+
+ BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
+
+ tee = sess->ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > cmd nr=%d\n", __func__, _IOC_NR(cmd));
+
+ switch (cmd) {
+ case TEE_INVOKE_COMMAND_IOC:
+ ret =
+ tee_do_invoke_command(sess,
+ (struct tee_cmd_io __user *)arg);
+ break;
+ case TEE_REQUEST_CANCELLATION_IOC:
+ ret = tee_do_cancel_cmd(sess, (struct tee_cmd_io __user *)arg);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ dev_dbg(_DEV(tee), "%s: < ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int tee_session_release(struct inode *inode, struct file *filp)
+{
+ struct tee_session *sess = filp->private_data;
+ int ret = 0;
+ struct tee *tee;
+
+ BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
+ tee = sess->ctx->tee;
+
+ ret = tee_session_close_and_destroy(sess);
+ return ret;
+}
+
+const struct file_operations tee_session_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = tee_session_ioctl,
+ .release = tee_session_release,
+};
+
+int tee_session_close_and_destroy(struct tee_session *sess)
+{
+ int ret;
+ struct tee *tee;
+ struct tee_context *ctx;
+
+ if (!sess || !sess->ctx || !sess->ctx->tee)
+ return -EINVAL;
+
+ ctx = sess->ctx;
+ tee = ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > sess=%p\n", __func__, sess);
+
+ if (!tee_session_is_opened(sess))
+ return -EINVAL;
+
+ ret = tee_session_close_be(sess);
+
+ mutex_lock(&sess->ctx->tee->lock);
+ tee_dec_stats(&tee->stats[TEE_STATS_SESSION_IDX]);
+ list_del(&sess->entry);
+ mutex_unlock(&sess->ctx->tee->lock);
+
+ devm_kfree(_DEV(tee), sess);
+ tee_context_put(ctx);
+ tee_put(tee);
+
+ dev_dbg(_DEV(tee), "%s: <\n", __func__);
+ return ret;
+}
+
+struct tee_session *tee_session_create_and_open(struct tee_context *ctx,
+ struct tee_cmd_io *cmd_io)
+{
+ int ret = 0;
+ struct tee_session *sess;
+ struct tee *tee;
+
+ BUG_ON(!ctx->tee);
+
+ tee = ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: >\n", __func__);
+ ret = tee_get(tee);
+ if (ret)
+ return ERR_PTR(-EBUSY);
+
+ sess = devm_kzalloc(_DEV(tee), sizeof(struct tee_session), GFP_KERNEL);
+ if (!sess) {
+ dev_err(_DEV(tee), "%s: tee_session allocation() failed\n",
+ __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ tee_context_get(ctx);
+ sess->ctx = ctx;
+
+ ret = tee_session_open_be(sess, cmd_io);
+ if (ret || !sess->sessid || cmd_io->err) {
+ dev_err(_DEV(tee), "%s: ERROR ret=%d (err=0x%08x, org=%d, sessid=0x%08x)\n",
+ __func__, ret, cmd_io->err,
+ cmd_io->origin, sess->sessid);
+ tee_put(tee);
+ tee_context_put(ctx);
+ devm_kfree(_DEV(tee), sess);
+ if (ret)
+ return ERR_PTR(ret);
+ else
+ return NULL;
+ }
+
+ mutex_lock(&tee->lock);
+ tee_inc_stats(&tee->stats[TEE_STATS_SESSION_IDX]);
+ list_add_tail(&sess->entry, &ctx->list_sess);
+ mutex_unlock(&tee->lock);
+
+ dev_dbg(_DEV(tee), "%s: < sess=%p\n", __func__, sess);
+ return sess;
+}
+
+int tee_session_create_fd(struct tee_context *ctx, struct tee_cmd_io *cmd_io)
+{
+ int ret;
+ struct tee_session *sess;
+ struct tee *tee = ctx->tee;
+
+ BUG_ON(cmd_io->fd_sess > 0);
+
+ dev_dbg(_DEV(tee), "%s: >\n", __func__);
+
+ sess = tee_session_create_and_open(ctx, cmd_io);
+ if (IS_ERR_OR_NULL(sess)) {
+ ret = PTR_ERR(sess);
+ dev_dbg(_DEV(tee), "%s: ERROR can't create the session (ret=%d, err=0x%08x, org=%d)\n",
+ __func__, ret, cmd_io->err, cmd_io->origin);
+ cmd_io->fd_sess = -1;
+ goto out;
+ }
+
+ /* Retrieve a fd */
+ cmd_io->fd_sess = -1;
+ ret =
+ anon_inode_getfd("tee_session", &tee_session_fops, sess, O_CLOEXEC);
+ if (ret < 0) {
+ dev_err(_DEV(tee), "%s: ERROR can't get a fd (ret=%d)\n",
+ __func__, ret);
+ tee_session_close_and_destroy(sess);
+ goto out;
+ }
+ cmd_io->fd_sess = ret;
+ ret = 0;
+
+out:
+ dev_dbg(_DEV(tee), "%s: < ret=%d, sess=%p, fd=%d\n", __func__,
+ ret, sess, cmd_io->fd_sess);
+ return ret;
+}
+
+static bool tee_session_is_supported_type(struct tee_session *sess, int type)
+{
+ switch (type) {
+ case TEEC_NONE:
+ case TEEC_VALUE_INPUT:
+ case TEEC_VALUE_OUTPUT:
+ case TEEC_VALUE_INOUT:
+ case TEEC_MEMREF_TEMP_INPUT:
+ case TEEC_MEMREF_TEMP_OUTPUT:
+ case TEEC_MEMREF_TEMP_INOUT:
+ case TEEC_MEMREF_WHOLE:
+ case TEEC_MEMREF_PARTIAL_INPUT:
+ case TEEC_MEMREF_PARTIAL_OUTPUT:
+ case TEEC_MEMREF_PARTIAL_INOUT:
+ return true;
+ default:
+ dev_err(_DEV_TEE, "type is invalid (type %02x)\n", type);
+ return false;
+ }
+}
+
+static int _copy_op(struct tee_session *sess, struct tee_cmd_io *cmd_io,
+ struct tee_cmd *cmd)
+{
+ int res = -EINVAL;
+ int idx;
+ TEEC_Operation op;
+ struct tee_data *param = &cmd->param;
+ struct tee *tee;
+ struct tee_context *ctx;
+
+ BUG_ON(!sess->ctx);
+ BUG_ON(!sess->ctx->tee);
+ ctx = sess->ctx;
+ tee = sess->ctx->tee;
+
+ dev_dbg(_DEV(tee), "%s: > sessid=%08x\n", __func__, sess->sessid);
+
+ if (tee_context_copy_from_client
+ (sess->ctx, &op, cmd_io->op, sizeof(TEEC_Operation)))
+ goto out;
+
+ cmd->param.type_original = op.paramTypes;
+
+ if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
+ TEEC_NONE, TEEC_NONE, TEEC_NONE)) {
+ param->type = cmd->param.type_original;
+ res = 0;
+ goto out;
+ }
+
+ for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
+ int type = TEEC_PARAM_TYPE_GET(op.paramTypes, idx);
+ switch (type) {
+ case TEEC_NONE:
+ break;
+ case TEEC_VALUE_INPUT:
+ case TEEC_VALUE_OUTPUT:
+ case TEEC_VALUE_INOUT:
+ param->params[idx].value = op.params[idx].value;
+ dev_dbg(_DEV_TEE,
+ "%s: param[%d]:type=%d,a=%08x,b=%08x (VALUE)\n",
+ __func__, idx, type, param->params[idx].value.a,
+ param->params[idx].value.b);
+ break;
+
+ case TEEC_MEMREF_TEMP_INPUT:
+ case TEEC_MEMREF_TEMP_OUTPUT:
+ case TEEC_MEMREF_TEMP_INOUT:
+ dev_dbg(_DEV_TEE,
+ "> param[%d]:type=%d,buffer=%p,s=%zu (TMPREF)\n",
+ idx, type, op.params[idx].tmpref.buffer,
+ op.params[idx].tmpref.size);
+ param->params[idx].shm =
+ tee_context_create_tmpref_buffer(sess->ctx,
+ op.params[idx].
+ tmpref.size,
+ op.params[idx].
+ tmpref.buffer,
+ type);
+ if (IS_ERR_OR_NULL(param->params[idx].shm))
+ return -ENOMEM;
+ dev_dbg(_DEV_TEE, "< %d %p:%zu (TMPREF)\n",
+ idx, (void *)param->params[idx].shm->paddr,
+ param->params[idx].shm->size_req);
+ break;
+
+ case TEEC_MEMREF_WHOLE:
+ if (sess->ctx->usr_client) {
+ if (tee_copy_from_user(ctx, &param->c_shm[idx],
+ op.params[idx].memref.
+ parent,
+ sizeof
+ (TEEC_SharedMemory))) {
+ res = TEEC_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+ } else
+ param->c_shm[idx] =
+ *op.params[idx].memref.parent;
+
+ BUG_ON(!param->c_shm[idx].buffer);
+ BUG_ON(!param->c_shm[idx].size);
+
+ if (param->c_shm[idx].flags == TEEC_MEM_INPUT)
+ type = TEEC_MEMREF_TEMP_INPUT;
+ else if (param->c_shm[idx].flags == TEEC_MEM_OUTPUT)
+ type = TEEC_MEMREF_TEMP_OUTPUT;
+ else if (param->c_shm[idx].flags ==
+ (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))
+ type = TEEC_MEMREF_TEMP_INOUT;
+
+ if (check_shm
+ (tee, (struct tee_shm_io *)&param->c_shm[idx])) {
+ dev_dbg(_DEV_TEE,
+ "> param[%d]:type=%d,buffer=%p, s=%zu (WHOLE)\n",
+ idx, type, op.params[idx].tmpref.buffer,
+ param->c_shm[idx].size);
+
+ param->params[idx].shm =
+ tee_context_create_tmpref_buffer(sess->ctx,
+ param->c_shm[idx].size,
+ param->c_shm[idx].buffer,
+ type);
+ if (IS_ERR_OR_NULL(param->params[idx].shm))
+ return -ENOMEM;
+
+ dev_dbg(_DEV_TEE, "< %d %p:%zu (WHOLE)\n",
+ idx,
+ (void *)param->params[idx].shm->paddr,
+ param->params[idx].shm->size_req);
+ } else {
+ struct tee_shm *shm;
+ /* The buffer is already allocated by the tee
+ * get a reference on it
+ */
+ shm =
+ tee_shm_get(sess->ctx,
+ (struct tee_shm_io *)&param->
+ c_shm[idx]);
+ if (!shm)
+ /* not allocated by us,
+ * is it a use case ? */
+ BUG_ON(1);
+
+ param->params[idx].shm =
+ devm_kzalloc(tee->dev,
+ sizeof(struct tee_shm),
+ GFP_KERNEL);
+ if (!param->params[idx].shm)
+ return -ENOMEM;
+
+ param->params[idx].shm->parent = shm;
+ param->params[idx].shm->ctx = sess->ctx;
+ param->params[idx].shm->tee = tee;
+ param->params[idx].shm->dev = tee->dev;
+ param->params[idx].shm->size_req =
+ param->c_shm[idx].size;
+ param->params[idx].shm->size_alloc = 0;
+ param->params[idx].shm->kaddr = shm->kaddr;
+ param->params[idx].shm->paddr = shm->paddr;
+ param->params[idx].shm->flags =
+ shm->flags | TEE_SHM_PARENT;
+ }
+ break;
+
+ case TEEC_MEMREF_PARTIAL_INPUT:
+ case TEEC_MEMREF_PARTIAL_OUTPUT:
+ case TEEC_MEMREF_PARTIAL_INOUT:{
+ uint32_t offset = op.params[idx].memref.offset;
+ uint32_t size = op.params[idx].memref.size;
+
+ if (sess->ctx->usr_client) {
+ if (tee_copy_from_user
+ (ctx, &param->c_shm[idx],
+ op.params[idx].memref.parent,
+ sizeof(TEEC_SharedMemory))) {
+ res = TEEC_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+ } else
+ param->c_shm[idx] =
+ *op.params[idx].memref.parent;
+
+ dev_dbg(_DEV_TEE,
+ "> param[%d]:type=%d,buffer=%p, offset=%x s=%d (PARTIAL)\n",
+ idx, type, param->c_shm[idx].buffer,
+ offset, size);
+
+ if (type == TEEC_MEMREF_PARTIAL_INPUT)
+ type = TEEC_MEMREF_TEMP_INPUT;
+ else if (type == TEEC_MEMREF_PARTIAL_OUTPUT)
+ type = TEEC_MEMREF_TEMP_OUTPUT;
+ else if (type == TEEC_MEMREF_PARTIAL_INOUT)
+ type = TEEC_MEMREF_TEMP_INOUT;
+
+
+ if (check_shm
+ (tee,
+ (struct tee_shm_io *)&param->c_shm[idx])) {
+
+ param->params[idx].shm =
+ tee_context_create_tmpref_buffer
+ (sess->ctx, size,
+ param->c_shm[idx].buffer + offset,
+ type);
+ if (IS_ERR_OR_NULL(
+ param->params[idx].shm))
+ return -ENOMEM;
+
+ } else {
+ struct tee_shm *shm;
+ /* The buffer is already allocated by
+ * the tee
+ * get a reference on it
+ */
+
+ shm =
+ tee_shm_get(sess->ctx,
+ (struct tee_shm_io *)
+ &param->c_shm[idx]);
+ if (!shm)
+ /* not allocated by us,
+ * is it a use case ? */
+ BUG_ON(1);
+
+ param->params[idx].shm =
+ devm_kzalloc(tee->dev,
+ sizeof(struct tee_shm),
+ GFP_KERNEL);
+ if (!param->params[idx].shm)
+ return -ENOMEM;
+
+ param->params[idx].shm->parent = shm;
+ param->params[idx].shm->ctx = sess->ctx;
+ param->params[idx].shm->tee = tee;
+ param->params[idx].shm->dev = tee->dev;
+ param->params[idx].shm->size_req = size;
+ param->params[idx].shm->size_alloc = 0;
+ param->params[idx].shm->kaddr =
+ shm->kaddr + offset;
+ param->params[idx].shm->paddr =
+ shm->paddr + offset;
+ param->params[idx].shm->flags =
+ shm->flags | TEE_SHM_PARENT;
+
+
+ }
+ dev_dbg(_DEV_TEE, "< %d %p:%zu (PARTIAL)\n",
+ idx,
+ (void *)param->params[idx].shm->paddr,
+ param->params[idx].shm->size_req);
+ break;
+ }
+ default:
+ BUG_ON(1);
+ }
+
+ param->type |= (type << (idx * 4));
+ }
+ res = 0;
+
+out:
+ dev_dbg(_DEV(tee), "%s: < fd=%d\n", __func__, res);
+ return res;
+}
+
+static int _copy_ta_image(struct tee_session *sess, struct tee_cmd_io *cmd_io,
+ struct tee_cmd *cmd)
+{
+ int res = -EINVAL;
+
+ dev_dbg(_DEV_TEE, "%s: > data=%p uuid=%p\n",
+ __func__, cmd_io->data, cmd_io->uuid);
+
+ if (((cmd_io->data != NULL) && (cmd_io->data_size == 0)) ||
+ ((cmd_io->data == NULL) && (cmd_io->data_size != 0)))
+ goto out_failed;
+
+ if ((cmd_io->data != NULL) && (cmd_io->data_size > 0)) {
+ dev_dbg(_DEV_TEE, "%s: copy DATA image (s=%d)...\n", __func__,
+ cmd_io->data_size);
+ cmd->ta =
+ tee_context_alloc_shm_tmp(sess->ctx, cmd_io->data_size,
+ cmd_io->data, TEEC_MEM_INPUT);
+ if (IS_ERR_OR_NULL(cmd->ta))
+ goto out_failed;
+ }
+
+ if (cmd_io->uuid != NULL) {
+ dev_dbg(_DEV_TEE, "%s: copy UUID value...\n", __func__);
+ cmd->uuid =
+ tee_context_alloc_shm_tmp(sess->ctx, sizeof(*cmd_io->uuid),
+ cmd_io->uuid, TEEC_MEM_INPUT);
+ if (IS_ERR_OR_NULL(cmd->uuid))
+ goto out_failed;
+ }
+
+ res = 0;
+ goto out;
+
+out_failed:
+ tee_shm_free(cmd->uuid);
+ tee_shm_free(cmd->ta);
+
+out:
+ dev_dbg(_DEV_TEE, "%s: < res=%d", __func__, res);
+ return res;
+}
+
+static int _init_tee_cmd(struct tee_session *sess, struct tee_cmd_io *cmd_io,
+ struct tee_cmd *cmd)
+{
+ int ret = -EINVAL;
+
+ dev_dbg(_DEV_TEE, "%s: > set tee_cmd...\n", __func__);
+
+ memset(cmd, 0, sizeof(struct tee_cmd));
+
+ cmd->cmd = cmd_io->cmd;
+ cmd->origin = TEEC_ORIGIN_TEE;
+ cmd->err = TEEC_ERROR_BAD_PARAMETERS;
+ cmd_io->origin = cmd->origin;
+ cmd_io->err = cmd->err;
+
+ ret = _copy_op(sess, cmd_io, cmd);
+ if (ret)
+ goto out;
+
+ ret = _copy_ta_image(sess, cmd_io, cmd);
+
+out:
+ if (ret)
+ _release_tee_cmd(sess, cmd);
+ dev_dbg(_DEV_TEE, "%s: < ret=%d\n", __func__, ret);
+ return ret;
+}
+
+static void _update_client_tee_cmd(struct tee_session *sess,
+ struct tee_cmd_io *cmd_io,
+ struct tee_cmd *cmd)
+{
+ int idx;
+ struct tee_context *ctx;
+ BUG_ON(!cmd_io);
+ BUG_ON(!cmd_io->op);
+ BUG_ON(!cmd_io->op->params);
+ BUG_ON(!cmd);
+ BUG_ON(!sess->ctx);
+ ctx = sess->ctx;
+
+ dev_dbg(_DEV_TEE, "%s: returned err=0x%08x (origin=%d)\n", __func__,
+ cmd->err, cmd->origin);
+
+ cmd_io->origin = cmd->origin;
+ cmd_io->err = cmd->err;
+
+ if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
+ TEEC_NONE, TEEC_NONE, TEEC_NONE))
+ return;
+
+ for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
+ int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
+ dev_dbg(_DEV_TEE, "%s: id %d type %d\n", __func__, idx, type);
+ BUG_ON(!tee_session_is_supported_type(sess, type));
+ switch (type) {
+ case TEEC_NONE:
+ case TEEC_VALUE_INPUT:
+ case TEEC_MEMREF_TEMP_INPUT:
+ case TEEC_MEMREF_PARTIAL_INPUT:
+ break;
+ case TEEC_VALUE_OUTPUT:
+ case TEEC_VALUE_INOUT:{
+ dev_dbg(_DEV_TEE, "%s: a=%08x, b=%08x\n",
+ __func__,
+ cmd->param.params[idx].value.a,
+ cmd->param.params[idx].value.b);
+ if (tee_copy_to_user
+ (ctx, &cmd_io->op->params[idx].value,
+ &cmd->param.params[idx].value,
+ sizeof(cmd_io->op->params[idx].value)))
+ dev_err(_DEV_TEE,
+ "%s:%d: can't update %d result to user\n",
+ __func__, __LINE__, idx);
+ break;
+ }
+ case TEEC_MEMREF_TEMP_OUTPUT:
+ case TEEC_MEMREF_TEMP_INOUT:{
+ /* Returned updated size */
+ size_t size =
+ cmd->param.params[idx].shm->size_req;
+ if (size !=
+ cmd_io->op->params[idx].tmpref.size) {
+ dev_dbg(_DEV_TEE,
+ "Size has been updated by the TA %zu != %zu\n",
+ size,
+ cmd_io->op->params[idx].tmpref.
+ size);
+ tee_put_user(ctx, size,
+ &cmd_io->op->params[idx].
+ tmpref.size);
+ }
+
+ BUG_ON(!cmd->param.params[idx].shm);
+ BUG_ON(!
+ (cmd->param.params[idx].shm->
+ flags & TEE_SHM_TEMP));
+ dev_dbg(_DEV_TEE, "%s: tmpref %p\n", __func__,
+ cmd->param.params[idx].shm->kaddr);
+
+ /* ensure we do not exceed
+ * the shared buffer length */
+ if (size > cmd_io->op->params[idx].tmpref.size)
+ dev_err(_DEV_TEE,
+ " *** Wrong returned size from %d:%zu > %zu\n",
+ idx, size,
+ cmd_io->op->params[idx].tmpref.
+ size);
+
+ else if (tee_copy_to_user
+ (ctx,
+ cmd_io->op->params[idx].tmpref.buffer,
+ cmd->param.params[idx].shm->kaddr,
+ size))
+ dev_err(_DEV_TEE,
+ "%s:%d: can't update %d result to user\n",
+ __func__, __LINE__, idx);
+ break;
+ }
+ case TEEC_MEMREF_WHOLE:{
+ /* Returned updated size */
+ size_t size =
+ cmd->param.params[idx].shm->size_req;
+ if (size !=
+ cmd_io->op->params[idx].memref.size) {
+ dev_dbg(_DEV_TEE,
+ "Size has been updated by the TA %zu != %zu\n",
+ size,
+ cmd_io->op->params[idx].memref.
+ size);
+ tee_put_user(ctx, size,
+ &cmd_io->op->params[idx].
+ memref.size);
+ }
+
+ /* ensure we do not exceed
+ * the shared buffer length */
+ if (size > cmd->param.c_shm[idx].size)
+ dev_err(_DEV_TEE,
+ " *** Wrong returned size from %d:%zu > %zu\n",
+ idx, size,
+ cmd->param.c_shm[idx].size);
+
+ else if ((cmd->param.params[idx].shm->flags &
+ (TEE_SHM_MAPPED | TEE_SHM_TEMP)) ==
+ (TEE_SHM_MAPPED | TEE_SHM_TEMP)) {
+ BUG_ON(!cmd->param.c_shm[idx].buffer);
+ BUG_ON(!cmd->param.c_shm[idx].size > 0);
+ dev_dbg(_DEV_TEE, "%s: whole %p\n",
+ __func__,
+ cmd->param.params[idx].shm->
+ kaddr);
+ if (tee_copy_to_user
+ (ctx, cmd->param.c_shm[idx].buffer,
+ cmd->param.params[idx].shm->kaddr,
+ size))
+ dev_err(_DEV_TEE,
+ "%s: can't update %d result to user\n",
+ __func__, idx);
+ }
+ break;
+ }
+ case TEEC_MEMREF_PARTIAL_OUTPUT:
+ case TEEC_MEMREF_PARTIAL_INOUT:{
+ int offset =
+ cmd_io->op->params[idx].memref.offset;
+ /* Returned updated size */
+ size_t size =
+ cmd->param.params[idx].shm->size_req;
+
+ if (size !=
+ cmd_io->op->params[idx].memref.size) {
+ dev_dbg(_DEV_TEE,
+ "Size has been updated by the TA %zu != %zu\n",
+ size,
+ cmd_io->op->params[idx].memref.
+ size);
+ tee_put_user(ctx, size,
+ &cmd_io->op->params[idx].
+ memref.size);
+ }
+
+ /* ensure we do not exceed
+ * the shared buffer length */
+ if ((offset + size) >
+ cmd->param.c_shm[idx].size)
+ dev_err(_DEV_TEE,
+ " *** Wrong returned size from %d:%d +%zu > %zu\n",
+ idx, offset, size,
+ cmd->param.c_shm[idx].size);
+
+ /* If we allocated a tmpref buffer,
+ * copy back data to the user buffer */
+ else if ((cmd->param.params[idx].shm->flags &
+ (TEE_SHM_MAPPED | TEE_SHM_TEMP)) ==
+ (TEE_SHM_MAPPED | TEE_SHM_TEMP)) {
+ BUG_ON(!cmd->param.c_shm[idx].buffer);
+ BUG_ON(!cmd->param.c_shm[idx].size > 0);
+ if (tee_copy_to_user
+ (ctx,
+ cmd->param.c_shm[idx].buffer +
+ offset,
+ cmd->param.params[idx].shm->kaddr,
+ size))
+ dev_err(_DEV_TEE,
+ "%s: can't update %d result to user\n",
+ __func__, idx);
+ }
+ break;
+ }
+ default:
+ BUG_ON(1);
+ }
+ }
+
+}
+
+static void _release_tee_cmd(struct tee_session *sess, struct tee_cmd *cmd)
+{
+ int idx;
+ struct tee_context *ctx;
+
+ BUG_ON(!cmd);
+ BUG_ON(!sess);
+ BUG_ON(!sess->ctx);
+ BUG_ON(!sess->ctx->tee);
+
+ ctx = sess->ctx;
+
+ dev_dbg(_DEV_TEE, "%s: > free the temporary objects...\n", __func__);
+
+ tee_shm_free(cmd->ta);
+ tee_shm_free(cmd->uuid);
+
+ if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
+ TEEC_NONE, TEEC_NONE, TEEC_NONE))
+ goto out;
+
+ for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
+ int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
+ switch (type) {
+ case TEEC_NONE:
+ case TEEC_VALUE_INPUT:
+ case TEEC_VALUE_OUTPUT:
+ case TEEC_VALUE_INOUT:
+ break;
+ case TEEC_MEMREF_TEMP_INPUT:
+ case TEEC_MEMREF_TEMP_OUTPUT:
+ case TEEC_MEMREF_TEMP_INOUT:
+ case TEEC_MEMREF_WHOLE:
+ case TEEC_MEMREF_PARTIAL_INPUT:
+ case TEEC_MEMREF_PARTIAL_OUTPUT:
+ case TEEC_MEMREF_PARTIAL_INOUT:
+ if (IS_ERR_OR_NULL(cmd->param.params[idx].shm))
+ break;
+
+ if ((cmd->param.params[idx].shm->flags &
+ (TEE_SHM_MAPPED | TEE_SHM_TEMP)) ==
+ (TEE_SHM_MAPPED | TEE_SHM_TEMP)) {
+ tee_shm_free(cmd->param.params[idx].shm);
+ } else {
+ BUG_ON(!cmd->param.params[idx].shm->parent);
+ tee_shm_put(cmd->param.params[idx].shm->parent);
+ BUG_ON(!(cmd->param.params[idx].shm->flags &
+ TEE_SHM_PARENT));
+ devm_kfree(ctx->tee->dev,
+ cmd->param.params[idx].shm);
+ }
+ break;
+ default:
+ BUG_ON(1);
+ }
+ }
+
+out:
+ memset(cmd, 0, sizeof(struct tee_cmd));
+ dev_dbg(_DEV_TEE, "%s: <\n", __func__);
+}
diff --git a/core/tee_shm.c b/core/tee_shm.c
new file mode 100644
index 0000000..b312b8e
--- /dev/null
+++ b/core/tee_shm.c
@@ -0,0 +1,455 @@
+
+#include <linux/types.h>
+#include <linux/dma-buf.h>
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include "tee_core_priv.h"
+#include "tee_shm.h"
+
+#define INMSG dev_dbg(_DEV(tee), "%s: >\n", __func__)
+#define OUTMSG(val) \
+ dev_dbg(_DEV(tee), "%s: < %lld\n", __func__, \
+ (long long int)(uintptr_t)val)
+
+/* TODO
+#if (sizeof(TEEC_SharedMemory) != sizeof(tee_shm))
+#error "sizeof(TEEC_SharedMemory) != sizeof(tee_shm))"
+#endif
+*/
+
+struct tee_shm *tee_shm_alloc_from_rpc(struct tee *tee, size_t size,
+ uint32_t flags)
+{
+ struct tee_shm *shm;
+
+ INMSG;
+
+ shm = tee->ops->alloc(tee, size, flags);
+ if (IS_ERR_OR_NULL(shm)) {
+ dev_err(_DEV(tee),
+ "%s: allocation failed (s=%d,flags=0x%08x) err=%ld\n",
+ __func__, (int)size, flags, PTR_ERR(shm));
+ shm = NULL;
+ } else {
+ mutex_lock(&tee->lock);
+ tee_inc_stats(&tee->stats[TEE_STATS_SHM_IDX]);
+ list_add_tail(&shm->entry, &tee->list_rpc_shm);
+ mutex_unlock(&tee->lock);
+ shm->ctx = NULL;
+ shm->tee = tee;
+ }
+
+ OUTMSG(shm);
+ return shm;
+}
+EXPORT_SYMBOL(tee_shm_alloc_from_rpc);
+
+void tee_shm_free_from_rpc(struct tee_shm *shm)
+{
+ if (shm == NULL)
+ return;
+ if (shm->ctx == NULL) {
+ mutex_lock(&shm->tee->lock);
+ tee_dec_stats(&shm->tee->stats[TEE_STATS_SHM_IDX]);
+ list_del(&shm->entry);
+ mutex_unlock(&shm->tee->lock);
+ shm->tee->ops->free(shm);
+ } else
+ tee_shm_free(shm);
+}
+EXPORT_SYMBOL(tee_shm_free_from_rpc);
+
+
+struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size,
+ uint32_t flags)
+{
+ struct tee_shm *shm;
+ struct tee *tee;
+
+ BUG_ON(!ctx);
+ BUG_ON(!ctx->tee);
+
+ tee = ctx->tee;
+
+ INMSG;
+
+ if (!ctx->usr_client)
+ flags |= TEE_SHM_FROM_KAPI;
+
+ shm = tee->ops->alloc(tee, size, flags);
+ if (IS_ERR_OR_NULL(shm)) {
+ dev_err(_DEV(tee),
+ "%s: allocation failed (s=%d,flags=0x%08x) err=%ld\n",
+ __func__, (int)size, flags, PTR_ERR(shm));
+ } else {
+ shm->ctx = ctx;
+ shm->tee = tee;
+
+ dev_dbg(_DEV(ctx->tee), "%s: shm=%p, paddr=%p,s=%d/%d app=\"%s\" pid=%d\n",
+ __func__, shm, (void *)shm->paddr, (int)shm->size_req,
+ (int)shm->size_alloc, current->comm, current->pid);
+ }
+
+
+
+ OUTMSG(shm);
+ return shm;
+}
+
+void tee_shm_free(struct tee_shm *shm)
+{
+ struct tee *tee;
+
+ if (IS_ERR_OR_NULL(shm))
+ return;
+ tee = shm->tee;
+ if (tee == NULL)
+ pr_warn("invalid call to tee_shm_free(%p): NULL tee\n", shm);
+ else if (shm->ctx == NULL)
+ dev_warn(_DEV(tee), "tee_shm_free(%p): NULL context\n", shm);
+ else if (shm->ctx->tee == NULL)
+ dev_warn(_DEV(tee), "tee_shm_free(%p): NULL tee\n", shm);
+ else
+ shm->ctx->tee->ops->free(shm);
+}
+
+/*
+ * tee_shm dma_buf operations
+ */
+static struct sg_table *_tee_shm_dmabuf_map_dma_buf(struct dma_buf_attachment
+ *attach,
+ enum dma_data_direction dir)
+{
+ return NULL;
+}
+
+static void _tee_shm_dmabuf_unmap_dma_buf(struct dma_buf_attachment *attach,
+ struct sg_table *table,
+ enum dma_data_direction dir)
+{
+ return;
+}
+
+static void _tee_shm_dmabuf_release(struct dma_buf *dmabuf)
+{
+ struct tee_shm *shm = dmabuf->priv;
+ struct device *dev;
+ struct tee_context *ctx;
+ struct tee *tee;
+ BUG_ON(!shm);
+ BUG_ON(!shm->ctx);
+ BUG_ON(!shm->ctx->tee);
+ tee = shm->ctx->tee;
+
+ INMSG;
+
+ ctx = shm->ctx;
+ dev = shm->dev;
+ dev_dbg(_DEV(ctx->tee), "%s: shm=%p, paddr=%p,s=%d/%d app=\"%s\" pid=%d\n",
+ __func__, shm, (void *)shm->paddr, (int)shm->size_req,
+ (int)shm->size_alloc, current->comm, current->pid);
+
+ mutex_lock(&ctx->tee->lock);
+ tee_dec_stats(&tee->stats[TEE_STATS_SHM_IDX]);
+ list_del(&shm->entry);
+ mutex_unlock(&ctx->tee->lock);
+
+ tee_shm_free(shm);
+ tee_put(ctx->tee);
+ tee_context_put(ctx);
+ if (dev)
+ put_device(dev);
+
+ OUTMSG(0);
+}
+
+static int _tee_shm_dmabuf_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;
+ struct tee *tee;
+ int ret;
+ pgprot_t prot;
+ BUG_ON(!shm);
+ BUG_ON(!shm->ctx);
+ BUG_ON(!shm->ctx->tee);
+ tee = shm->ctx->tee;
+
+ INMSG;
+
+ if (shm->flags & TEE_SHM_CACHED)
+ prot = vma->vm_page_prot;
+ else
+ prot = pgprot_noncached(vma->vm_page_prot);
+
+ ret =
+ remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, size,
+ prot);
+ if (!ret)
+ vma->vm_private_data = (void *)shm;
+
+ dev_dbg(_DEV(shm->ctx->tee), "%s: map the shm (p@=%p,s=%dKiB) => %x\n",
+ __func__, (void *)shm->paddr, (int)size / 1024,
+ (unsigned int)vma->vm_start);
+
+ OUTMSG(ret);
+ return ret;
+}
+
+static void *_tee_shm_dmabuf_kmap_atomic(struct dma_buf *dmabuf,
+ unsigned long pgnum)
+{
+ return NULL;
+}
+
+static void *_tee_shm_dmabuf_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
+{
+ return NULL;
+}
+
+struct dma_buf_ops _tee_shm_dma_buf_ops = {
+ .map_dma_buf = _tee_shm_dmabuf_map_dma_buf,
+ .unmap_dma_buf = _tee_shm_dmabuf_unmap_dma_buf,
+ .release = _tee_shm_dmabuf_release,
+ .kmap_atomic = _tee_shm_dmabuf_kmap_atomic,
+ .kmap = _tee_shm_dmabuf_kmap,
+ .mmap = _tee_shm_dmabuf_mmap,
+};
+
+static int get_fd(struct tee *tee, struct tee_shm *shm)
+{
+ struct dma_buf *dmabuf;
+ int fd = -1;
+
+ dmabuf = dma_buf_export(shm, &_tee_shm_dma_buf_ops, shm->size_alloc,
+ O_RDWR, NULL);
+ if (IS_ERR_OR_NULL(dmabuf)) {
+ dev_err(_DEV(tee), "%s: dmabuf: couldn't export buffer (%ld)\n",
+ __func__, PTR_ERR(dmabuf));
+ goto out;
+ }
+
+ fd = dma_buf_fd(dmabuf, O_CLOEXEC);
+
+out:
+ OUTMSG(fd);
+ return fd;
+}
+
+int tee_shm_alloc_fd(struct tee_context *ctx, struct tee_shm_io *shm_io)
+{
+ struct tee_shm *shm;
+ struct tee *tee = ctx->tee;
+ int ret;
+
+ INMSG;
+
+ shm_io->fd_shm = 0;
+
+ shm = tee_shm_alloc(ctx, shm_io->size, shm_io->flags);
+ if (IS_ERR_OR_NULL(shm)) {
+ dev_err(_DEV(tee), "%s: buffer allocation failed (%ld)\n",
+ __func__, PTR_ERR(shm));
+ return PTR_ERR(shm);
+ }
+
+ shm_io->fd_shm = get_fd(tee, shm);
+ if (shm_io->fd_shm <= 0) {
+ tee_shm_free(shm);
+ ret = -ENOMEM;
+ goto out;
+ }
+ shm->dev = get_device(tee->dev);
+ ret = tee_get(tee);
+ BUG_ON(ret); /* tee_core_get must not issue */
+ tee_context_get(ctx);
+
+ mutex_lock(&tee->lock);
+ tee_inc_stats(&tee->stats[TEE_STATS_SHM_IDX]);
+ list_add_tail(&shm->entry, &ctx->list_shm);
+ mutex_unlock(&tee->lock);
+out:
+ OUTMSG(ret);
+ return ret;
+}
+
+/* Buffer allocated by rpc from fw and to be accessed by the user
+ * Not need to be registered as it is not allocated by the user */
+int tee_shm_get_fd(struct tee_context *ctx, struct tee_shm_io *shm_io)
+{
+ struct tee_shm *shm = NULL;
+ struct tee *tee = ctx->tee;
+ int ret;
+ struct list_head *pshm;
+
+ INMSG;
+
+ shm_io->fd_shm = 0;
+
+ if (!list_empty(&tee->list_rpc_shm)) {
+ list_for_each(pshm, &tee->list_rpc_shm) {
+ shm = list_entry(pshm, struct tee_shm, entry);
+ if ((void *)shm->paddr == shm_io->buffer)
+ goto found;
+ }
+ }
+
+ dev_err(tee->dev, "Can't find shm for %p\n", (void *)shm_io->buffer);
+ ret = -ENOMEM;
+ goto out;
+
+found:
+ shm_io->fd_shm = get_fd(tee, shm);
+ if (shm_io->fd_shm <= 0) {
+ tee_shm_free(shm);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ shm->ctx = ctx;
+ ret = tee->ops->shm_inc_ref(shm);
+ BUG_ON(!ret); /* to do: path error */
+ mutex_lock(&tee->lock);
+ list_move(&shm->entry, &ctx->list_shm);
+ mutex_unlock(&tee->lock);
+
+ shm->dev = get_device(tee->dev);
+ ret = tee_get(tee);
+ BUG_ON(ret);
+ tee_context_get(ctx);
+
+out:
+ OUTMSG(ret);
+ return ret;
+}
+
+int check_shm(struct tee *tee, struct tee_shm_io *shm_io)
+{
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = current->mm;
+ struct tee_shm *shm;
+ int ret = 0;
+
+ INMSG;
+
+ if (shm_io->flags & TEE_SHM_FROM_KAPI) {
+ /* TODO fixme will not work on 64-bit platform */
+ shm = (struct tee_shm *)(uintptr_t)shm_io->fd_shm;
+ BUG_ON(!shm);
+ /* must be size_req but not in line with above test */
+ if (shm->size_req < shm_io->size) {
+ dev_err(tee->dev, "[%s] %p not big enough %x %zu %zu\n",
+ __func__, shm_io->buffer,
+ (unsigned int)shm->paddr, shm->size_req,
+ shm_io->size);
+ ret = -EINVAL;
+ }
+ goto out;
+ }
+
+ /* if the caller is the kernel api, active_mm is mm */
+ if (!mm)
+ mm = current->active_mm;
+
+ vma = find_vma(mm, (unsigned long)shm_io->buffer);
+ if (!vma) {
+ dev_err(tee->dev, "[%s] %p can't find vma\n", __func__,
+ shm_io->buffer);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ shm = vma->vm_private_data;
+
+ /* It's a VMA => consider it a a user address */
+ if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) {
+ dev_err(tee->dev, "[%s] %p not Contiguous %x\n", __func__,
+ shm_io->buffer, shm ? (unsigned int)shm->paddr : 0);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Contiguous ? */
+ if (vma->vm_end - vma->vm_start < shm_io->size) {
+ dev_err(tee->dev, "[%s] %p not big enough %x %ld %zu\n",
+ __func__, shm_io->buffer,
+ shm ? (unsigned int)shm->paddr : 0,
+ vma->vm_end - vma->vm_start, shm_io->size);
+ ret = -EINVAL;
+ }
+
+out:
+ OUTMSG(ret);
+ return ret;
+}
+
+static dma_addr_t get_phy_addr(struct tee *tee, struct tee_shm_io *shm_io)
+{
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = current->mm;
+ struct tee_shm *shm;
+
+ INMSG;
+
+ /* if the caller is the kernel api, active_mm is mm */
+ if (!mm)
+ mm = current->active_mm;
+
+ vma = find_vma(mm, (unsigned long)shm_io->buffer);
+ BUG_ON(!vma);
+ shm = vma->vm_private_data;
+
+ OUTMSG(shm->paddr);
+ /* Consider it has been allowd by the TEE */
+ return shm->paddr;
+}
+
+struct tee_shm *tee_shm_get(struct tee_context *ctx, struct tee_shm_io *shm_io)
+{
+ struct tee_shm *shm;
+ struct list_head *pshm;
+ int ret;
+ dma_addr_t buffer;
+ struct tee *tee = ctx->tee;
+
+ INMSG;
+
+ if (shm_io->flags & TEE_SHM_FROM_KAPI) {
+ /* TODO fixme will not work on 64-bit platform */
+ shm = (struct tee_shm *)(uintptr_t)shm_io->fd_shm;
+ BUG_ON(!shm);
+ ret = ctx->tee->ops->shm_inc_ref(shm);
+ BUG_ON(!ret); /* to do: path error */
+ OUTMSG(shm);
+ return shm;
+ }
+
+ buffer = get_phy_addr(ctx->tee, shm_io);
+ if (!buffer)
+ return NULL;
+
+ if (!list_empty(&ctx->list_shm)) {
+ list_for_each(pshm, &ctx->list_shm) {
+ shm = list_entry(pshm, struct tee_shm, entry);
+ BUG_ON(!shm);
+ /* if this ok, do not need to get_phys_addr
+ * if ((void *)shm->kaddr == shm_io->buffer) { */
+ if (shm->paddr == buffer) {
+ ret = ctx->tee->ops->shm_inc_ref(shm);
+ BUG_ON(!ret);
+ OUTMSG(shm);
+ return shm;
+ }
+ }
+ }
+ BUG_ON(1);
+ return NULL;
+}
+
+void tee_shm_put(struct tee_shm *shm)
+{
+ tee_shm_free(shm);
+}
diff --git a/core/tee_shm.h b/core/tee_shm.h
new file mode 100644
index 0000000..08ee139
--- /dev/null
+++ b/core/tee_shm.h
@@ -0,0 +1,20 @@
+
+#ifndef __TEE_SHM_H__
+#define __TEE_SHM_H__
+
+struct tee_context;
+struct tee_shm_io;
+struct tee;
+
+int tee_shm_alloc_fd(struct tee_context *ctx, struct tee_shm_io *shm_io);
+int tee_shm_get_fd(struct tee_context *ctx, struct tee_shm_io *shm_io);
+
+struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size,
+ uint32_t flags);
+void tee_shm_free(struct tee_shm *shm);
+
+int check_shm(struct tee *tee, struct tee_shm_io *shm_io);
+struct tee_shm *tee_shm_get(struct tee_context *ctx, struct tee_shm_io *shm_io);
+void tee_shm_put(struct tee_shm *shm);
+
+#endif /* __TEE_SHM_H__ */
diff --git a/core/tee_supp_com.c b/core/tee_supp_com.c
new file mode 100644
index 0000000..2776dbc
--- /dev/null
+++ b/core/tee_supp_com.c
@@ -0,0 +1,271 @@
+/*
+* Copyright (C) STMicroelectronics 2014. All rights reserved.
+*
+* This code is STMicroelectronics proprietary and confidential.
+* Any use of the code for whatever purpose is subject to
+* specific written permission of STMicroelectronics SA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/anon_inodes.h>
+#include <linux/semaphore.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+
+#include "tee_shm.h"
+#include "tee_core.h"
+#include "tee_supp_com.h"
+
+#define TEE_RPC_BUFFER 0x00000001
+#define TEE_RPC_VALUE 0x00000002
+
+enum teec_rpc_result tee_supp_cmd(struct tee *tee,
+ uint32_t id, void *data, size_t datalen)
+{
+ struct tee_rpc *rpc = tee->rpc;
+ enum teec_rpc_result res = TEEC_RPC_FAIL;
+ size_t size;
+ struct task_struct *task = current;
+
+ dev_dbg(tee->dev, "> tgid:[%d] id:[0x%08x]\n", task->tgid, id);
+
+ if (atomic_read(&rpc->used) == 0) {
+ dev_err(tee->dev, "%s: ERROR Supplicant application NOT ready\n"
+ , __func__);
+ goto out;
+ }
+
+ switch (id) {
+ case TEE_RPC_ICMD_ALLOCATE:
+ {
+ struct tee_rpc_alloc *alloc;
+ struct tee_shm *shmint;
+
+ alloc = (struct tee_rpc_alloc *)data;
+ size = alloc->size;
+ memset(alloc, 0, sizeof(struct tee_rpc_alloc));
+ shmint =
+ tee_shm_alloc_from_rpc(tee, size,
+ TEE_SHM_TEMP |
+ TEE_SHM_FROM_RPC);
+ if (shmint == NULL)
+ break;
+
+ alloc->size = size;
+ alloc->data = (void *)shmint->paddr;
+ alloc->shm = shmint;
+ res = TEEC_RPC_OK;
+
+ break;
+ }
+ case TEE_RPC_ICMD_FREE:
+ {
+ struct tee_rpc_free *free;
+
+ free = (struct tee_rpc_free *)data;
+ tee_shm_free(free->shm);
+ res = TEEC_RPC_OK;
+ break;
+ }
+ case TEE_RPC_ICMD_INVOKE:
+ {
+ if (sizeof(rpc->commToUser) < datalen)
+ break;
+
+ mutex_lock(&rpc->outsync);
+
+ memcpy(&rpc->commToUser, data, datalen);
+
+ mutex_unlock(&rpc->outsync);
+
+ dev_dbg(tee->dev,
+ "Supplicant Cmd: %x. Give hand to supplicant\n",
+ rpc->commToUser.cmd);
+
+ up(&rpc->datatouser);
+
+ down(&rpc->datafromuser);
+
+ dev_dbg(tee->dev,
+ "Supplicant Cmd: %x. Give hand to fw\n",
+ rpc->commToUser.cmd);
+
+ mutex_lock(&rpc->insync);
+
+ memcpy(data, &rpc->commFromUser, datalen);
+
+ mutex_unlock(&rpc->insync);
+
+ res = TEEC_RPC_OK;
+
+ break;
+ }
+ default:
+ /* not supported */
+ break;
+ }
+
+out:
+ dev_dbg(tee->dev, "< res: [%d]\n", res);
+
+ return res;
+}
+EXPORT_SYMBOL(tee_supp_cmd);
+
+ssize_t tee_supp_read(struct file *filp, char __user *buffer,
+ size_t length, loff_t *offset)
+{
+ struct tee_context *ctx = (struct tee_context *)(filp->private_data);
+ struct tee *tee;
+ struct tee_rpc *rpc;
+ struct task_struct *task = current;
+ int ret;
+
+ BUG_ON(!ctx);
+ tee = ctx->tee;
+ BUG_ON(!tee);
+ BUG_ON(!tee->dev);
+ BUG_ON(!tee->rpc);
+
+ dev_dbg(tee->dev, "> ctx %p\n", ctx);
+
+ rpc = tee->rpc;
+
+ if (atomic_read(&rpc->used) == 0) {
+ dev_err(tee->dev, "%s: ERROR Supplicant application NOT ready\n"
+ , __func__);
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (down_interruptible(&rpc->datatouser))
+ return -ERESTARTSYS;
+
+ dev_dbg(tee->dev, "> tgid:[%d]\n", task->tgid);
+
+ mutex_lock(&rpc->outsync);
+
+ ret =
+ sizeof(rpc->commToUser) - sizeof(rpc->commToUser.cmds) +
+ sizeof(rpc->commToUser.cmds[0]) * rpc->commToUser.nbr_bf;
+ if (length < ret) {
+ ret = -EINVAL;
+ } else {
+ if (copy_to_user(buffer, &rpc->commToUser, ret)) {
+ dev_err(tee->dev,
+ "[%s] error, copy_to_user failed!\n", __func__);
+ ret = -EINVAL;
+ }
+ }
+
+ mutex_unlock(&rpc->outsync);
+
+out:
+ dev_dbg(tee->dev, "< [%d]\n", ret);
+ return ret;
+}
+
+ssize_t tee_supp_write(struct file *filp, const char __user *buffer,
+ size_t length, loff_t *offset)
+{
+ struct tee_context *ctx = (struct tee_context *)(filp->private_data);
+ struct tee *tee;
+ struct tee_rpc *rpc;
+ struct task_struct *task = current;
+ int ret = 0;
+
+ BUG_ON(!ctx);
+ BUG_ON(!ctx->tee);
+ BUG_ON(!ctx->tee->rpc);
+ tee = ctx->tee;
+ rpc = tee->rpc;
+ dev_dbg(tee->dev, "> tgid:[%d]\n", task->tgid);
+
+ if (atomic_read(&rpc->used) == 0) {
+ dev_err(tee->dev, "%s: ERROR Supplicant application NOT ready\n"
+ , __func__);
+ goto out;
+ }
+
+ if (length > 0 && length < sizeof(rpc->commFromUser)) {
+ uint32_t i;
+
+ mutex_lock(&rpc->insync);
+
+ if (copy_from_user(&rpc->commFromUser, buffer, length)) {
+ dev_err(tee->dev,
+ "%s: ERROR, tee_session copy_from_user failed\n",
+ __func__);
+ mutex_unlock(&rpc->insync);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Translate virtual address of caller into physical address */
+ for (i = 0; i < rpc->commFromUser.nbr_bf; i++) {
+ if (rpc->commFromUser.cmds[i].type == TEE_RPC_BUFFER
+ && rpc->commFromUser.cmds[i].buffer) {
+ struct vm_area_struct *vma =
+ find_vma(current->mm,
+ (unsigned long)rpc->
+ commFromUser.cmds[i].buffer);
+ if (vma != NULL) {
+ struct tee_shm *shm =
+ vma->vm_private_data;
+ BUG_ON(!shm);
+ dev_dbg(tee->dev,
+ "%d gid2pa(0x%p => %x)\n", i,
+ rpc->commFromUser.cmds[i].
+ buffer,
+ (unsigned int)shm->paddr);
+ rpc->commFromUser.cmds[i].buffer =
+ (void *)shm->paddr;
+ } else
+ dev_dbg(tee->dev,
+ " gid2pa(0x%p => NULL\n)",
+ rpc->commFromUser.cmds[i].
+ buffer);
+ }
+ }
+
+ mutex_unlock(&rpc->insync);
+ up(&rpc->datafromuser);
+ ret = length;
+ }
+
+out:
+ dev_dbg(tee->dev, "< [%d]\n", ret);
+ return ret;
+}
+
+int tee_supp_init(struct tee *tee)
+{
+ struct tee_rpc *rpc =
+ devm_kzalloc(tee->dev, sizeof(struct tee_rpc), GFP_KERNEL);
+ if (!rpc) {
+ dev_err(tee->dev, "%s: can't allocate tee_rpc structure\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ rpc->datafromuser = (struct semaphore)
+ __SEMAPHORE_INITIALIZER(rpc->datafromuser, 0);
+ rpc->datatouser = (struct semaphore)
+ __SEMAPHORE_INITIALIZER(rpc->datatouser, 0);
+ mutex_init(&rpc->outsync);
+ mutex_init(&rpc->insync);
+ atomic_set(&rpc->used, 0);
+ tee->rpc = rpc;
+ return 0;
+}
+
+void tee_supp_deinit(struct tee *tee)
+{
+ devm_kfree(tee->dev, tee->rpc);
+ tee->rpc = NULL;
+}
diff --git a/generic/tee_supp_com.h b/core/tee_supp_com.h
index a9a3655..8c81756 100644
--- a/generic/tee_supp_com.h
+++ b/core/tee_supp_com.h
@@ -1,25 +1,17 @@
/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
+* Copyright (C) STMicroelectronics 2014. All rights reserved.
+*
+* This code is STMicroelectronics proprietary and confidential.
+* Any use of the code for whatever purpose is subject to
+* specific written permission of STMicroelectronics SA.
+*/
+
#ifndef TEE_SUPP_COMM_H
#define TEE_SUPP_COMM_H
-#define TEE_RPC_ICMD_ALLOCATE 0x1001
-#define TEE_RPC_ICMD_FREE 0x1002
-#define TEE_RPC_ICMD_INVOKE 0x1003
+#define TEE_RPC_ICMD_ALLOCATE 0x1001
+#define TEE_RPC_ICMD_FREE 0x1002
+#define TEE_RPC_ICMD_INVOKE 0x1003
#define TEE_RPC_NBR_BUFF 1
#define TEE_RPC_DATA_SIZE 64
@@ -58,13 +50,13 @@ struct tee_rpc_bf {
};
struct tee_rpc_alloc {
- uint32_t size; /* size of block */
- void *data; /* pointer to data */
- void *shm; /* pointer to an opaque data, being shm structure */
+ uint32_t size; /* size of block */
+ void *data; /* pointer to data */
+ void *shm; /* pointer to an opaque data, being shm structure */
};
struct tee_rpc_free {
- void *shm; /* pointer to an opaque data, being shm structure */
+ void *shm; /* pointer to an opaque data, being shm structure */
};
struct tee_rpc_cmd {
@@ -81,7 +73,7 @@ struct tee_rpc_invoke {
struct tee_rpc_cmd cmds[TEE_RPC_BUFFER_NUMBER];
};
-struct tee_rpc_priv_data {
+struct tee_rpc {
struct tee_rpc_invoke commToUser;
struct tee_rpc_invoke commFromUser;
struct semaphore datatouser;
@@ -89,6 +81,7 @@ struct tee_rpc_priv_data {
struct mutex outsync; /* Out sync mutex */
struct mutex insync; /* In sync mutex */
struct mutex reqsync; /* Request sync mutex */
+ atomic_t used;
};
enum teec_rpc_result {
@@ -96,18 +89,18 @@ enum teec_rpc_result {
TEEC_RPC_FAIL
};
-int tee_supp_init(struct tee_rpc_priv_data *rpc);
-void tee_supp_exit(void);
+struct tee;
-enum teec_rpc_result tee_supp_cmd(struct tee_targetop *op,
- uint32_t id, void *data,
- unsigned int datalen);
+int tee_supp_init(struct tee *tee);
+void tee_supp_deinit(struct tee *tee);
+
+enum teec_rpc_result tee_supp_cmd(struct tee *tee,
+ uint32_t id, void *data, size_t datalen);
ssize_t tee_supp_read(struct file *filp, char __user *buffer,
- size_t length, loff_t *offset);
+ size_t length, loff_t *offset);
ssize_t tee_supp_write(struct file *filp, const char __user *buffer,
- size_t length, loff_t *offset);
-
+ size_t length, loff_t *offset);
#endif
diff --git a/core/tee_sysfs.c b/core/tee_sysfs.c
new file mode 100644
index 0000000..38fe28a
--- /dev/null
+++ b/core/tee_sysfs.c
@@ -0,0 +1,193 @@
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/atomic.h>
+#include <asm/page.h>
+
+#include "tee_core_priv.h"
+
+static ssize_t dump_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+ int len;
+ char *tmp_buf;
+
+ tmp_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tmp_buf) {
+ printk(KERN_ALERT "%s : Unable to get buf memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ len = tee_context_dump(tee, tmp_buf, PAGE_SIZE - 128);
+
+ if (len > 0)
+ len = snprintf(buf, PAGE_SIZE, "%s", tmp_buf);
+ kfree(tmp_buf);
+
+ return len;
+}
+
+static ssize_t stat_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+
+ return snprintf(buf, PAGE_SIZE, "%d/%d %d/%d %d/%d %d/%d\n",
+ atomic_read(&tee->refcount),
+ tee->max_refcount,
+ tee->stats[TEE_STATS_CONTEXT_IDX].count,
+ tee->stats[TEE_STATS_CONTEXT_IDX].max,
+ tee->stats[TEE_STATS_SESSION_IDX].count,
+ tee->stats[TEE_STATS_SESSION_IDX].max,
+ tee->stats[TEE_STATS_SHM_IDX].count,
+ tee->stats[TEE_STATS_SHM_IDX].max);
+}
+
+static ssize_t info_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+
+ return snprintf(buf, PAGE_SIZE, "%s iminor=%d dev=\"%s\" state=%d\n",
+ dev_name(tee->dev), tee->miscdev.minor,
+ dev_name(tee->miscdev.this_device), tee->state);
+}
+
+static ssize_t name_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", tee->name);
+}
+
+static ssize_t type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", tee->ops->type);
+}
+
+static ssize_t refcount_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&tee->refcount));
+}
+
+static ssize_t conf_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", tee->conf);
+}
+
+static ssize_t test_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+
+ return snprintf(buf, PAGE_SIZE, "%08X\n", tee->test);
+}
+
+static ssize_t test_store(struct device *device,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct tee *tee = dev_get_drvdata(device);
+ unsigned long val;
+ int status;
+
+ status = kstrtoul(buf, 0, &val);
+ if (status)
+ return status;
+
+ if ((tee->conf & TEE_CONF_TEST_MODE) == TEE_CONF_TEST_MODE)
+ tee->test = val;
+
+ return count;
+}
+
+/*
+ * A state-to-string lookup table, for exposing a human readable state
+ * via sysfs. Always keep in sync with enum tee_state
+ */
+static const char *const tee_state_string[] = {
+ "offline",
+ "online",
+ "suspended",
+ "running",
+ "crashed",
+ "invalid",
+};
+
+static ssize_t tee_show_state(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee *tee = dev_get_drvdata(device);
+
+ int state = tee->state > TEE_LAST ? TEE_LAST : tee->state;
+
+ return snprintf(buf, PAGE_SIZE, "%s (%d)\n", tee_state_string[state],
+ tee->state);
+}
+
+/*
+ * In the following, 0660 is (S_IWUGO | S_IRUGO)
+ */
+static struct device_attribute device_attrs[] = {
+ __ATTR_RO(dump),
+ __ATTR_RO(stat),
+ __ATTR_RO(info),
+ __ATTR(test, (0660), test_show, test_store),
+ __ATTR(state, S_IRUGO, tee_show_state, NULL),
+ __ATTR(name, S_IRUGO, name_show, NULL),
+ __ATTR(refcount, S_IRUGO, refcount_show, NULL),
+ __ATTR(type, S_IRUGO, type_show, NULL),
+ __ATTR(conf, S_IRUGO, conf_show, NULL),
+};
+
+void tee_init_sysfs(struct tee *tee)
+{
+ int i, error = 0;
+
+ if (!tee)
+ return;
+
+ if (dev_get_drvdata(tee->miscdev.this_device) != tee) {
+ dev_err(_DEV(tee), "drvdata is not valid\n");
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+ error =
+ device_create_file(tee->miscdev.this_device,
+ &device_attrs[i]);
+ if (error)
+ break;
+ }
+
+ if (error) {
+ while (--i >= 0)
+ device_remove_file(tee->miscdev.this_device,
+ &device_attrs[i]);
+ }
+ /* location /sys/class/<class name>/<dev_name()>/<name> ->
+ * /sys/class/misc/teelx00/info */
+}
+
+void tee_cleanup_sysfs(struct tee *tee)
+{
+ int i;
+
+ if (!tee)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+ device_remove_file(tee->miscdev.this_device, &device_attrs[i]);
+}
diff --git a/core/tee_sysfs.h b/core/tee_sysfs.h
new file mode 100644
index 0000000..24c3b3d
--- /dev/null
+++ b/core/tee_sysfs.h
@@ -0,0 +1,10 @@
+
+#ifndef __TEE_SYSFS_H__
+#define __TEE_SYSFS_H__
+
+struct tee;
+
+void tee_init_sysfs(struct tee *tee);
+void tee_cleanup_sysfs(struct tee *tee);
+
+#endif
diff --git a/generic/tee-op.h b/generic/tee-op.h
deleted file mode 100644
index 65aca23..0000000
--- a/generic/tee-op.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#ifndef TEE_OP_H
-#define TEE_OP_H
-
-#include <linux/mutex.h>
-
-#include "tee_client_api.h"
-#include "tee_ioctl.h"
-#include "tee_mem.h"
-
-#define TEE_TZ_NAME "teetz"
-
-/*
- * Target virtualization
- */
-struct tee_session;
-
-enum t_cmd_service_id {
- /* For TEE Client API 1.0 */
- CMD_TEEC_OPEN_SESSION = 0x11000008,
- CMD_TEEC_CLOSE_SESSION = 0x11000009,
- CMD_TEEC_INVOKE_COMMAND = 0x1100000a,
- CMD_REGISTER_RPC = 0x1100000b, /* this is NOT a GP TEE API ! */
- CMD_SET_SEC_DDR = 0x1100000c, /* this is NOT a GP TEE API ! */
- CMD_TEEC_CANCEL_COMMAND = 0x1100000d,
- CMD_TEEC_REGISTER_MEMORY = 0x1100000e,
- CMD_TEEC_UNREGISTER_MEMORY = 0x1100000f,
-
- /* Internal command */
- CMD_TEE_DEINIT_CPU = 0x11000010,
- CMD_TEE_SET_CORE_TRACE_LEVEL = 0x11000012,
- CMD_TEE_GET_CORE_TRACE_LEVEL = 0x11000013,
- CMD_TEE_SET_TA_TRACE_LEVEL = 0x11000014,
- CMD_TEE_GET_TA_TRACE_LEVEL = 0x11000015,
-
- CMD_REGISTER_DEF_SHM = 0x11000020,
- CMD_UNREGISTER_DEF_SHM = 0x11000021
-};
-
-struct tee_targetop {
- struct miscdevice *miscdev;
- TEEC_Result(*call_sec_world) (struct tee_session *ts,
- enum t_cmd_service_id sec_cmd,
- uint32_t ta_cmd,
- uint32_t param_type,
- TEEC_Value
- params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *origin);
- TEEC_Result(*register_shm) (unsigned long paddr, unsigned long size,
- void **handle);
- TEEC_Result(*unregister_shm) (void *handle);
- uint32_t page_size;
-
- struct shm_pool *Allocator;
-};
-
-enum TEED_State {
- TEED_STATE_OPEN_DEV = 0,
- TEED_STATE_OPEN_SESSION = 1
-};
-
-/**
- * struct tee_session - The session data of an open tee device.
- * @uc: The command struct
- * @id: The session ID returned and managed by the secure world
- * @state: The current state of the session in the linux kernel.
- * @vaddr: Virtual address for the operation memrefs currently in use.
- */
-struct tee_session {
- __u32 id;
- enum TEED_State state;
- struct mutex syncstate; /* Sync state mutex */
-
- TEEC_UUID *uuid; /* !< The uuid for the trusted application */
- int tafd; /* !< Trusted App SHM file */
- void *ta; /* !< Trusted App allocated memory (in SHM) */
- __u32 tasize; /* !< Trusted App allocated memory size */
-
- __u32 login;
- bool userApi;
-
- struct tee_targetop *op;
-};
-
-/**
- * struct tee_identity - Represents the identity of the client
- * @login: Login id
- * @uuid: UUID as defined above
- */
-struct tee_identity {
- uint32_t login;
- TEEC_UUID uuid;
-};
-
-/*
- * tee_cmd_str() - return the string corresponding to this command
- * @cmd: id of the command
- * @return null if error
- */
-const char *tee_cmd_str(enum t_cmd_service_id cmd);
-
-/*
- * Definitions of messages to communicate with TEE
- * TODO: clean
- * 1st attribute of send msg must be the service
- * 1st attribute of rcv msg must be the duration
- */
-
-/*
- * tee_msg_recv - default strcutre of TEE service output message
- */
-struct tee_msg_recv {
- int duration;
- uint32_t res;
- uint32_t origin;
-};
-
-/*
- * tee_msg_send - generic part of the msg sent to the TEE
- */
-struct tee_msg_send {
- unsigned int service;
-};
-
-/*
- * tee_open_session_data - input arg structure for TEE open session service
- */
-struct tee_open_session_data {
- struct ta_signed_header_t *ta;
- TEEC_UUID *uuid;
- uint32_t param_types;
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
- struct tee_identity client_id;
- uint32_t params_flags[TEEC_CONFIG_PAYLOAD_REF_COUNT];
-};
-
-/*
- * tee_open_session_send - input arg msg for TEE open session service
- */
-struct tee_open_session_send {
- struct tee_msg_send header;
- struct tee_open_session_data data;
-};
-
-/*
- * tee_open_session_recv - output arg structure for TEE open session service
- */
-struct tee_open_session_recv {
- struct tee_msg_recv header;
- uint32_t sess;
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
-};
-
-/*
- * tee_invoke_command_data - input arg structure for TEE invoke cmd service
- */
-struct tee_invoke_command_data {
- uint32_t sess;
- uint32_t cmd;
- uint32_t param_types;
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
- struct tee_identity client_id;
- uint32_t params_flags[TEEC_CONFIG_PAYLOAD_REF_COUNT];
-};
-
-struct tee_invoke_command_send {
- struct tee_msg_send header;
- struct tee_invoke_command_data data;
-};
-
-/*
- * tee_invoke_command_recv - output arg structure for TEE invoke cmd service
- */
-struct tee_invoke_command_recv {
- struct tee_msg_recv header;
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
-};
-
-/*
- * tee_close_session_data - input arg structure for TEE close session service
- */
-struct tee_close_session_data {
- uint32_t sess;
-};
-
-/*
- * tee_close_session_send - input arg msg for TEE close session service
- */
-struct tee_close_session_send {
- struct tee_msg_send header;
- struct tee_close_session_data data;
-};
-
-/*
- * tee_cancel_command_data - input arg structure for TEE cancel service
- */
-struct tee_cancel_command_data {
- uint32_t sess;
- struct tee_identity client_id;
-};
-
-/*
- * tee_cancel_command_send - input msg structure for TEE cancel service
- */
-struct tee_cancel_command_send {
- struct tee_msg_send header;
- struct tee_cancel_command_data data;
-};
-
-/*
- * tee_register_rpc_send_data - input arg structure for TEE register rpc service
- */
-struct tee_register_rpc_send_data {
- uint32_t fnk;
- uint32_t bf;
- uint32_t nbr_bf;
-};
-
-/*
- * tee_register_rpc_send - input msg structure for TEE register rpc service
- */
-struct tee_register_rpc_send {
- struct tee_msg_send header;
- struct tee_register_rpc_send_data data;
-};
-
-/*
- * tee_register_rpc_recv_data - ouput arg structure for TEE register rpc service
- */
-struct tee_register_rpc_recv_data {
- uint32_t fnk;
- uint32_t bf;
- uint32_t nbr_bf;
-};
-
-/*
- * tee_register_rpc_recv - ouput msg structure for TEE register rpc service
- */
-struct tee_register_rpc_recv {
- struct tee_msg_recv header;
- struct tee_register_rpc_recv_data data;
-};
-
-/*
- * tee_register_irqfwd_xxx - (un)register callback for interrupt forwarding
- */
-struct tee_register_irqfwd_send {
- struct tee_msg_send header;
- struct {
- unsigned long cb;
- } data;
-};
-struct tee_register_irqfwd_recv {
- struct tee_msg_recv header;
-};
-
-/*
- * tee_trace_level_data - input arg structure for TEE trace level service
- */
-struct tee_trace_level_data {
- int trace_level;
-};
-
-/*
- * tee_trace_level_send - input msg structure for TEE trace level service
- */
-struct tee_trace_level_send {
- struct tee_msg_send header;
- struct tee_trace_level_data data;
-};
-
-/*
- * tee_trace_level_recv - output arg structure for TEE trace level service
- */
-struct tee_trace_level_recv {
- struct tee_msg_recv header;
- int trace_level;
-};
-
-/*
- * tee_core_status_out - output arg structure for TEE status service
- */
-#define TEEC_STATUS_MSG_SIZE 80
-
-struct tee_core_status_out {
- struct tee_msg_recv header;
- char raw[TEEC_STATUS_MSG_SIZE];
-};
-
-/*
- * tee_get_l2cc_mutex - input/output argument structures
- */
-struct tee_get_l2cc_mutex_send {
- struct tee_msg_send header;
-};
-struct tee_get_l2cc_mutex_recv {
- struct tee_msg_recv header;
- struct {
- unsigned long paddr;
- } data;
-};
-
-#endif
diff --git a/generic/tee_debug.c b/generic/tee_debug.c
deleted file mode 100644
index 34d893b..0000000
--- a/generic/tee_debug.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/device.h>
-
-#include "tee-op.h"
-#include "tee_driver.h"
-#include "tee_debug.h"
-
-static struct dentry *tee_debug_root;
-
-#define CMD_HIST_DEPTH 20
-#define CMD_HIST_FIFO_SIZE roundup_pow_of_two( \
- CMD_HIST_DEPTH * sizeof(struct tee_debug_cmd))
-
-static ssize_t tee_read_file_hist(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- ssize_t ret = 0;
- struct device *dev = file->private_data;
- static const int MAX_SIZE = 2 * PAGE_SIZE;
- char *buf;
-
- buf = devm_kzalloc(dev, MAX_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ret = tee_debug_dump_cmd_hist(dev, buf, MAX_SIZE);
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
-
- devm_kfree(dev, buf);
-
- return ret;
-}
-
-static const struct file_operations tee_debug_fops_hist = {
- .open = simple_open,
- .read = tee_read_file_hist,
- .llseek = default_llseek,
-};
-
-int tee_debug_init(struct device *dev)
-{
- char buf[20];
- struct dentry *entry = 0;
- int ret = 0;
- struct tee_driver *tee = tee_get_drvdata(dev);
-
- dev_dbg(dev, ">\n");
-
- ret = kfifo_alloc(&tee->cmds, CMD_HIST_FIFO_SIZE, GFP_KERNEL);
- if (ret) {
- dev_err(dev, "Can't allocate [%lu] bytes the fifo for the history cmds\n",
- CMD_HIST_FIFO_SIZE);
- ret = -ENOMEM;
- goto exit;
- }
-
- if (!tee_debug_root) {
- tee_debug_root = debugfs_create_dir("tee", NULL);
- if (!tee_debug_root) {
- dev_err(dev, "Failed to create tee debugfs root\n");
- ret = -EIO;
- goto err_dealloc;
- }
- }
-
- if (strcmp(DEV_NAME(dev), TEE_TZ_NAME) == 0)
- entry = debugfs_create_file(TEE_TZ_NAME, 0644, tee_debug_root,
- dev, &tee_debug_fops_tee_tz);
- if (!entry) {
- dev_err(dev, "Failed to create tee debugfs file\n");
- ret = -EIO;
- goto err_remove;
- }
-
- snprintf(buf, sizeof(buf), "%s_hist", DEV_NAME(dev));
- entry = debugfs_create_file(buf, 0644, tee_debug_root,
- dev, &tee_debug_fops_hist);
- if (!entry) {
- dev_err(dev, "Failed to create tee debugfs hist file\n");
- ret = -EIO;
- goto err_remove;
- }
-
- goto exit;
-
-err_remove:
- debugfs_remove_recursive(tee_debug_root);
-err_dealloc:
- kfifo_free(&tee->cmds);
-exit:
- dev_dbg(dev, "< [%d]\n", ret);
- return ret;
-}
-
-void tee_debug_remove(struct device *dev)
-{
- struct tee_driver *tee = tee_get_drvdata(dev);
- dev_dbg(dev, ">\n");
-
- if (tee_debug_root)
- debugfs_remove_recursive(tee_debug_root);
- tee_debug_root = NULL;
-
- kfifo_free(&tee->cmds);
-
- dev_dbg(dev, "<\n");
-}
diff --git a/generic/tee_debug.h b/generic/tee_debug.h
deleted file mode 100644
index 0c79673..0000000
--- a/generic/tee_debug.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#ifndef TEE_DEBUG_H
-#define TEE_DEBUG_H
-
-int tee_debug_init(struct device *dev);
-void tee_debug_remove(struct device *dev);
-
-extern const struct file_operations tee_debug_fops_tee_tz;
-
-#endif /* TEE_DEBUG_H */
diff --git a/generic/tee_driver.c b/generic/tee_driver.c
deleted file mode 100644
index ae4a9c7..0000000
--- a/generic/tee_driver.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/mutex.h>
-#include <linux/miscdevice.h>
-#include <linux/uaccess.h>
-#include <linux/file.h>
-#include <linux/anon_inodes.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include "tee-op.h"
-#include "tee_supp_com.h"
-#include "tee_mem.h"
-#include "tee_service.h"
-#include "tee_debug.h"
-#include "tee_tz.h"
-#include "tee_mutex_wait.h"
-
-
-#include "tee_driver.h"
-
-/******************************************************************************/
-
-static TEEC_Result copy_ta(
- struct device *dev, struct tee_session *ts, struct tee_cmd *ku_buffer)
-{
- unsigned long paddr;
- dev_dbg(dev, "> session: [0x%p]\n", ts);
-
- paddr = tee_shm_pool_alloc(dev, ts->op->Allocator,
- ku_buffer->data_size, 0);
- if (paddr == 0x0) {
- dev_err(dev, "error, out of memory\n");
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- ts->ta = tee_shm_pool_p2v(dev, ts->op->Allocator, paddr);
- ts->tasize = ku_buffer->data_size;
- ts->tafd = 0;
-
- if (copy_from_user(ts->ta, ku_buffer->data, ku_buffer->data_size)) {
- tee_shm_pool_free(dev, ts->op->Allocator, paddr,
- NULL);
- return TEEC_ERROR_BAD_PARAMETERS;
- }
-
- dev_dbg(dev, "<\n");
-
- return TEEC_SUCCESS;
-}
-
-/*
- * Direct return => Linux Error
- */
-static int invoke_command(struct device *dev, struct tee_session *ts,
- int sec_cmd, struct tee_cmd __user *u_buffer)
-{
- struct tee_cmd ku_buffer;
- TEEC_Operation op;
- uint32_t param_type = 0x0;
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
- unsigned long tmp_allocated_memories[TEEC_CONFIG_PAYLOAD_REF_COUNT] = {
- 0, };
- TEEC_Result res;
- bool ta_allocated = false;
- bool uid_allocated = false;
- int ret = 0;
- unsigned long paddr;
-
- if (copy_from_user
- (&ku_buffer, (void *)u_buffer, sizeof(struct tee_cmd))) {
- dev_err(dev, "[%s] copy_from_user failed\n",
- __func__);
- ret = -EINVAL;
- goto exit;
- }
-
- if (ku_buffer.op == NULL)
- goto inval;
-
- if (ku_buffer.data && ts->ta == NULL) {
- res = copy_ta(dev, ts, &ku_buffer);
- if (res != TEEC_SUCCESS)
- goto error;
- ta_allocated = true;
- }
- if (ku_buffer.uuid && ts->uuid == NULL) {
- res = allocate_uuid(ts);
- if (res != TEEC_SUCCESS)
- goto error;
- uid_allocated = true;
-
- if (copy_from_user(
- ts->uuid, ku_buffer.uuid, sizeof(TEEC_UUID))) {
- ret = -EINVAL;
- goto exit;
- }
- }
-
- if (copy_from_user(&op, ku_buffer.op, sizeof(TEEC_Operation))) {
- ret = -EINVAL;
- goto exit;
- }
-
- res = copy_op(ts, &op, tmp_allocated_memories, &param_type, params);
- if (res != TEEC_SUCCESS)
- goto error;
-
- res = ts->op->call_sec_world(ts, sec_cmd, ku_buffer.cmd, param_type,
- params, &ku_buffer.origin);
-
- if (res != TEEC_SUCCESS) {
- dev_err(dev,
- "invoke_command: call_sec_world , err [%x], org [%x]\n",
- res, ku_buffer.origin);
-
- (void)uncopy_op(ts, &op, tmp_allocated_memories, params);
- } else {
- res = uncopy_op(ts, &op, tmp_allocated_memories, params);
- }
-
- if (copy_to_user(ku_buffer.op, &op, sizeof(TEEC_Operation))) {
- ret = -EINVAL;
- goto exit;
- }
-
- goto out;
-
-inval:
- res = TEEC_ERROR_BAD_PARAMETERS;
-error:
- ku_buffer.origin = TEEC_ORIGIN_API;
-out:
- /* Update error code */
- put_user(res, &u_buffer->err);
- put_user(ku_buffer.origin, &u_buffer->origin);
-
-exit:
- if (ret && ta_allocated) {
- paddr = tee_shm_pool_v2p(
- dev, ts->op->Allocator, ts->ta);
- tee_shm_pool_free(
- dev, ts->op->Allocator, paddr, NULL);
- }
-
- if (ret && uid_allocated) {
- paddr = tee_shm_pool_v2p(
- dev, ts->op->Allocator, ts->uuid);
- tee_shm_pool_free(
- dev, ts->op->Allocator, paddr, NULL);
- }
-
- return ret;
-}
-
-static int tee_share_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct tee_shm *shmint = (struct tee_shm *)(filp->private_data);
- struct device *dev = shmint->op->miscdev->this_device;
- size_t size = vma->vm_end - vma->vm_start;
- pgprot_t prot;
-
- if (shmint != NULL) {
- dev_dbg(dev, "[%s] %x => %x (+%zu)\n", __func__,
- (unsigned int)shmint->
- paddr, (unsigned int)vma->vm_start,
- size);
-
- if (tee_shm_pool_is_cached(shmint->op->Allocator))
- prot = vma->vm_page_prot;
- else
- prot = pgprot_noncached(vma->vm_page_prot);
-
- if (remap_pfn_range(vma, vma->vm_start,
- shmint->paddr >> PAGE_SHIFT, size, prot))
- return -EAGAIN;
- BUG_ON(vma->vm_private_data != NULL);
- vma->vm_private_data = (void *)shmint->paddr;
- }
-
- return 0;
-
-}
-
-static int tee_share_release(struct inode *inode, struct file *filp)
-{
- struct tee_shm *shmint = (struct tee_shm *)(filp->private_data);
- struct device *dev = shmint->op->miscdev->this_device;
-
- dev_dbg(dev, "> %p\n", (void *)shmint);
- if (shmint != NULL) {
- tee_shm_unallocate(shmint);
- filp->private_data = NULL;
- }
-
- dev_dbg(dev, "< [0]\n");
- return 0;
-}
-
-const struct file_operations tee_share_fops = {
- .owner = THIS_MODULE,
- .release = tee_share_release,
- .mmap = tee_share_mmap,
-};
-
-static int tee_open(struct inode *inode, struct file *filp)
-{
- filp->private_data =
- tee_create_session(filp->f_path.dentry->d_iname, true);
- if (filp->private_data == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-static int tee_release(struct inode *inode, struct file *filp)
-{
- struct tee_session *ts = filp->private_data;
-
- tee_delete_session(ts);
-
- return 0;
-}
-
-#if (CFG_TEE_DRV_DEBUGFS == 1)
-inline int tee_debug_do_dump_cmd_hist(struct device *dev,
- const char line[], int ret, char *output, int max_size)
-{
- if (max_size > 0 && output)
- ret += snprintf(output + ret, max_size - ret, line);
- else
- dev_info(dev, line);
-
- return ret;
-}
-
-int tee_debug_dump_cmd_hist(struct device *dev, char *output, int max_size)
-{
- struct tee_debug_cmd cmd;
- int age = 1;
- struct tee_driver *tee = tee_get_drvdata(dev);
- int ret = 0;
- char tmp[256];
-
- ret = tee_debug_do_dump_cmd_hist(dev,
- "History of the commands\n", ret, output, max_size);
-
- ret = tee_debug_do_dump_cmd_hist(dev,
- "\t\t\t\t\t\t\t\t\t\tduration (ms)\n", ret, output, max_size);
-
- ret = tee_debug_do_dump_cmd_hist(dev,
- "\tdate (ms)\tsession\t\ttee cmd\t\t\tta cmd\tres\tarm\n",
- ret, output, max_size);
-
- mutex_lock(&tee->mutex_tee);
-
- while (kfifo_out(&tee->cmds, &cmd, sizeof(cmd))) {
- snprintf(tmp, sizeof(tmp),
- "%04d\t[%lld]\t[0x%p]\t[%s]\t[%d]\t[%d]\t[%lld]\n",
- age++, cmd.begin, cmd.ts, tee_cmd_str(cmd.cmd),
- cmd.ta_cmd, cmd.ret, cmd.duration);
- ret = tee_debug_do_dump_cmd_hist(
- dev, tmp, ret, output, max_size);
- }
-
- mutex_unlock(&tee->mutex_tee);
- return ret;
-}
-#endif
-
-static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct tee_session *ts = (struct tee_session *)(filp->private_data);
- struct device *dev = ts->op->miscdev->this_device;
- __u32 state;
- int ret = 0;
-
- dev_dbg(dev, "> cmd:[0x%x]\n", cmd);
-
- mutex_lock(&ts->syncstate);
- state = ts->state;
- mutex_unlock(&ts->syncstate);
-
- switch (cmd) {
- case TEE_OPEN_SESSION_IOC:
- if (state != TEED_STATE_OPEN_DEV) {
- dev_err(dev, "[%s] invalid state\n",
- __func__);
- ret = -EINVAL;
- } else {
- ret = invoke_command(dev, ts, CMD_TEEC_OPEN_SESSION,
- (struct tee_cmd *)arg);
- if (ret == 0) {
- mutex_lock(&ts->syncstate);
- ts->state = TEED_STATE_OPEN_SESSION;
- mutex_unlock(&ts->syncstate);
- }
- }
- break;
-
- case TEE_CLOSE_SESSION_IOC:
- if (state != TEED_STATE_OPEN_SESSION) {
- dev_err(dev, "[%s] invalid state\n",
- __func__);
- ret = -EINVAL;
- } else {
- if (ts->
- op->call_sec_world(ts, CMD_TEEC_CLOSE_SESSION,
- 0, 0x0, NULL,
- NULL) != TEEC_SUCCESS)
- ret = -EINVAL;
-
- mutex_lock(&ts->syncstate);
- ts->state = TEED_STATE_OPEN_DEV;
- mutex_unlock(&ts->syncstate);
- }
-
- break;
-
- case TEE_INVOKE_COMMAND_IOC:
- if (state != TEED_STATE_OPEN_SESSION) {
- dev_err(dev, "[%s] invalid state\n",
- __func__);
- ret = -EINVAL;
- } else {
- ret =
- invoke_command(dev, ts, CMD_TEEC_INVOKE_COMMAND,
- (struct tee_cmd *)arg);
- }
- break;
- case TEE_REQUEST_CANCELLATION_IOC:
- if (state != TEED_STATE_OPEN_SESSION) {
- dev_err(dev, "[%s] invalid state\n",
- __func__);
- ret = -EINVAL;
- } else {
- if (ts->
- op->call_sec_world(ts, CMD_TEEC_CANCEL_COMMAND,
- 0, 0x0, NULL,
- NULL) != TEEC_SUCCESS)
- ret = -EINVAL;
- }
- break;
-
- case TEE_ALLOC_SHM_IOC:
- {
- TEEC_SharedMemory shm;
- struct file *file;
- struct tee_shm *shmint;
-
- if (copy_from_user(&shm, (void __user *)arg,
- sizeof(TEEC_SharedMemory)))
- return -EFAULT;
-
- shmint =
- tee_shm_allocate(ts->op, shm.buffer,
- shm.size, shm.flags);
- if (shmint == NULL)
- return -ENOMEM;
-
- shm.d.fd = get_unused_fd();
- if (shm.d.fd < 0) {
- tee_shm_unallocate(shmint);
- return -ENFILE;
- }
-
- file =
- anon_inode_getfile("tee_share_fd", &tee_share_fops,
- shmint, O_RDWR);
- if (IS_ERR_OR_NULL(file)) {
- put_unused_fd(shm.d.fd);
- tee_shm_unallocate(shmint);
- return -ENFILE;
- }
- fd_install(shm.d.fd, file);
-
- if (copy_to_user((void __user *)arg,
- &shm, sizeof(TEEC_SharedMemory)))
- return -EFAULT;
- };
- break;
-
- default:
- ret = -ENOSYS;
- break;
- }
-
- dev_dbg(dev, "< [%d]\n", ret);
-
- return ret;
-}
-
-
-struct tee_driver *tee_get_drvdata(struct device *dev)
-{
- if (strcmp(DEV_NAME(dev), TEE_TZ_NAME) == 0)
- return &tee_tz_data;
- BUG_ON(1);
- return NULL;
-}
-
-const struct file_operations tee_fops = {
- .owner = THIS_MODULE,
- .open = tee_open,
- .release = tee_release,
- .unlocked_ioctl = tee_ioctl,
- .read = tee_supp_read,
- .write = tee_supp_write,
-};
-
-
-static int __init tee_init(void)
-{
- int ret = 0;
- bool tz_init = false;
- bool supp_init = false;
- bool wait_init = false;
-
- ret = tee_tz_init();
- if (ret)
- goto err;
- tz_init = true;
-
- ret = tee_supp_init(&tee_tz_data.rpc);
- if (ret)
- goto err;
- supp_init = true;
-
- ret = tee_mutex_wait_init(&tee_tz_data.mutex_wait);
- if (ret)
- goto err;
-
- goto exit;
-err:
- if (wait_init)
- tee_mutex_wait_exit(&tee_tz_data.mutex_wait);
- if (supp_init)
- tee_supp_exit();
- if (tz_init)
- tee_tz_exit();
-exit:
- return ret;
-}
-
-static void __exit tee_exit(void)
-{
- pr_info("in tee_exit\n");
-
- tee_mutex_wait_exit(&tee_tz_data.mutex_wait);
-
- tee_supp_exit();
-
- tee_tz_exit();
-}
-
-module_init(tee_init);
-module_exit(tee_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("Trusted Execution Enviroment driver");
-
diff --git a/generic/tee_driver.h b/generic/tee_driver.h
deleted file mode 100644
index fc05e90..0000000
--- a/generic/tee_driver.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#ifndef TEE_DRIVER_H
-#define TEE_DRIVER_H
-
-#include <linux/mutex.h>
-
-#include "tee_supp_com.h"
-#include "tee_mutex_wait.h"
-
-/******************************************************************************/
-
-/* Helpers */
-#define DEV_NAME(dev) (dev->kobj.name)
-
-/******************************************************************************/
-
-#if (CFG_TEE_DRV_DEBUGFS == 1)
-
-#include <linux/kfifo.h>
-
-struct tee_debug_cmd {
- enum t_cmd_service_id cmd;
- struct tee_session *ts;
- uint32_t ta_cmd;
- int ret;
- s64 begin;
- s64 duration;
-};
-
-#endif /* CFG_TEE_DRV_DEBUGFS */
-
-struct tee_driver {
- /* protect concurrent access to the tee_driver */
- struct mutex mutex_tee;
- int count_session;
- char *memory_pool;
- struct tee_rpc_priv_data rpc;
- struct tee_mutex_wait_private mutex_wait;
-#if (CFG_TEE_DRV_DEBUGFS == 1)
- struct kfifo cmds;
-#endif
-};
-
-
-struct device;
-extern const struct file_operations tee_fops;
-
-/******************************************************************************/
-
-struct tee_driver *tee_get_drvdata(struct device *dev);
-
-#if (CFG_TEE_DRV_DEBUGFS == 1)
-int tee_debug_dump_cmd_hist(struct device *dev, char *output, int max_size);
-#endif
-
-/******************************************************************************/
-
-#endif /* TEE_DRIVER_H */
diff --git a/generic/tee_kernel_api.c b/generic/tee_kernel_api.c
deleted file mode 100644
index ff49af6..0000000
--- a/generic/tee_kernel_api.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/io.h>
-#include <linux/vmalloc.h>
-
-#include "linux/tee_kernel_api.h"
-
-#include "tee-op.h"
-#include "tee_supp_com.h"
-#include "tee_service.h"
-
-struct tee_supp_arg {
- uint32_t res;
- uint32_t id;
- uint32_t datasize;
- uint32_t reserved;
- /* uint32_t instead of uint8_t in order to ensure it is 4 aligned */
- uint32_t data[TEE_RPC_DATA_SIZE / sizeof(uint32_t)];
-};
-
-
-struct tee_uuid {
- uint32_t timeLow;
- uint16_t timeMid;
- uint16_t timeHiAndVersion;
- uint8_t clockSeqAndNode[8];
-};
-
-
-struct tee_rpc_load_ta_cmd {
- struct tee_uuid uuid;
- void *va;
-};
-
-static int alloc_ta_bin(struct tee_session *ts)
-{
- struct tee_supp_arg supp_arg;
- struct tee_rpc_invoke *head;
- struct tee_rpc_load_ta_cmd *supp_cmd;
- struct tee_shm *tee_shm;
- struct device *dev = ts->op->miscdev->this_device;
-
- dev_dbg(dev, ">\n");
- head = (struct tee_rpc_invoke *)&supp_arg.data;
- head->cmd = TEE_RPC_LOAD_TA;
- head->res = 0;
- head->nbr_bf = 2;
-
- tee_shm = tee_shm_allocate(
- ts->op, NULL, sizeof(struct tee_rpc_load_ta_cmd), 0);
- if (!tee_shm)
- return -ENOMEM;
-
- head->cmds[0].buffer = (void *)tee_shm->paddr;
-
- supp_cmd = (struct tee_rpc_load_ta_cmd *)tee_shm_pool_p2v(
- dev, ts->op->Allocator, (unsigned long)head->cmds[0].buffer);
- memcpy(&supp_cmd->uuid, ts->uuid, sizeof(struct tee_uuid));
- head->cmds[0].size = sizeof(struct tee_rpc_load_ta_cmd);
- head->cmds[0].type = TEE_RPC_BUFFER;
-
- head->cmds[1].buffer = NULL;
- head->cmds[1].size = 0;
- head->cmds[1].type = TEE_RPC_BUFFER;
-
- supp_arg.datasize = sizeof(*head) - sizeof(head->cmds) +
- sizeof(head->cmds[0]) * head->nbr_bf;
- supp_arg.id = TEE_RPC_ICMD_INVOKE;
- supp_arg.res = tee_supp_cmd(
- ts->op, supp_arg.id, supp_arg.data, supp_arg.datasize);
- ts->ta = (void *)tee_shm_pool_p2v(
- dev, ts->op->Allocator, (unsigned long)head->cmds[1].buffer);
- ts->tasize = head->cmds[1].size;
- ts->tafd = head->cmds[1].fd;
- dev_dbg(dev, "ta loaded pa %p va %p fd %d\n",
- head->cmds[1].buffer, ts->ta, ts->tafd);
- dev_dbg(dev, "Going to free %p\n", head->cmds[0].buffer);
- tee_shm_unallocate(tee_shm);
- if (supp_arg.res != TEEC_SUCCESS) {
- dev_err(dev, "can't load ta\n");
- return -ENOENT;
- }
-
- dev_dbg(dev, "<\n");
- return 0;
-}
-
-static int free_ta_bin(struct tee_session *ts)
-{
- struct tee_supp_arg supp_arg;
- struct tee_rpc_invoke *head;
- struct tee_shm *tee_shm;
- struct device *dev = ts->op->miscdev->this_device;
-
- dev_dbg(dev, ">\n");
- head = (struct tee_rpc_invoke *)&supp_arg.data;
- head->cmd = TEE_RPC_FREE_TA_WITH_FD;
- head->res = 0;
- head->nbr_bf = 1;
-
- tee_shm = tee_shm_allocate(
- ts->op, NULL, sizeof(struct tee_rpc_load_ta_cmd), 0);
- if (!tee_shm)
- return -ENOMEM;
-
- dev_dbg(dev, "free ta va %p fd %d\n", ts->ta, ts->tafd);
- head->cmds[0].size = ts->tasize;
- head->cmds[0].type = TEE_RPC_BUFFER;
- head->cmds[0].fd = ts->tafd;
-
- supp_arg.datasize = sizeof(*head) - sizeof(head->cmds) +
- sizeof(head->cmds[0]) * head->nbr_bf;
- supp_arg.id = TEE_RPC_ICMD_INVOKE;
- supp_arg.res = tee_supp_cmd(
- ts->op, supp_arg.id, supp_arg.data, supp_arg.datasize);
- tee_shm_unallocate(tee_shm);
- if (supp_arg.res != TEEC_SUCCESS) {
- dev_err(dev, "can't unload ta\n");
- return -ENOENT;
- }
- ts->ta = NULL;
- dev_dbg(dev, "<\n");
- return 0;
-}
-
-
-TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context)
-{
- if (name == NULL)
- strcpy(context->devname, TEE_TZ_NAME);
- else
- strcpy(context->devname, name);
-
- return TEEC_SUCCESS;
-}
-EXPORT_SYMBOL(TEEC_InitializeContext);
-
-TEEC_Result TEEC_FinalizeContext(TEEC_Context *context)
-{
- return TEEC_SUCCESS;
-}
-EXPORT_SYMBOL(TEEC_FinalizeContext);
-
-TEEC_Result TEEC_OpenSession(TEEC_Context *context,
- TEEC_Session *session,
- const TEEC_UUID *destination,
- uint32_t connectionMethod,
- const void *connectionData,
- TEEC_Operation *operation,
- uint32_t *returnOrigin)
-{
- struct tee_session *ts;
- uint32_t param_type = 0x0;
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
- unsigned long tmp_allocated_memories[TEEC_CONFIG_PAYLOAD_REF_COUNT] = {
- 0, };
- TEEC_Result ret;
- TEEC_Operation dummy_op;
- struct device *dev = NULL;
-
- if (operation == NULL) {
- /*
- * The code here exist because Global Platform API states that
- * it is allowed to give operation as a NULL pointer.
- * In kernel and secure world we in most cases don't want
- * this to be NULL, hence we use this dummy operation when
- * a client doesn't provide any operation.
- */
- memset(&dummy_op, 0, sizeof(TEEC_Operation));
- operation = &dummy_op;
- }
-
-
- if (context == NULL || session == NULL || destination == NULL ||
- operation == NULL || returnOrigin == NULL ||
- connectionData != NULL)
- return TEEC_ERROR_BAD_PARAMETERS;
-
- *returnOrigin = TEEC_ORIGIN_API;
-
- ts = tee_create_session(context->devname, false);
- if (ts == NULL)
- return TEEC_ERROR_OUT_OF_MEMORY;
-
- dev = ts->op->miscdev->this_device;
-
- ret = allocate_uuid(ts);
- if (ret != TEEC_SUCCESS)
- goto error;
-
- *ts->uuid = *destination;
-
- ret = copy_op(ts, operation, tmp_allocated_memories,
- &param_type, params);
- if (ret != TEEC_SUCCESS)
- goto error;
-
- dev_dbg(dev, "uuid=%08x-%04x-%04x\n",
- ((ts->uuid) ? ts->uuid->timeLow : 0xDEAD),
- ((ts->uuid) ? ts->uuid->timeMid : 0xDEAD),
- ((ts->uuid) ? ts->uuid->
- timeHiAndVersion : 0xDEAD));
-
- alloc_ta_bin(ts);
-
- ret = ts->op->call_sec_world(ts, CMD_TEEC_OPEN_SESSION, 0,
- param_type, params, returnOrigin);
-
- (void)uncopy_op(ts, operation, tmp_allocated_memories, params);
-
- if (ret != TEEC_SUCCESS) {
- dev_err(dev,
- "TEEC_OpenSession: call_sec_world , err [%x], org [%x]\n",
- ret, *returnOrigin);
- goto error;
- }
-
- ts->state = TEED_STATE_OPEN_SESSION;
- session->session = ts;
-
- return TEEC_SUCCESS;
-error:
- tee_delete_session(ts);
- return ret;
-}
-EXPORT_SYMBOL(TEEC_OpenSession);
-
-void TEEC_CloseSession(TEEC_Session *session)
-{
- if (session != NULL && session->session != NULL) {
- struct tee_session *ts = (struct tee_session *)session->session;
-
- free_ta_bin(ts);
-
- tee_delete_session(ts);
- }
-}
-EXPORT_SYMBOL(TEEC_CloseSession);
-
-TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
- uint32_t commandID,
- TEEC_Operation *operation,
- uint32_t *returnOrigin)
-{
- struct tee_session *ts;
- uint32_t param_type = 0x0;
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
- unsigned long tmp_allocated_memories[TEEC_CONFIG_PAYLOAD_REF_COUNT] = {
- 0, };
- TEEC_Result ret;
- struct device *dev = NULL;
-
- if (session == NULL || operation == NULL || returnOrigin == NULL ||
- session->session == NULL)
- return TEEC_ERROR_BAD_PARAMETERS;
-
- *returnOrigin = TEEC_ORIGIN_API;
- ts = (struct tee_session *)session->session;
- dev = ts->op->miscdev->this_device;
-
- if (ts->state != TEED_STATE_OPEN_SESSION)
- return TEEC_ERROR_BAD_PARAMETERS;
-
- ret = copy_op(ts, operation, tmp_allocated_memories,
- &param_type, params);
- if (ret != TEEC_SUCCESS)
- return ret;
-
- ret = ts->op->call_sec_world(ts, CMD_TEEC_INVOKE_COMMAND, commandID,
- param_type, params, returnOrigin);
-
- (void)uncopy_op(ts, operation, tmp_allocated_memories, params);
-
- if (ret != TEEC_SUCCESS)
- dev_err(dev,
- "TEEC_InvokeCommand: call_sec_world , err [%x], org [%x]\n",
- ret, *returnOrigin);
-
- return ret;
-}
-EXPORT_SYMBOL(TEEC_InvokeCommand);
-
-TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
- TEEC_SharedMemory *sharedMem)
-{
- pr_info("TEEC_RegisterSharedMemory (vaddr=%p, size=%d)\n",
- sharedMem->buffer, (int)sharedMem->size);
-
- if (sharedMem == NULL || sharedMem->buffer == NULL ||
- sharedMem->size == 0)
- return TEEC_ERROR_BAD_PARAMETERS;
-
- sharedMem->d.shm = NULL;
- sharedMem->registered = 1;
-
- /*
- * Note: memory register in this context and allocate by previous
- * TEEC_AllocateSharedMemory
- * in another context will be consider as continuous by infrastructure.
- * Elsewhere, it will be always uncontinuous.
- *
- * A potential optimization could be to pass flags to indicate
- * continuity !!!!
- */
- return 0;
-}
-EXPORT_SYMBOL(TEEC_RegisterSharedMemory);
-
-TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
- TEEC_SharedMemory *sharedMem)
-{
- struct tee_targetop *op;
-
- if (context == NULL)
- return TEEC_ERROR_BAD_PARAMETERS;
-
- op = tee_get_target(context->devname);
- if (op == NULL)
- return TEEC_ERROR_BAD_PARAMETERS;
-
- sharedMem->d.shm =
- tee_shm_allocate(op, NULL, sharedMem->size, sharedMem->flags);
- if (sharedMem->d.shm == NULL) {
- pr_err("TEEC_AllocateSharedMemory: tee_shm_allocate(%zu) failed\n",
- sharedMem->size);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- pr_info("TEEC_AllocateSharedMemory (%zu) => paddr = %lx\n",
- sharedMem->size, sharedMem->d.shm->paddr);
-
- sharedMem->buffer =
- ioremap_nocache(sharedMem->d.shm->paddr, sharedMem->size);
- if (sharedMem->buffer == NULL) {
- pr_err("TEEC_AllocateSharedMemory: ioremap_nocache(%lx, %zu) failed\n",
- sharedMem->d.shm->paddr, sharedMem->size);
- tee_shm_unallocate(sharedMem->d.shm);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- sharedMem->registered = 0;
-
- return TEEC_SUCCESS;
-}
-EXPORT_SYMBOL(TEEC_AllocateSharedMemory);
-
-void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory)
-{
- pr_info("TEEC_ReleaseSharedMemory (vaddr = %p)\n",
- sharedMemory->buffer);
-
- if (sharedMemory->registered == 0) {
- iounmap(sharedMemory->buffer);
- sharedMemory->buffer = NULL;
- tee_shm_unallocate(sharedMemory->d.shm);
- }
-}
-EXPORT_SYMBOL(TEEC_ReleaseSharedMemory);
diff --git a/generic/tee_mem.h b/generic/tee_mem.h
deleted file mode 100644
index ed91eb3..0000000
--- a/generic/tee_mem.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#ifndef TEE_MEM_H
-#define TEE_MEM_H
-
-#include <linux/types.h>
-#include <linux/device.h>
-
-struct shm_pool;
-
-
-struct shm_pool *tee_shm_pool_create(struct device *dev, size_t shm_size,
- void *shm_vaddr, unsigned long shm_paddr);
-
-void tee_shm_pool_destroy(struct device *dev, struct shm_pool *pool);
-
-
-void *tee_shm_pool_p2v(struct device *dev, struct shm_pool *pool,
- unsigned long paddr);
-
-unsigned long tee_shm_pool_v2p(struct device *dev, struct shm_pool *pool,
- void *vaddr);
-
-
-unsigned long tee_shm_pool_alloc(struct device *dev,
- struct shm_pool *pool,
- size_t size, size_t alignment);
-
-
-void tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
- unsigned long paddr, size_t *size);
-
-
-bool tee_shm_pool_incref(struct device *dev, struct shm_pool *pool,
- unsigned long paddr);
-
-
-void tee_shm_pool_dump(struct device *dev, struct shm_pool *pool,
- bool forced);
-
-void tee_shm_pool_reset(struct device *dev, struct shm_pool *pool);
-
-bool tee_shm_pool_is_cached(struct shm_pool *pool);
-
-void tee_shm_pool_set_cached(struct shm_pool *pool);
-
-
-#endif
diff --git a/generic/tee_op.c b/generic/tee_op.c
deleted file mode 100644
index d8947da..0000000
--- a/generic/tee_op.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include "tee-op.h"
-
-static const char CMD_TEEC_OPEN_SESSION_STR[] = "OPEN_SESSION ";
-
-static const char CMD_TEEC_CLOSE_SESSION_STR[] = "CLOSE_SESSION ";
-static const char CMD_TEEC_INVOKE_COMMAND_STR[] = "INVOKE_COMMAND ";
-static const char CMD_REGISTER_RPC_STR[] = "REGISTER_RPC ";
-static const char CMD_SET_SEC_DDR_STR[] = "SET_SEC_DDR ";
-static const char CMD_TEEC_CANCEL_COMMAND_STR[] = "CANCEL_COMMAND ";
-
-static const char CMD_TEE_DEINIT_CPU_STR[] = "DEINIT_CPU ";
-static const char CMD_TEE_SET_CORE_TRACE_LEVEL_STR[] =
- "SET_CORE_TRACE_LEVEL";
-static const char CMD_TEE_GET_CORE_TRACE_LEVEL_STR[] =
- "GET_CORE_TRACE_LEVEL";
-static const char CMD_TEE_SET_TA_TRACE_LEVEL_STR[] = "SET_TA_TRACE_LEVEL";
-static const char CMD_TEE_GET_TA_TRACE_LEVEL_STR[] = "GET_TA_TRACE_LEVEL";
-
-static const char CMD_REGISTER_DEF_SHM_STR[] = "REGISTER_DEF_SHM";
-static const char CMD_UNREGISTER_DEF_SHM_STR[] = "UNREGISTER_DEF_SHM";
-
-const char *tee_cmd_str(enum t_cmd_service_id cmd)
-{
- switch (cmd) {
- case CMD_TEEC_OPEN_SESSION:
- return CMD_TEEC_OPEN_SESSION_STR;
-
- case CMD_TEEC_CLOSE_SESSION:
- return CMD_TEEC_CLOSE_SESSION_STR;
-
- case CMD_TEEC_INVOKE_COMMAND:
- return CMD_TEEC_INVOKE_COMMAND_STR;
-
- case CMD_REGISTER_RPC:
- return CMD_REGISTER_RPC_STR;
-
- case CMD_SET_SEC_DDR:
- return CMD_SET_SEC_DDR_STR;
-
- case CMD_TEEC_CANCEL_COMMAND:
- return CMD_TEEC_CANCEL_COMMAND_STR;
-
- case CMD_TEE_DEINIT_CPU:
- return CMD_TEE_DEINIT_CPU_STR;
-
- case CMD_TEE_SET_CORE_TRACE_LEVEL:
- return CMD_TEE_SET_CORE_TRACE_LEVEL_STR;
-
- case CMD_TEE_GET_CORE_TRACE_LEVEL:
- return CMD_TEE_GET_CORE_TRACE_LEVEL_STR;
-
- case CMD_TEE_SET_TA_TRACE_LEVEL:
- return CMD_TEE_SET_TA_TRACE_LEVEL_STR;
-
- case CMD_TEE_GET_TA_TRACE_LEVEL:
- return CMD_TEE_GET_TA_TRACE_LEVEL_STR;
-
- case CMD_REGISTER_DEF_SHM:
- return CMD_REGISTER_DEF_SHM_STR;
- case CMD_UNREGISTER_DEF_SHM:
- return CMD_UNREGISTER_DEF_SHM_STR;
-
- default:
- return NULL;
- }
-}
diff --git a/generic/tee_service.c b/generic/tee_service.c
deleted file mode 100644
index 78fe38e..0000000
--- a/generic/tee_service.c
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/uaccess.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/highmem.h>
-
-#include "tee-op.h"
-#include "tee_driver.h"
-#include "tee_service.h"
-#include "tee_tz.h"
-
-struct tee_targetop *tee_get_target(const char *devname)
-{
- if (strcmp(devname, TEE_TZ_NAME) == 0)
- return &TZop;
- return NULL;
-}
-
-struct tee_session *tee_create_session(const char *devname, bool userApi)
-{
- struct tee_targetop *op;
- struct tee_session *ts;
- struct tee_driver *tee = NULL;
- int count_session = -1;
- struct device *dev = NULL;
-
- op = tee_get_target(devname);
- if (op == NULL) {
- dev_err(dev, "[%s] Invalid TEE device name '%s'",
- __func__, devname);
- return NULL;
- }
-
- dev = op->miscdev->this_device;
- dev_dbg(dev, "> count_session:[%d] devname:[%s]\n",
- count_session, devname);
-
- tee = tee_get_drvdata(dev);
- count_session = tee->count_session;
-
- ts = (struct tee_session *)devm_kzalloc(dev, sizeof(struct tee_session),
- GFP_KERNEL);
- if (ts == NULL) {
- dev_err(dev, "[%s] allocation failed", __func__);
- return NULL;
- }
- mutex_lock(&tee->mutex_tee);
- tee->count_session++;
- mutex_unlock(&tee->mutex_tee);
-
- mutex_init(&ts->syncstate);
- ts->op = op;
- ts->state = TEED_STATE_OPEN_DEV;
- ts->id = 0;
- ts->ta = NULL;
- ts->tasize = 0;
- ts->uuid = NULL;
- ts->login = TEEC_LOGIN_PUBLIC;
- ts->userApi = userApi;
-
- dev_dbg(dev, "< count_session:[%d] ts:[%p]\n", count_session, ts);
- return ts;
-}
-
-void tee_delete_session(struct tee_session *ts)
-{
- struct device *dev = ts->op->miscdev->this_device;
- struct tee_driver *tee = tee_get_drvdata(dev);
- int count_session = tee->count_session;
-
- dev_dbg(dev, "> session:[%p] count_session:[%d]\n", ts, count_session);
-
- /* Close session to secure world if a session is open */
- if (ts->state == TEED_STATE_OPEN_SESSION) {
- ts->op->call_sec_world(ts, CMD_TEEC_CLOSE_SESSION, 0, 0x0,
- NULL, NULL);
- }
-
- if (ts->ta != NULL)
- tee_shm_pool_free(dev, ts->op->Allocator,
- tee_shm_pool_v2p(dev, ts->op->Allocator,
- ts->ta), NULL);
-
- if (ts->uuid != NULL)
- tee_shm_pool_free(dev, ts->op->Allocator,
- tee_shm_pool_v2p(dev, ts->op->Allocator,
- ts->uuid), NULL);
-
- mutex_lock(&tee->mutex_tee);
- count_session = --tee->count_session;
- BUG_ON(tee->count_session < 0);
- mutex_unlock(&tee->mutex_tee);
-
- if (!count_session) {
-#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 1)
- tee_shm_pool_dump(dev, ts->op->Allocator, true);
-#endif
- tee_shm_pool_reset(dev, ts->op->Allocator);
- }
-
- devm_kfree(dev, ts);
-
- dev_dbg(dev, "<\n");
-}
-
-struct ListPhysicalAddr {
- unsigned long paddr; /* Physical address */
- unsigned int refcounter; /* Refcounter */
- struct mem_part *part; /* memory part of the allocation */
- void *handle; /* handle to registered shared memory */
- struct ListPhysicalAddr *next;
-};
-
-struct ListPhysicalAddr *_listPhysicalAddr;
-static DEFINE_MUTEX(list_paddr_lock);
-
-#define _DUMP_INFO_SHM 0
-#if _DUMP_INFO_SHM == 1
-static void tee_DumpShm(struct device *dev, char *message)
-{
- struct ListPhysicalAddr *list;
-
- dev_info(dev, "tee_DumpShm() %s\n", message);
- if (!_listPhysicalAddr)
- dev_info(dev, " | No more shared memory\n");
- for (list = _listPhysicalAddr; list; list = list->next) {
- dev_info(dev,
- " | paddr [0x%p] refcounter [%d] part [0x%p]\n",
- (void *)list->paddr, list->refcounter, list->part);
-
- }
-}
-#endif
-
-struct ListPhysicalAddr *addPhysicalAddr(struct device *dev,
- unsigned long paddr, struct mem_part *part, bool mem_allocated)
-{
- struct ListPhysicalAddr *list, *ret;
-
- dev_dbg(dev, "Adding physical address %p\n", (void *)paddr);
-
- mutex_lock(&list_paddr_lock);
- list = _listPhysicalAddr;
-
- while (list) {
- if (list->paddr == paddr) {
- if (part) {
- dev_err(dev, "[%s] Found physical address %p\n",
- __func__, (void *)paddr);
- dev_err(dev, " but with part==%p\n",
- (void *)part);
- ret = NULL;
- goto out;
- }
- list->refcounter++;
-#if _DUMP_INFO_SHM == 1
- tee_DumpShm(dev, "addPhysicalAddr() reference found");
-#endif
- ret = list;
- goto out;
- }
- list = list->next;
- }
- mutex_unlock(&list_paddr_lock);
-
- if (mem_allocated && !part) {
- dev_err(dev, "[%s] New physical address with part==NULL\n",
- __func__);
- return NULL;
- }
-
- list = (struct ListPhysicalAddr *)devm_kzalloc(dev,
- sizeof(struct ListPhysicalAddr), GFP_KERNEL);
- if (list == NULL) {
- dev_err(dev,
- "[%s] Cannot allocate a new element in the list\n",
- __func__);
- return NULL;
- }
-
- memset(list, 0, sizeof(struct ListPhysicalAddr));
- list->paddr = paddr;
- list->part = part;
- list->refcounter = 1;
- mutex_lock(&list_paddr_lock);
- list->next = _listPhysicalAddr;
- _listPhysicalAddr = list;
- ret = list;
-out:
- mutex_unlock(&list_paddr_lock);
-#if _DUMP_INFO_SHM == 1
- tee_DumpShm(dev, "addPhysicalAddr() new reference");
-#endif
- return ret;
-}
-
-static bool isPhysicalAddr(struct device *dev, unsigned long paddr)
-{
- struct ListPhysicalAddr *list;
-
- mutex_lock(&list_paddr_lock);
-
- list = _listPhysicalAddr;
- while (list) {
- if (list->paddr == paddr) {
- mutex_unlock(&list_paddr_lock);
- return true;
- }
- list = list->next;
- }
- mutex_unlock(&list_paddr_lock);
- return false;
-}
-
-unsigned int removePhysicalAddr(struct device *dev, unsigned long paddr,
- struct mem_part **part, void **handle)
-{
- struct ListPhysicalAddr *list, *prev = 0;
-
- mutex_lock(&list_paddr_lock);
-
- list = _listPhysicalAddr;
- *part = 0;
- *handle = 0;
-
- while (list) {
- if (list->paddr == paddr) {
- *part = list->part;
- *handle = list->handle;
- if (list->refcounter == 1) {
- if (prev)
- prev->next = list->next;
- else
- _listPhysicalAddr = list->next;
-
- mutex_unlock(&list_paddr_lock);
- devm_kfree(dev, list);
-#if _DUMP_INFO_SHM == 1
- dev_info(dev, "[0x%p] is removed\n", paddr);
- tee_DumpShm(dev,
- "removePhysicalAddr() removing a reference");
-#endif
-
- return 0;
- } else {
- list->refcounter--;
- mutex_unlock(&list_paddr_lock);
-#if _DUMP_INFO_SHM == 1
- dev_info(dev, "[0x%p] has its refcounter decreased [%d]\n",
- paddr, list->refcounter);
- tee_DumpShm(dev,
- "removePhysicalAddr() decreased refcounter");
-#endif
- return list->refcounter;
- }
- }
- prev = list;
- list = list->next;
- }
- mutex_unlock(&list_paddr_lock);
-
- /* error */
- dev_err(dev, "[%s] Cannot find physical address to remove\n", __func__);
- return -1;
-}
-
-static unsigned long GetPhysicalContiguous(unsigned long ptr)
-{
- struct mm_struct *mm = current->mm;
- /* struct vma_area_struct *vma = find_vma(mm, ptr); */
- unsigned virt_base = (ptr / PAGE_SIZE) * PAGE_SIZE;
- unsigned phys_base = 0;
-
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- /* if the caller is the kernel api, active_mm is mm */
- if (!mm)
- mm = current->active_mm;
-
- spin_lock(&mm->page_table_lock);
-
- pgd = pgd_offset(mm, virt_base);
- if (pgd_none(*pgd) || pgd_bad(*pgd))
- goto out;
-
- pmd = pmd_offset((pud_t *)pgd, virt_base);
- if (pmd_none(*pmd) || pmd_bad(*pmd))
- goto out;
-
- ptep = pte_offset_map(pmd, virt_base);
-
- if (!ptep)
- goto out;
-
- pte = *ptep;
-
- if (pte_present(pte))
- phys_base = __pa(page_address(pte_page(pte)));
-
- if (!phys_base)
- goto out;
-
- spin_unlock(&mm->page_table_lock);
- return phys_base + (ptr - virt_base);
-
-out:
- spin_unlock(&mm->page_table_lock);
- return 0;
-}
-
-static unsigned long tee_shm_iscontinuous(
- struct device *dev,
- void *vaddr,
- unsigned long size)
-{
- struct vm_area_struct *vma;
- struct mm_struct *mm = current->mm;
-
- /* if the caller is the kernel api, active_mm is mm */
- if (!mm)
- mm = current->active_mm;
-
- vma = find_vma(mm, (unsigned long)vaddr);
-
- if (vma == NULL) {
- /* It's not a VMA => consider it as a kernel address
- * And look if it's an internal known phys addr
- * Note: virt_to_phys is not usable since it can be a direct
- * map or a vremap address
- */
- unsigned long paddr;
-
- paddr = GetPhysicalContiguous((unsigned long)vaddr);
- if (isPhysicalAddr(dev, paddr))
- return paddr;
- } else {
- void *paddr = vma->vm_private_data;
- /* It's a VMA => consider it a a user address */
- if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) {
- dev_err(dev, "[%s] 0x%p not Contiguous %p\n", __func__,
- vaddr, paddr);
- return 0x0;
- }
-
- if (vma->vm_end - vma->vm_start < size) {
- dev_err(dev, "[%s] 0x%p not big enough %p %ld %ld\n",
- __func__, vaddr, paddr,
- vma->vm_end - vma->vm_start, size);
- return 0x0;
- }
-
- return (unsigned long)paddr;
- }
-
- return 0x0;
-}
-
-struct tee_shm *tee_shm_allocate(struct tee_targetop *op,
- void *vaddr, size_t size, uint32_t flags)
-{
- struct device *dev = op->miscdev->this_device;
- struct tee_shm *shm;
- struct ListPhysicalAddr *list = 0;
- struct mem_part *part = 0, *part_removed = 0;
- void *handle;
- struct tee_driver *tee = NULL;
- tee = tee_get_drvdata(dev);
-
- dev_dbg(dev, "> vaddr:[%p] size:[%zu]\n", (void *)vaddr, size);
-
- /*
- * Adjust the size in case it is 0 as, from the spec:
- * The size is allowed to be zero. In this case memory is
- * allocated and the pointer written in to the buffer field
- * on return MUST not be NULL but MUST never be de-referenced
- * by the Client Application. In this case however, the
- * Shared Memory block can be used in Registered Memory References
- */
- if (size == 0)
- size = 8;
-
- /* Align the size to be ICS compliant */
- if ((size % op->page_size) != 0)
- size = ((size / op->page_size) + 1) * op->page_size;
-
- if (unlikely(size == 0)) {
- dev_err(dev, "[%s] requested size too big\n", __func__);
- return NULL;
- }
-
- shm = (struct tee_shm *)devm_kzalloc(dev, sizeof(struct tee_shm),
- GFP_KERNEL);
- if (shm == NULL)
- return NULL;
-
- shm->op = op;
-
- if (vaddr == NULL) {
- shm->paddr = tee_shm_pool_alloc(dev,
- op->Allocator, size, op->page_size);
-
- if (shm->paddr == 0x0) {
- dev_err(dev, "[%s] out of shared memory (%zu)\n",
- __func__, size);
- goto out_shm;
- }
- } else {
- if (flags & SHM_ALLOCATE_FROM_PHYSICAL) {
- shm->paddr = (unsigned long)vaddr;
- } else {
- shm->paddr = tee_shm_iscontinuous(dev, vaddr, size);
- if (shm->paddr == 0x0) {
- dev_err(dev, "[%s] SHM not contiguous (0x%p + %zu)\n",
- __func__, vaddr, size);
- goto out_shm;
- }
- }
- }
-
- list = addPhysicalAddr(dev, shm->paddr, part,
- false);
- if (!list)
- goto out_mem;
- if (list->refcounter == 1)
- if (op->register_shm(shm->paddr, size, &list->handle)
- != TEEC_SUCCESS) {
- dev_err(dev, "[%s] Cannot register [0x%p] size [%zu]\n",
- __func__, (void *)shm->paddr, size);
- goto out_mem;
- }
-
- dev_dbg(dev, "< %p + %zd\n", (void *)shm->paddr, size);
- return shm;
-
-out_mem:
- if (list)
- removePhysicalAddr(dev, shm->paddr, &part_removed, &handle);
-
- tee_shm_pool_free(dev, shm->op->Allocator, shm->paddr, &size);
-out_shm:
- if (shm)
- devm_kfree(dev, shm);
- dev_dbg(dev, "<\n");
- return NULL;
-}
-
-void tee_shm_unallocate(struct tee_shm *shm)
-{
- struct device *dev = shm->op->miscdev->this_device;
- struct mem_part *part;
- void *handle;
- size_t size;
- struct tee_driver *tee = NULL;
- unsigned int refcounter =
- removePhysicalAddr(dev, shm->paddr, &part, &handle);
- tee = tee_get_drvdata(dev);
-
- if (refcounter == 0) {
- if (handle)
- shm->op->unregister_shm(handle);
-
- tee_shm_pool_free(dev,
- shm->op->Allocator, shm->paddr, &size);
- }
-
- devm_kfree(dev, shm);
-}
-
-TEEC_Result allocate_uuid(struct tee_session *ts)
-{
- unsigned long paddr;
- struct device *dev = ts->op->miscdev->this_device;
-
- dev_dbg(dev, "> session: [0x%p]\n", ts);
-
- paddr = tee_shm_pool_alloc(
- dev, ts->op->Allocator, sizeof(TEEC_UUID), 0);
- if (paddr == 0x0) {
- dev_err(dev, "[%s] error, out of memory\n", __func__);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- ts->uuid = tee_shm_pool_p2v(dev, ts->op->Allocator, paddr);
-
- dev_dbg(dev, "<\n");
- return TEEC_SUCCESS;
-}
-
-static TEEC_Result tee_cpy_memref(struct tee_session *ts, void *buffer,
- uint32_t size, TEEC_Value *param, int type)
-{
- unsigned long paddr;
- void *vaddr;
- size_t size_allocate = (size_t)size;
- struct device *dev = ts->op->miscdev->this_device;
-
- dev_dbg(dev, "> session: [0x%p] buffer [0x%p]\n", ts, buffer);
- param->b = size;
-
- /* Size 0 is OK to use.
- * Artificially set the size to 8 for buffer allocation
- */
- if (size_allocate == 0)
- size_allocate = 8;
-
- /*
- * Allocate consecutive memory
- */
- paddr = tee_shm_pool_alloc(dev, ts->op->Allocator, size_allocate, 0);
- if (!paddr) {
- dev_err(dev, "[%s] couldn't alloc tee memory\n", __func__);
- return TEEC_ERROR_OUT_OF_MEMORY;
- }
-
- vaddr = tee_shm_pool_p2v(dev, ts->op->Allocator, paddr);
-
- if ((size) && (type != TEEC_MEMREF_TEMP_OUTPUT)) {
- if (ts->userApi) {
- if (copy_from_user(vaddr, buffer, size)) {
- dev_err(dev, " *** tee_cpy_memref(0x%p, %lx, %d) failed\n",
- buffer, paddr, size);
- tee_shm_pool_free(dev, ts->op->Allocator,
- paddr, NULL);
- return TEEC_ERROR_BAD_PARAMETERS;
- }
- } else {
- memcpy(vaddr, buffer, size);
- }
- }
-
- param->a = paddr;
-
- dev_dbg(dev, "< copied to vaddr [0x%p] paddr [0x%p]\n",
- vaddr, (void *)paddr);
- return TEEC_SUCCESS;
-}
-
-static TEEC_Result tee_resolve_shm(struct device *dev, TEEC_SharedMemory *shm,
- TEEC_Value *param)
-{
- unsigned long paddr;
-
- BUG_ON(shm->buffer == NULL);
-
- paddr = tee_shm_iscontinuous(dev, shm->buffer, shm->size);
- if (paddr == 0x0)
- return TEEC_ERROR_NOT_SUPPORTED;
-
- dev_dbg(dev, "[%s] => %lx\n", __func__, paddr);
-
- param->a = (uint32_t) (paddr);
- param->b = shm->size;
-
- return TEEC_SUCCESS;
-}
-
-TEEC_Result copy_op(struct tee_session *ts, TEEC_Operation *op,
- unsigned long
- tmp_allocated_memories[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT])
-{
- TEEC_Result ret;
- int memref;
- struct device *dev = ts->op->miscdev->this_device;
- dev_dbg(dev, ">\n");
-
- *param_type = 0;
-
- for (memref = 0; memref < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++memref)
- tmp_allocated_memories[memref] = 0UL;
-
- for (memref = 0; memref < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++memref) {
- int type = TEEC_PARAM_TYPE_GET(op->paramTypes, memref);
- dev_dbg(dev, "type [0x%x]\n", type);
-
- switch (type) {
- case TEEC_NONE:
- break;
- case TEEC_VALUE_INPUT:
- case TEEC_VALUE_OUTPUT:
- case TEEC_VALUE_INOUT: {
- /* nothing to copy or allocate */
- params[memref] = op->params[memref].value;
- dev_dbg(dev, " params[%d] = %x:%x (VALUE)\n",
- memref, params[memref].a,
- params[memref].b);
- break;
- }
- case TEEC_MEMREF_TEMP_INPUT:
- case TEEC_MEMREF_TEMP_OUTPUT:
- case TEEC_MEMREF_TEMP_INOUT: {
- ret = tee_cpy_memref(ts,
- op->params[memref].tmpref.buffer,
- op->params[memref].tmpref.size,
- &params[memref], type);
- if (ret != TEEC_SUCCESS)
- goto out_failed;
- tmp_allocated_memories[memref] =
- params[memref].a;
- dev_dbg(dev, " params[%d] = %x + %d (TEMP)\n",
- memref, params[memref].a,
- params[memref].b);
- break;
- }
- case TEEC_MEMREF_WHOLE: {
- TEEC_SharedMemory shm;
-
- if (ts->userApi) {
- if (copy_from_user(&shm,
- op->
- params[memref].memref.parent,
- sizeof(TEEC_SharedMemory))) {
- ret = TEEC_ERROR_BAD_PARAMETERS;
- goto out_failed;
- }
- } else {
- shm = *op->params[memref].memref.parent;
- }
-
- if (shm.flags == TEEC_MEM_INPUT)
- type = TEEC_MEMREF_TEMP_INPUT;
- else if (shm.flags == TEEC_MEM_OUTPUT)
- type = TEEC_MEMREF_TEMP_OUTPUT;
- else if (shm.flags ==
- (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))
- type = TEEC_MEMREF_TEMP_INOUT;
-
- if (tee_resolve_shm(dev, &shm, &params[memref])
- != TEEC_SUCCESS) {
- /* This is not a continuous
- * allocated buffer => Do copy */
- ret = tee_cpy_memref(ts,
- shm.buffer,
- shm.size,
- &params[memref],
- type);
- if (ret != TEEC_SUCCESS)
- goto out_failed;
- tmp_allocated_memories[memref] =
- params[memref].a;
- }
-
- dev_dbg(dev,
- " params[%d] = %x + %d (WHOLE)\n",
- memref, params[memref].a,
- params[memref].b);
- break;
- }
- case TEEC_MEMREF_PARTIAL_INPUT:
- case TEEC_MEMREF_PARTIAL_OUTPUT:
- case TEEC_MEMREF_PARTIAL_INOUT: {
- u32 offset = op->params[memref].memref.offset;
- u32 size = op->params[memref].memref.size;
- TEEC_SharedMemory shm;
-
- if (ts->userApi) {
- if (copy_from_user(&shm ,
- op->
- params[memref].memref.parent,
- sizeof(TEEC_SharedMemory))) {
- ret = TEEC_ERROR_BAD_PARAMETERS;
- goto out_failed;
- }
- } else {
- shm = *op->params[memref].memref.parent;
- }
-
- if (type == TEEC_MEMREF_PARTIAL_INPUT)
- type = TEEC_MEMREF_TEMP_INPUT;
- else if (type == TEEC_MEMREF_PARTIAL_OUTPUT)
- type = TEEC_MEMREF_TEMP_OUTPUT;
- else if (type == TEEC_MEMREF_PARTIAL_INOUT)
- type = TEEC_MEMREF_TEMP_INOUT;
-
- if (tee_resolve_shm(dev, &shm, &params[memref])
- != TEEC_SUCCESS) {
- /* This is not a continuous
- * allocated buffer => Do copy */
- ret = tee_cpy_memref(ts,
- (uint8_t *)shm.
- buffer + offset,
- size,
- &params[memref],
- type);
- if (ret != TEEC_SUCCESS)
- goto out_failed;
- tmp_allocated_memories[memref] =
- params[memref].a;
- } else {
- params[memref].a += offset;
- params[memref].b = size;
- }
- dev_dbg(dev,
- " params[%d] = %x + %d (PARTIAL)\n",
- memref, params[memref].a,
- params[memref].b);
- break;
- }
- default:
- ret = TEEC_ERROR_BAD_PARAMETERS;
- goto out_failed;
- }
-
- *param_type |= (type << (memref * 4));
- }
-
- dev_dbg(dev, "< TEEC_SUCCESS\n");
- return TEEC_SUCCESS;
-
-out_failed:
- for (memref = 0; memref < TEEC_CONFIG_PAYLOAD_REF_COUNT; memref++)
- if (tmp_allocated_memories[memref] != 0UL) {
- tee_shm_pool_free(dev, ts->op->Allocator,
- tmp_allocated_memories[memref], NULL);
- tmp_allocated_memories[memref] = 0UL;
- }
- return ret;
-}
-
-static TEEC_Result tee_update_buffer(struct device *dev, struct tee_session *ts,
- void *buffer,
- unsigned long paddr, unsigned int size)
-{
- void *vaddr = tee_shm_pool_p2v(dev, ts->op->Allocator, paddr);
-
- dev_dbg(dev, "[%d] [%p] [%p] [%p] %d\n",
- ts->userApi, buffer, (void *)paddr, vaddr, size);
-
- if (ts->userApi) {
- if (copy_to_user(buffer, vaddr, size)) {
- dev_err(dev,
- " *** tee_update_buffer(0x%p, %lx, %d) failed\n",
- buffer, paddr, size);
- return TEEC_ERROR_BAD_PARAMETERS;
- }
- } else {
- memcpy(buffer, vaddr, size);
- }
-
- dev_dbg(dev, "< TEEC_SUCCESS\n");
- return TEEC_SUCCESS;
-}
-
-TEEC_Result uncopy_op(struct tee_session *ts, TEEC_Operation *op,
- unsigned long
- tmp_allocated_memories[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT])
-{
- int memref;
- TEEC_Result ret = TEEC_SUCCESS;
- struct device *dev = ts->op->miscdev->this_device;
-
- dev_dbg(dev, "> session: [0x%p]\n", ts);
-
-
- for (memref = 0; memref < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++memref) {
- int type = TEEC_PARAM_TYPE_GET(op->paramTypes, memref);
- dev_dbg(dev, "type [0x%x]\n", type);
- switch (type) {
- case TEEC_NONE:
- case TEEC_VALUE_INPUT:
- case TEEC_MEMREF_TEMP_INPUT:
- case TEEC_MEMREF_PARTIAL_INPUT:
- /* nothing to copy */
- break;
-
- case TEEC_VALUE_OUTPUT:
- case TEEC_VALUE_INOUT:
- op->params[memref].value = params[memref];
- break;
-
- case TEEC_MEMREF_TEMP_OUTPUT:
- case TEEC_MEMREF_TEMP_INOUT:
- {
- op->params[memref].tmpref.size =
- params[memref].b;
- ret =
- tee_update_buffer(dev, ts,
- op->params[memref].tmpref.
- buffer, params[memref].a,
- params[memref].b);
- break;
- }
- case TEEC_MEMREF_WHOLE:
- {
- TEEC_SharedMemory shm;
-
- if (ts->userApi) {
- if (copy_from_user
- (&shm,
- op->params[memref].memref.parent,
- sizeof(TEEC_SharedMemory)))
- goto inval;
- } else {
- shm = *op->params[memref].memref.parent;
- }
-
- op->params[memref].memref.size =
- params[memref].b;
- if (tmp_allocated_memories[memref] != 0x0) {
- ret =
- tee_update_buffer(dev, ts,
- shm.buffer,
- params[memref].a,
- shm.size);
- }
- break;
- }
- case TEEC_MEMREF_PARTIAL_OUTPUT:
- case TEEC_MEMREF_PARTIAL_INOUT:
- {
- u32 offset = op->params[memref].memref.offset;
- size_t size = params[memref].b;
- TEEC_SharedMemory shm;
-
- if (ts->userApi) {
- if (copy_from_user
- (&shm,
- op->params[memref].memref.parent,
- sizeof(TEEC_SharedMemory)))
- goto inval;
- } else {
- shm = *op->params[memref].memref.parent;
- }
-
- /* ensure we do not exceed
- * the shared buffer length */
- if ((offset + size) > shm.size) {
- dev_err(dev,
- " *** Wrong returned size from %d\n",
- memref);
- goto inval;
- }
-
- op->params[memref].memref.size = size;
- if (tmp_allocated_memories[memref] != 0x0) {
- ret =
- tee_update_buffer(dev, ts,
- shm.buffer +
- offset,
- params[memref].a,
- size);
- }
- break;
- }
- default:
- goto inval;
- }
- if (ret != TEEC_SUCCESS)
- goto out;
- }
-
- goto out;
-inval:
- ret = TEEC_ERROR_BAD_PARAMETERS;
-out:
- for (memref = 0; memref < TEEC_CONFIG_PAYLOAD_REF_COUNT; memref++)
- if (tmp_allocated_memories[memref] != 0x0)
- tee_shm_pool_free(dev, ts->op->Allocator,
- tmp_allocated_memories[memref],
- NULL);
-
- dev_dbg(dev, "< [%d]\n", ret);
-
- return ret;
-}
diff --git a/generic/tee_service.h b/generic/tee_service.h
deleted file mode 100644
index 316555a..0000000
--- a/generic/tee_service.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#ifndef TEE_SERVICE_H
-#define TEE_SERVICE_H
-
-#include <linux/types.h>
-
-#define SHM_ALLOCATE_FROM_PHYSICAL 0x100
-
-struct tee_shm {
- struct tee_targetop *op;
- unsigned long paddr;
-};
-
-struct tee_targetop *tee_get_target(const char *devname);
-
-struct tee_session *tee_create_session(const char *devname, bool userApi);
-void tee_delete_session(struct tee_session *ts);
-
-struct tee_shm *tee_shm_allocate(struct tee_targetop *op,
- void *vaddr, size_t size, uint32_t flags);
-void tee_shm_unallocate(struct tee_shm *shm);
-
-TEEC_Result allocate_uuid(struct tee_session *ts);
-
-TEEC_Result copy_op(struct tee_session *ts, TEEC_Operation *op,
- unsigned long
- tmp_allocated_memories[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- uint32_t *param_type,
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT]);
-TEEC_Result uncopy_op(struct tee_session *ts, TEEC_Operation *op,
- unsigned long
- tmp_allocated_memories[TEEC_CONFIG_PAYLOAD_REF_COUNT],
- TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT]);
-void free_temp_op(struct tee_session *ts,
- unsigned long
- tmp_allocated_memories[TEEC_CONFIG_PAYLOAD_REF_COUNT]);
-
-#endif
diff --git a/generic/tee_supp_com.c b/generic/tee_supp_com.c
deleted file mode 100644
index 1b74172..0000000
--- a/generic/tee_supp_com.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include <linux/miscdevice.h>
-#include <linux/uaccess.h>
-#include <linux/anon_inodes.h>
-#include <linux/semaphore.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/device.h>
-
-#include "tee-op.h"
-#include "tee_mem.h"
-#include "tee_service.h"
-#include "tee_supp_com.h"
-#include "tee_driver.h"
-
-enum teec_rpc_result tee_supp_cmd(struct tee_targetop *op,
- uint32_t id, void *data,
- unsigned int datalen)
-{
- struct device *dev = op->miscdev->this_device;
- struct tee_rpc_priv_data *rpc = &tee_get_drvdata(dev)->rpc;
- enum teec_rpc_result res = TEEC_RPC_FAIL;
- size_t size; /* size of block */
- struct task_struct *task = current;
-
- dev_dbg(dev, "> tgid:[%d] op:[0x%p] id:[0x%x]\n",
- task->tgid, (void *)op, id);
-
- switch (id) {
- case TEE_RPC_ICMD_ALLOCATE:
- {
- struct tee_rpc_alloc *alloc;
- struct tee_shm *shmint;
-
- alloc = (struct tee_rpc_alloc *)data;
- size = alloc->size;
- memset(alloc, 0, sizeof(struct tee_rpc_alloc));
- shmint = tee_shm_allocate(op, 0, size, 0);
- if (shmint == NULL)
- break;
-
- alloc->size = size;
- alloc->data = (void *)shmint->paddr;
- alloc->shm = shmint;
- res = TEEC_RPC_OK;
-
- break;
- }
- case TEE_RPC_ICMD_FREE:
- {
- struct tee_rpc_free *free;
-
- free = (struct tee_rpc_free *)data;
- tee_shm_unallocate(free->shm);
- res = TEEC_RPC_OK;
- break;
- }
- case TEE_RPC_ICMD_INVOKE:
- {
- if (sizeof(rpc->commToUser) < datalen)
- break;
-
- /*
- * Don't allow interleaved requests (from two
- * different threads) as the second request will
- * overwrite the first request.
- */
- mutex_lock(&rpc->reqsync);
-
- mutex_lock(&rpc->outsync);
-
- memcpy(&rpc->commToUser, data, datalen);
-
- mutex_unlock(&rpc->outsync);
-
- dev_dbg(dev, "Supplicant Cmd: %x. Give hand to supplicant\n",
- rpc->commToUser.cmd);
-
- up(&rpc->datatouser);
-
- down(&rpc->datafromuser);
-
- dev_dbg(dev, "Supplicant Cmd: %x. Give hand to fw\n",
- rpc->commToUser.cmd);
-
- mutex_lock(&rpc->insync);
-
- memcpy(data, &rpc->commFromUser, datalen);
-
- mutex_unlock(&rpc->insync);
-
- mutex_unlock(&rpc->reqsync);
-
- res = TEEC_RPC_OK;
-
- break;
- }
- default:
- /* not supported */
- break;
- }
-
- dev_dbg(dev, "< res: [%d]\n", res);
-
- return res;
-}
-
-ssize_t tee_supp_read(struct file *filp, char __user *buffer,
- size_t length, loff_t *offset)
-{
- struct tee_session *ts = (struct tee_session *)(filp->private_data);
- struct device *dev = ts->op->miscdev->this_device;
- struct tee_rpc_priv_data *rpc = &tee_get_drvdata(dev)->rpc;
- struct task_struct *task = current;
- int ret;
-
- if (down_interruptible(&rpc->datatouser))
- return -ERESTARTSYS;
-
- dev_dbg(dev, "> tgid:[%d] ts:[0x%p]\n", task->tgid, (void *)ts);
-
- mutex_lock(&rpc->outsync);
-
- ret =
- sizeof(rpc->commToUser) - sizeof(rpc->commToUser.cmds) +
- sizeof(rpc->commToUser.cmds[0]) * rpc->commToUser.nbr_bf;
- if (length < ret) {
- ret = -EINVAL;
- } else {
- if (copy_to_user(buffer, &rpc->commToUser, ret)) {
- dev_err(dev,
- "[%s] error, copy_to_user failed!\n", __func__);
- ret = -EINVAL;
- }
- }
-
- mutex_unlock(&rpc->outsync);
-
- dev_dbg(dev, "< [%d]\n", ret);
- return ret;
-}
-
-ssize_t tee_supp_write(struct file *filp, const char __user *buffer,
- size_t length, loff_t *offset)
-{
- struct tee_session *ts = (struct tee_session *)(filp->private_data);
- struct device *dev = ts->op->miscdev->this_device;
- struct tee_rpc_priv_data *rpc = &tee_get_drvdata(dev)->rpc;
- struct task_struct *task = current;
- dev_dbg(dev, "> tgid:[%d] ts:[0x%p]\n", task->tgid, (void *)ts);
-
- if (length > 0 && length < sizeof(rpc->commFromUser)) {
- uint32_t i;
-
- mutex_lock(&rpc->insync);
-
- if (copy_from_user(&rpc->commFromUser, buffer, length)) {
- dev_err(dev,
- "[%s] error, tee_session copy_from_user failed\n",
- __func__);
- mutex_unlock(&rpc->insync);
- return -EINVAL;
- }
-
- /* Translate virtual address of caller into physical address */
- for (i = 0; i < rpc->commFromUser.nbr_bf; i++) {
- if (rpc->commFromUser.cmds[i].type == TEE_RPC_BUFFER &&
- rpc->commFromUser.cmds[i].buffer) {
- struct vm_area_struct *vma =
- find_vma(current->mm,
- (unsigned long)rpc->commFromUser.
- cmds[i].buffer);
- if (vma != NULL) {
-
- unsigned long paddr =
- (unsigned long)vma->vm_private_data;
-
- dev_dbg(dev, " gid2pa(0x%p => %lx)\n",
- rpc->
- commFromUser.cmds[i].buffer,
- paddr);
- rpc->commFromUser.cmds[i].buffer =
- (void *)paddr;
- } else
- dev_dbg(dev,
- " gid2pa(0x%p => NULL\n)",
- rpc->commFromUser.cmds[i].buffer);
- }
- }
-
- mutex_unlock(&rpc->insync);
- up(&rpc->datafromuser);
- dev_dbg(dev, "< [%zu]\n", length);
- return length;
- }
-
- dev_dbg(dev, "< [0]\n");
- return 0;
-}
-
-int tee_supp_init(struct tee_rpc_priv_data *rpc)
-{
- rpc->datafromuser = (struct semaphore)
- __SEMAPHORE_INITIALIZER(rpc->datafromuser, 0);
- rpc->datatouser = (struct semaphore)
- __SEMAPHORE_INITIALIZER(rpc->datatouser, 0);
- mutex_init(&rpc->outsync);
- mutex_init(&rpc->insync);
- mutex_init(&rpc->reqsync);
- return 0;
-}
-
-void tee_supp_exit(void)
-{
-}
-
diff --git a/include/arm_common/teesmc.h b/include/arm_common/teesmc.h
index 26cc9c2..cd0e70a 100644
--- a/include/arm_common/teesmc.h
+++ b/include/arm_common/teesmc.h
@@ -81,6 +81,8 @@
#define TEESMC_ATTR_CACHE_O_WRITE_THR 0x4
#define TEESMC_ATTR_CACHE_O_WRITE_BACK 0x8
+#define TEESMC_ATTR_CACHE_NONCACHE (TEESMC_ATTR_CACHE_I_NONCACHE | \
+ TEESMC_ATTR_CACHE_O_NONCACHE)
#define TEESMC_ATTR_CACHE_DEFAULT (TEESMC_ATTR_CACHE_I_WRITE_BACK | \
TEESMC_ATTR_CACHE_O_WRITE_BACK)
diff --git a/include/arm_common/teesmc_st.h b/include/arm_common/teesmc_st.h
index 915c7bb..58c00bb 100644
--- a/include/arm_common/teesmc_st.h
+++ b/include/arm_common/teesmc_st.h
@@ -47,10 +47,10 @@
TEESMC_ST_FUNCID_GET_SHM_CONFIG)
/*
- * Configures L2CC mutex
+ * Configures TZ/NS shared mutex for outer cache maintenance
*
- * Disables, enables usage of L2CC mutex. Returns or sets physical address
- * of L2CC mutex.
+ * Disables, enables usage of outercache mutex.
+ * Returns or sets physical address of outercache mutex.
*
* Call register usage:
* r0 SMC Function ID, TEESMC32_ST_FASTCALL_L2CC_MUTEX
diff --git a/include/linux/tee_client_api.h b/include/linux/tee_client_api.h
index 4445ed1..17ce6e5 100644
--- a/include/linux/tee_client_api.h
+++ b/include/linux/tee_client_api.h
@@ -1,22 +1,37 @@
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * 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_CLIENT_API_H
#define TEE_CLIENT_API_H
+#ifndef __KERNEL__
+#include <stdint.h>
+#include <stddef.h>
+#endif /* __KERNEL__ */
+
/*
* Defines the number of available memory references in an open session or
* invoke command operation payload.
@@ -135,6 +150,8 @@
* TEEC_ERROR_SECURITY A security fault was detected.
* TEEC_ERROR_SHORT_BUFFER The supplied buffer is too short for the
* generated output.
+ * TEEC_ERROR_TARGET_DEAD Trusted Application has panicked
+ * during the operation.
*/
/**
@@ -158,6 +175,7 @@
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
#define TEEC_ERROR_SECURITY 0xFFFF000F
#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
+#define TEEC_ERROR_TARGET_DEAD 0xFFFF3024
/**
* Function error origins, of type TEEC_ErrorOrigin. These indicate where in
@@ -216,6 +234,15 @@
typedef uint32_t TEEC_Result;
/**
+ * struct TEEC_Context - Represents a connection between a client application
+ * and a TEE.
+ */
+typedef struct {
+ char devname[256];
+ int fd;
+} TEEC_Context;
+
+/**
* This type contains a Universally Unique Resource Identifier (UUID) type as
* defined in RFC4122. These UUID values are used to identify Trusted
* Applications.
@@ -227,8 +254,6 @@ typedef struct {
uint8_t clockSeqAndNode[8];
} TEEC_UUID;
-struct tee_shm;
-
/**
* struct TEEC_SharedMemory - Memory to transfer data between a client
* application and trusted code.
@@ -249,9 +274,10 @@ typedef struct {
void *buffer;
size_t size;
uint32_t flags;
+ /* Implementation-Defined, must match what the kernel driver have */
union {
int fd;
- struct tee_shm *shm;
+ void *ptr;
} d;
uint8_t registered;
} TEEC_SharedMemory;
@@ -330,6 +356,14 @@ typedef union {
} TEEC_Parameter;
/**
+ * struct TEEC_Session - Represents a connection between a client application
+ * and a trusted application.
+ */
+typedef struct {
+ int fd;
+} TEEC_Session;
+
+/**
* struct TEEC_Operation - Holds information and memory references used in
* TEEC_InvokeCommand().
*
@@ -348,7 +382,171 @@ typedef struct {
uint32_t paramTypes;
TEEC_Parameter params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
/* Implementation-Defined */
- void *session;
+ TEEC_Session *session;
+ TEEC_SharedMemory memRefs[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+ uint32_t flags;
} TEEC_Operation;
+/**
+ * TEEC_InitializeContext() - Initializes a context holding connection
+ * information on the specific TEE, designated by the name string.
+
+ * @param name A zero-terminated string identifying the TEE to connect to.
+ * If name is set to NULL, the default TEE is connected to. NULL
+ * is the only supported value in this version of the API
+ * implementation.
+ *
+ * @param context The context structure which is to be initialized.
+ *
+ * @return TEEC_SUCCESS The initialization was successful.
+ * @return TEEC_Result Something failed.
+ */
+TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context);
+
+/**
+ * TEEC_FinalizeContext() - Destroys a context holding connection information
+ * on the specific TEE.
+ *
+ * This function destroys an initialized TEE context, closing the connection
+ * between the client application and the TEE. This function must only be
+ * called when all sessions related to this TEE context have been closed and
+ * all shared memory blocks have been released, otherwise an error will be
+ * returned.
+ *
+ * @param context The context to be destroyed.
+ *
+ * @return TEEC_SUCCESS The function call was successful.
+ * @return TEEC_Result Something failed.
+ */
+TEEC_Result TEEC_FinalizeContext(TEEC_Context *context);
+
+/**
+ * TEEC_OpenSession() - Opens a new session with the specified trusted
+ * application.
+ *
+ * @param context The initialized TEE context structure in which
+ * scope to open the session.
+ * @param session The session to initialize.
+ * @param destination A structure identifying the trusted application
+ * with which to open a session.
+ *
+ * @param connectionMethod The connection method to use.
+ * @param connectionData Any data necessary to connect with the chosen
+ * connection method. Not supported, should be set to
+ * NULL.
+ * @param operation An operation structure to use in the session. May
+ * be set to NULL to signify no operation structure
+ * needed.
+ *
+ * @param returnOrigin A parameter which will hold the error origin if
+ * this function returns any value other than
+ * TEEC_SUCCESS.
+ *
+ * @return TEEC_SUCCESS OpenSession successfully opened a new session.
+ * @return TEEC_Result Something failed.
+ *
+ */
+TEEC_Result TEEC_OpenSession(TEEC_Context *context,
+ TEEC_Session *session,
+ const TEEC_UUID *destination,
+ uint32_t connectionMethod,
+ const void *connectionData,
+ TEEC_Operation *operation,
+ uint32_t *returnOrigin);
+
+/**
+ * TEEC_CloseSession() - Closes the session which has been opened with the
+ * specific trusted application.
+ *
+ * @param session The opened session to close.
+ */
+void TEEC_CloseSession(TEEC_Session *session);
+
+/**
+ * TEEC_InvokeCommand() - Executes a command in the specified trusted
+ * application.
+ *
+ * @param session A handle to an open connection to the trusted
+ * application.
+ * @param commandID Identifier of the command in the trusted application
+ * to invoke.
+ * @param operation An operation structure to use in the invoke command.
+ * May be set to NULL to signify no operation structure
+ * needed.
+ * @param returnOrigin A parameter which will hold the error origin if this
+ * function returns any value other than TEEC_SUCCESS.
+ *
+ * @return TEEC_SUCCESS OpenSession successfully opened a new session.
+ * @return TEEC_Result Something failed.
+ */
+TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
+ uint32_t commandID,
+ TEEC_Operation *operation,
+ uint32_t *returnOrigin);
+
+/**
+ * TEEC_RegisterSharedMemory() - Register a block of existing memory as a
+ * shared block within the scope of the specified context.
+ *
+ * @param context The initialized TEE context structure in which scope to
+ * open the session.
+ * @param sharedMem pointer to the shared memory structure to register.
+ *
+ * @return TEEC_SUCCESS The registration was successful.
+ * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion.
+ * @return TEEC_Result Something failed.
+ */
+TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
+ TEEC_SharedMemory *sharedMem);
+
+/**
+ * TEEC_AllocateSharedMemory() - Allocate shared memory for TEE.
+ *
+ * @param context The initialized TEE context structure in which scope to
+ * open the session.
+ * @param sharedMem Pointer to the allocated shared memory.
+ *
+ * @return TEEC_SUCCESS The registration was successful.
+ * @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion.
+ * @return TEEC_Result Something failed.
+ */
+TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
+ TEEC_SharedMemory *sharedMem);
+
+/**
+ * TEEC_ReleaseSharedMemory() - Free or deregister the shared memory.
+ *
+ * @param sharedMem Pointer to the shared memory to be freed.
+ */
+void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory);
+
+/**
+ * TEEC_RequestCancellation() - Request the cancellation of a pending open
+ * session or command invocation.
+ *
+ * @param operation Pointer to an operation previously passed to open session
+ * or invoke.
+ */
+void TEEC_RequestCancellation(TEEC_Operation *operation);
+
+/**
+ * Register a pre-allocated Trusted Application This is mainly intended for
+ * OS-FREE contexts or when a filesystem is not available.
+ *
+ * @param ta Pointer to the trusted application binary
+ * @param size The size of the TA binary
+ *
+ * @return TEEC_SUCCESS if successful.
+ * @return TEEC_Result something failed.
+ */
+TEEC_Result TEEC_RegisterTA(const void *ta, const size_t size);
+
+/**
+ * Unregister a pre-allocated Trusted Application This is mainly intended for
+ * OS-FREE contexts or when a filesystem is not available.
+ *
+ * @param ta Pointer to the trusted application binary
+ */
+void TEEC_UnregisterTA(const void *ta);
+
#endif
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
new file mode 100644
index 0000000..4baeb92
--- /dev/null
+++ b/include/linux/tee_core.h
@@ -0,0 +1,186 @@
+
+#ifndef __TEE_CORE_DRV_H__
+#define __TEE_CORE_DRV_H__
+
+#include <linux/klist.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/cdev.h>
+#include <linux/debugfs.h>
+#include <linux/miscdevice.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+
+#include <linux/types.h>
+
+#include <linux/tee_client_api.h>
+
+struct tee_cmd_io;
+struct tee_shm_io;
+struct tee_rpc;
+
+enum tee_state {
+ TEE_OFFLINE = 0,
+ TEE_ONLINE = 1,
+ TEE_SUSPENDED = 2,
+ TEE_RUNNING = 3,
+ TEE_CRASHED = 4,
+ TEE_LAST = 5,
+};
+
+#define TEE_CONF_TEST_MODE 0x01000000
+#define TEE_CONF_FW_NOT_CAPABLE 0x00000001
+
+struct tee_stats_entry {
+ int count;
+ int max;
+};
+
+#define TEE_STATS_CONTEXT_IDX 0
+#define TEE_STATS_SESSION_IDX 1
+#define TEE_STATS_SHM_IDX 2
+
+#define TEE_MAX_TEE_DEV_NAME (64)
+struct tee {
+ struct klist_node node;
+ char name[TEE_MAX_TEE_DEV_NAME];
+ int id;
+ void *priv;
+ const struct tee_ops *ops;
+ struct device *dev;
+ struct miscdevice miscdev;
+ struct tee_rpc *rpc;
+ struct dentry *dbg_dir;
+ atomic_t refcount;
+ int max_refcount;
+ struct tee_stats_entry stats[3];
+ struct list_head list_ctx;
+ struct list_head list_rpc_shm;
+ struct mutex lock;
+ unsigned int state;
+ uint32_t shm_flags; /* supported flags for shm allocation */
+ uint32_t conf;
+ uint32_t test;
+};
+
+#define _DEV(tee) (tee->miscdev.this_device)
+
+#define TEE_MAX_CLIENT_NAME (128)
+
+/**
+ * struct tee_context - internal structure to store a TEE context.
+ *
+ * @tee: tee attached to the tee_context
+ * @usr_client: flag to known if the client is user side client
+ * @entry: list of tee_context
+ * @list_sess: list of tee_session that denotes all tee_session attached
+ * @list_shm: list of tee_shm that denotes all tee_shm attached
+ * @refcount: number of objects which reference it (including itself)
+ */
+struct tee_context {
+ struct tee *tee;
+ char name[TEE_MAX_CLIENT_NAME];
+ int tgid;
+ int usr_client;
+ struct list_head entry;
+ struct list_head list_sess;
+ struct list_head list_shm;
+ struct kref refcount;
+};
+
+/**
+ * struct tee_session - internal structure to store a TEE session.
+ *
+ * @entry: list of tee_context
+ * @ctx: tee_context attached to the tee_session
+ * @sessid: session ID returned by the secure world
+ * @priv: exporter specific private data for this buffer object
+ */
+struct tee_session {
+ struct list_head entry;
+ struct tee_context *ctx;
+ uint32_t sessid;
+ void *priv;
+};
+
+/**
+ * struct tee_shm - internal structure to store a shm object.
+ *
+ * @ctx: tee_context attached to the buffer.
+ * @tee: tee attached to the buffer.
+ * @dev: device attached to the buffer.
+ * @size_req: requested size for the buffer
+ * @size_alloc: effective size of the buffer
+ * @kaddr: kernel address if mapped kernel side
+ * @paddr: physical address
+ * @flags: flags which denote the type of the buffer
+ * @entry: list of tee_shm
+ */
+struct tee_shm {
+ struct list_head entry;
+ struct tee_context *ctx;
+ struct tee *tee;
+ struct device *dev;
+ size_t size_req;
+ size_t size_alloc;
+ void *kaddr;
+ dma_addr_t paddr;
+ uint32_t flags;
+ struct tee_shm *parent;
+};
+
+#define TEE_SHM_MAPPED 0x01000000
+#define TEE_SHM_TEMP 0x02000000
+#define TEE_SHM_FROM_RPC 0x04000000
+#define TEE_SHM_REGISTERED 0x08000000
+#define TEE_SHM_PARENT 0x10000000
+#define TEE_SHM_CACHED 0x20000000
+#define TEE_SHM_FROM_KAPI 0x40000000
+
+#define TEE_SHM_DRV_PRIV_MASK 0xFF000000
+
+struct tee_data {
+ uint32_t type;
+ uint32_t type_original;
+ TEEC_SharedMemory c_shm[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+ union {
+ struct tee_shm *shm;
+ TEEC_Value value;
+ } params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
+};
+
+struct tee_cmd {
+ TEEC_Result err;
+ uint32_t origin;
+ uint32_t cmd;
+ struct tee_shm *uuid;
+ struct tee_shm *ta;
+ struct tee_data param;
+};
+
+struct tee_shm *tee_shm_alloc_from_rpc(struct tee *tee, size_t size,
+ uint32_t flags);
+void tee_shm_free_from_rpc(struct tee_shm *);
+
+int tee_core_add(struct tee *tee);
+int tee_core_del(struct tee *tee);
+
+struct tee *tee_core_alloc(struct device *dev, char *name, int id,
+ const struct tee_ops *ops, size_t len);
+
+struct tee_ops {
+ struct module *owner;
+ const char *type;
+ int (*start) (struct tee *tee);
+ int (*stop) (struct tee *tee);
+ int (*open) (struct tee_session *sess, struct tee_cmd *cmd);
+ int (*close) (struct tee_session *sess);
+ int (*invoke) (struct tee_session *sess, struct tee_cmd *cmd);
+ int (*cancel) (struct tee_session *sess, struct tee_cmd *cmd);
+ struct tee_shm *(*alloc) (struct tee *tee, size_t size,
+ uint32_t flags);
+ void (*free) (struct tee_shm *shm);
+ int (*shm_inc_ref) (struct tee_shm *shm);
+};
+
+#endif /* __TEE_CORE_DRV_H__ */
diff --git a/include/linux/tee_ioc.h b/include/linux/tee_ioc.h
new file mode 100644
index 0000000..43af082
--- /dev/null
+++ b/include/linux/tee_ioc.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) ST-Microelectronics 2013. All rights reserved.
+ */
+#ifndef _TEE_IOC_H
+#define _TEE_IOC_H
+
+#include <linux/tee_client_api.h>
+
+#ifndef __KERNEL__
+#define __user
+#endif
+
+/**
+ * struct tee_cmd_io - The command sent to an open tee device.
+ * @err: Error code (as in Global Platform TEE Client API spec)
+ * @origin: Origin for the error code (also from spec).
+ * @cmd: The command to be executed in the trusted application.
+ * @uuid: The uuid for the trusted application.
+ * @data: The trusted application or memory block.
+ * @data_size: The size of the trusted application or memory block.
+ * @op: The cmd payload operation for the trusted application.
+ *
+ * This structure is mainly used in the Linux kernel for communication
+ * with the user space.
+ */
+struct tee_cmd_io {
+ TEEC_Result err;
+ uint32_t origin;
+ uint32_t cmd;
+ TEEC_UUID __user *uuid;
+ void __user *data;
+ uint32_t data_size;
+ TEEC_Operation __user *op;
+ int fd_sess;
+};
+
+struct tee_shm_io {
+ void __user *buffer;
+ size_t size;
+ uint32_t flags;
+ int fd_shm;
+ uint8_t registered;
+};
+
+#define TEE_OPEN_SESSION_IOC _IOWR('t', 161, struct tee_cmd_io)
+#define TEE_INVOKE_COMMAND_IOC _IOWR('t', 163, struct tee_cmd_io)
+#define TEE_REQUEST_CANCELLATION_IOC _IOWR('t', 164, struct tee_cmd_io)
+#define TEE_ALLOC_SHM_IOC _IOWR('t', 165, struct tee_shm_io)
+#define TEE_GET_FD_FOR_RPC_SHM_IOC _IOWR('t', 167, struct tee_shm_io)
+
+#endif /* _TEE_IOC_H */
diff --git a/include/linux/tee_ioctl.h b/include/linux/tee_ioctl.h
deleted file mode 100644
index 003dbdc..0000000
--- a/include/linux/tee_ioctl.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2014, STMicroelectronics International N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#ifndef TEE_H
-#define TEE_H
-
-/**
- * struct tee_cmd - The command sent to an open tee device.
- * @err: Error code (as in Global Platform TEE Client API spec)
- * @origin: Origin for the error code (also from spec).
- * @cmd: The command to be executed in the trusted application.
- * @uuid: The uuid for the trusted application.
- * @data: The trusted application or memory block.
- * @data_size: The size of the trusted application or memory block.
- * @op: The payload for the trusted application.
- *
- * This structure is mainly used in the Linux kernel for communication
- * with the user space.
- */
-struct tee_cmd {
- TEEC_Result err;
- uint32_t origin;
- uint32_t cmd;
- TEEC_UUID *uuid;
- void *data;
- uint32_t data_size;
- TEEC_Operation *op;
-};
-
-#define TEE_OPEN_SESSION_IOC _IOWR('t', 161, struct tee_cmd)
-#define TEE_CLOSE_SESSION_IOC _IOWR('t', 162, unsigned long)
-#define TEE_INVOKE_COMMAND_IOC _IOWR('t', 163, struct tee_cmd)
-#define TEE_REQUEST_CANCELLATION_IOC _IOWR('t', 164, struct tee_cmd)
-#define TEE_ALLOC_SHM_IOC _IOWR('t', 165, TEEC_SharedMemory)
-
-#endif
diff --git a/include/linux/tee_kernel_api.h b/include/linux/tee_kernel_api.h
index cd37df8..2093f1d 100644
--- a/include/linux/tee_kernel_api.h
+++ b/include/linux/tee_kernel_api.h
@@ -23,17 +23,17 @@
* struct TEEC_Context - Represents a connection between a client application
* and a TEE.
*/
-typedef struct {
+/*typedef struct {
char devname[256];
-} TEEC_Context;
+} TEEC_Context;*/
/**
* struct TEEC_Session - Represents a connection between a client application
* and a trusted application.
*/
-typedef struct {
+/*typedef struct {
void *session;
-} TEEC_Session;
+} TEEC_Session;*/
/**
* TEEC_InitializeContext() - Initializes a context holding connection
@@ -95,11 +95,11 @@ TEEC_Result TEEC_FinalizeContext(TEEC_Context *context);
*
*/
TEEC_Result TEEC_OpenSession(TEEC_Context *context,
- TEEC_Session * session,
- const TEEC_UUID * destination,
+ TEEC_Session *session,
+ const TEEC_UUID *destination,
uint32_t connectionMethod,
const void *connectionData,
- TEEC_Operation * operation,
+ TEEC_Operation *operation,
uint32_t *returnOrigin);
/**
@@ -129,7 +129,7 @@ void TEEC_CloseSession(TEEC_Session *session);
*/
TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
uint32_t commandID,
- TEEC_Operation * operation,
+ TEEC_Operation *operation,
uint32_t *returnOrigin);
/**
@@ -145,7 +145,7 @@ TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
* @return TEEC_Result Something failed.
*/
TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
- TEEC_SharedMemory * sharedMem);
+ TEEC_SharedMemory *sharedMem);
/**
* TEEC_AllocateSharedMemory() - Allocate shared memory for TEE.
@@ -159,7 +159,7 @@ TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
* @return TEEC_Result Something failed.
*/
TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
- TEEC_SharedMemory * sharedMem);
+ TEEC_SharedMemory *sharedMem);
/**
* TEEC_ReleaseSharedMemory() - Free or deregister the shared memory.
@@ -168,6 +168,7 @@ TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
*/
void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory);
+#if 0
/**
* TEEC_RequestCancellation() - Request the cancellation of a pending open
* session or command invocation.
@@ -175,6 +176,7 @@ void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory);
* @param operation Pointer to an operation previously passed to open session
* or invoke.
*/
-/* void TEEC_RequestCancellation(TEEC_Operation *operation); */
+void TEEC_RequestCancellation(TEEC_Operation *operation);
+#endif
#endif