summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorKaran Jhavar <kjhavar@nvidia.com>2012-06-05 16:23:35 -0700
committerVarun Wadekar <vwadekar@nvidia.com>2012-06-19 23:35:32 -0700
commite4539a4cb6f023d089c1676d7bcfe10c21976132 (patch)
treec9f390aaa66b7f55001a56ea5c79f35978317494 /security
parent386c5b21da6dc7b403084e0cb503f0876badd9d1 (diff)
security: tf_driver integrate TL's latest SDK
Update TL's SDK to ver 01.12. New SDK adds - 1) LP2 exit time optimization 2) L2 cache optimization - stop only, no flush 3) PL310 - set dynamic clock gate 4) Support for TEEE client api's for drivers bug 996822 Change-Id: Id46b7dd153ef05cffeed76558fa7a8c50cae5bd7 Signed-off-by: Karan Jhavar <kjhavar@nvidia.com> Reviewed-on: http://git-master/r/108025 (cherry picked from commit 3f2b434827ef9456b12dab23339de19afa1ff77c) Signed-off-by: Pritesh Raithatha <praithatha@nvidia.com> Change-Id: I44399a9c79dba6439858d1bcdf8cd8add1fb3a8b Reviewed-on: http://git-master/r/109535 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Karan Jhavar <kjhavar@nvidia.com> Reviewed-by: Varun Wadekar <vwadekar@nvidia.com>
Diffstat (limited to 'security')
-rw-r--r--security/tf_driver/Makefile1
-rw-r--r--security/tf_driver/s_version.h2
-rw-r--r--security/tf_driver/tee_client_api.h180
-rw-r--r--security/tf_driver/tee_client_api_ex.h60
-rw-r--r--security/tf_driver/tee_client_api_imp.h68
-rw-r--r--security/tf_driver/tf_device.c2
-rw-r--r--security/tf_driver/tf_teec.c619
-rw-r--r--security/tf_driver/tf_teec.h33
8 files changed, 963 insertions, 2 deletions
diff --git a/security/tf_driver/Makefile b/security/tf_driver/Makefile
index 5c48f626f5d8..a4fac547e10a 100644
--- a/security/tf_driver/Makefile
+++ b/security/tf_driver/Makefile
@@ -32,5 +32,6 @@ tf_driver-objs += tf_conn.o
tf_driver-objs += tf_device.o
tf_driver-objs += tf_comm.o
tf_driver-objs += tf_comm_tz.o
+tf_driver-objs += tf_teec.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += tf_driver.o
diff --git a/security/tf_driver/s_version.h b/security/tf_driver/s_version.h
index d812cdca75df..54596939d507 100644
--- a/security/tf_driver/s_version.h
+++ b/security/tf_driver/s_version.h
@@ -38,7 +38,7 @@
/*
* This version number must be updated for each new release
*/
-#define S_VERSION_MAIN "01.08"
+#define S_VERSION_MAIN "01.12"
/*
* If this is a patch or engineering version use the following
diff --git a/security/tf_driver/tee_client_api.h b/security/tf_driver/tee_client_api.h
new file mode 100644
index 000000000000..1dbbab1169c7
--- /dev/null
+++ b/security/tf_driver/tee_client_api.h
@@ -0,0 +1,180 @@
+/**
+ * Copyright (c) 2011 Trusted Logic S.A.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* This header file corresponds to V1.0 of the GlobalPlatform
+ * TEE Client API Specification
+ */
+#ifndef __TEE_CLIENT_API_H__
+#define __TEE_CLIENT_API_H__
+
+#include <linux/types.h>
+
+#ifndef TEEC_EXPORT
+#define TEEC_EXPORT
+#endif
+
+/* The header tee_client_api_imp.h must define implementation-dependent
+ * types, constants and macros.
+ *
+ * The implementation-dependent types are:
+ * - TEEC_Context_IMP
+ * - TEEC_Session_IMP
+ * - TEEC_SharedMemory_IMP
+ * - TEEC_Operation_IMP
+ *
+ * The implementation-dependent constants are:
+ * - TEEC_CONFIG_SHAREDMEM_MAX_SIZE
+ * The implementation-dependent macros are:
+ * - TEEC_PARAM_TYPES
+ */
+#include "tee_client_api_imp.h"
+
+/* Type definitions */
+typedef struct TEEC_Context {
+ TEEC_Context_IMP imp;
+} TEEC_Context;
+
+typedef struct TEEC_Session {
+ TEEC_Session_IMP imp;
+} TEEC_Session;
+
+typedef struct TEEC_SharedMemory {
+ void *buffer;
+ size_t size;
+ uint32_t flags;
+ TEEC_SharedMemory_IMP imp;
+} TEEC_SharedMemory;
+
+typedef struct {
+ void *buffer;
+ size_t size;
+} TEEC_TempMemoryReference;
+
+typedef struct {
+ TEEC_SharedMemory *parent;
+ size_t size;
+ size_t offset;
+} TEEC_RegisteredMemoryReference;
+
+typedef struct {
+ uint32_t a;
+ uint32_t b;
+} TEEC_Value;
+
+typedef union {
+ TEEC_TempMemoryReference tmpref;
+ TEEC_RegisteredMemoryReference memref;
+ TEEC_Value value;
+} TEEC_Parameter;
+
+typedef struct TEEC_Operation {
+ volatile uint32_t started;
+ uint32_t paramTypes;
+ TEEC_Parameter params[4];
+ TEEC_Operation_IMP imp;
+} TEEC_Operation;
+
+#define TEEC_SUCCESS ((TEEC_Result)0x00000000)
+#define TEEC_ERROR_GENERIC ((TEEC_Result)0xFFFF0000)
+#define TEEC_ERROR_ACCESS_DENIED ((TEEC_Result)0xFFFF0001)
+#define TEEC_ERROR_CANCEL ((TEEC_Result)0xFFFF0002)
+#define TEEC_ERROR_ACCESS_CONFLICT ((TEEC_Result)0xFFFF0003)
+#define TEEC_ERROR_EXCESS_DATA ((TEEC_Result)0xFFFF0004)
+#define TEEC_ERROR_BAD_FORMAT ((TEEC_Result)0xFFFF0005)
+#define TEEC_ERROR_BAD_PARAMETERS ((TEEC_Result)0xFFFF0006)
+#define TEEC_ERROR_BAD_STATE ((TEEC_Result)0xFFFF0007)
+#define TEEC_ERROR_ITEM_NOT_FOUND ((TEEC_Result)0xFFFF0008)
+#define TEEC_ERROR_NOT_IMPLEMENTED ((TEEC_Result)0xFFFF0009)
+#define TEEC_ERROR_NOT_SUPPORTED ((TEEC_Result)0xFFFF000A)
+#define TEEC_ERROR_NO_DATA ((TEEC_Result)0xFFFF000B)
+#define TEEC_ERROR_OUT_OF_MEMORY ((TEEC_Result)0xFFFF000C)
+#define TEEC_ERROR_BUSY ((TEEC_Result)0xFFFF000D)
+#define TEEC_ERROR_COMMUNICATION ((TEEC_Result)0xFFFF000E)
+#define TEEC_ERROR_SECURITY ((TEEC_Result)0xFFFF000F)
+#define TEEC_ERROR_SHORT_BUFFER ((TEEC_Result)0xFFFF0010)
+
+#define TEEC_ORIGIN_API 0x00000001
+#define TEEC_ORIGIN_COMMS 0x00000002
+#define TEEC_ORIGIN_TEE 0x00000003
+#define TEEC_ORIGIN_TRUSTED_APP 0x00000004
+
+#define TEEC_MEM_INPUT 0x00000001
+#define TEEC_MEM_OUTPUT 0x00000002
+
+#define TEEC_NONE 0x0
+#define TEEC_VALUE_INPUT 0x1
+#define TEEC_VALUE_OUTPUT 0x2
+#define TEEC_VALUE_INOUT 0x3
+#define TEEC_MEMREF_TEMP_INPUT 0x5
+#define TEEC_MEMREF_TEMP_OUTPUT 0x6
+#define TEEC_MEMREF_TEMP_INOUT 0x7
+#define TEEC_MEMREF_WHOLE 0xC
+#define TEEC_MEMREF_PARTIAL_INPUT 0xD
+#define TEEC_MEMREF_PARTIAL_OUTPUT 0xE
+#define TEEC_MEMREF_PARTIAL_INOUT 0xF
+
+#define TEEC_LOGIN_PUBLIC 0x00000000
+#define TEEC_LOGIN_USER 0x00000001
+#define TEEC_LOGIN_GROUP 0x00000002
+#define TEEC_LOGIN_APPLICATION 0x00000004
+#define TEEC_LOGIN_USER_APPLICATION 0x00000005
+#define TEEC_LOGIN_GROUP_APPLICATION 0x00000006
+
+TEEC_Result TEEC_EXPORT TEEC_InitializeContext(
+ const char *name,
+ TEEC_Context * context);
+
+void TEEC_EXPORT TEEC_FinalizeContext(
+ TEEC_Context * context);
+
+TEEC_Result TEEC_EXPORT TEEC_RegisterSharedMemory(
+ TEEC_Context * context,
+ TEEC_SharedMemory *sharedMem);
+
+TEEC_Result TEEC_EXPORT TEEC_AllocateSharedMemory(
+ TEEC_Context * context,
+ TEEC_SharedMemory *sharedMem);
+
+void TEEC_EXPORT TEEC_ReleaseSharedMemory(
+ TEEC_SharedMemory *sharedMem);
+
+TEEC_Result TEEC_EXPORT TEEC_OpenSession(
+ TEEC_Context * context,
+ TEEC_Session * session,
+ const TEEC_UUID * destination,
+ uint32_t connectionMethod,
+ void *connectionData,
+ TEEC_Operation * operation,
+ uint32_t *errorOrigin);
+
+void TEEC_EXPORT TEEC_CloseSession(
+ TEEC_Session * session);
+
+TEEC_Result TEEC_EXPORT TEEC_InvokeCommand(
+ TEEC_Session * session,
+ uint32_t commandID,
+ TEEC_Operation * operation,
+ uint32_t *errorOrigin);
+
+void TEEC_EXPORT TEEC_RequestCancellation(
+ TEEC_Operation * operation);
+
+#include "tee_client_api_ex.h"
+
+#endif /* __TEE_CLIENT_API_H__ */
diff --git a/security/tf_driver/tee_client_api_ex.h b/security/tf_driver/tee_client_api_ex.h
new file mode 100644
index 000000000000..3025308a818d
--- /dev/null
+++ b/security/tf_driver/tee_client_api_ex.h
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2011 Trusted Logic S.A.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This header file contains extensions to the TEE Client API that are
+ * specific to the Trusted Foundations implementations
+ */
+#ifndef __TEE_CLIENT_API_EX_H__
+#define __TEE_CLIENT_API_EX_H__
+
+#include <linux/types.h>
+
+/* Implementation-defined login types */
+#define TEEC_LOGIN_AUTHENTICATION 0x80000000
+#define TEEC_LOGIN_PRIVILEGED 0x80000002
+#define TEEC_LOGIN_PRIVILEGED_KERNEL 0x80000002
+
+/* Type definitions */
+
+typedef u64 TEEC_TimeLimit;
+
+void TEEC_EXPORT TEEC_GetTimeLimit(
+ TEEC_Context * context,
+ uint32_t timeout,
+ TEEC_TimeLimit *timeLimit);
+
+TEEC_Result TEEC_EXPORT TEEC_OpenSessionEx(
+ TEEC_Context * context,
+ TEEC_Session * session,
+ const TEEC_TimeLimit *timeLimit,
+ const TEEC_UUID * destination,
+ uint32_t connectionMethod,
+ void *connectionData,
+ TEEC_Operation * operation,
+ uint32_t *errorOrigin);
+
+TEEC_Result TEEC_EXPORT TEEC_InvokeCommandEx(
+ TEEC_Session * session,
+ const TEEC_TimeLimit *timeLimit,
+ uint32_t commandID,
+ TEEC_Operation * operation,
+ uint32_t *errorOrigin);
+
+#endif /* __TEE_CLIENT_API_EX_H__ */
diff --git a/security/tf_driver/tee_client_api_imp.h b/security/tf_driver/tee_client_api_imp.h
new file mode 100644
index 000000000000..e3053b301ad6
--- /dev/null
+++ b/security/tf_driver/tee_client_api_imp.h
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2011 Trusted Logic S.A.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This header file defines the implementation-dependent types,
+ * constants and macros for all the Trusted Foundations implementations
+ * of the TEE Client API
+ */
+#ifndef __TEE_CLIENT_API_IMP_H__
+#define __TEE_CLIENT_API_IMP_H__
+
+#include <linux/types.h>
+
+typedef u32 TEEC_Result;
+
+typedef struct TEEC_UUID {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_and_node[8];
+} TEEC_UUID;
+
+typedef struct {
+ struct tf_connection *_connection;
+} TEEC_Context_IMP;
+
+typedef struct {
+ struct TEEC_Context *_context;
+ u32 _client_session;
+} TEEC_Session_IMP;
+
+typedef struct {
+ struct TEEC_Context *_context;
+ u32 _block;
+ bool _allocated;
+} TEEC_SharedMemory_IMP;
+
+typedef struct {
+ struct TEEC_Session *_pSession;
+} TEEC_Operation_IMP;
+
+/* There is no natural, compile-time limit on the shared memory, but a specific
+ * implementation may introduce a limit (in particular on TrustZone)
+ */
+#define TEEC_CONFIG_SHAREDMEM_MAX_SIZE ((size_t)0xFFFFFFFF)
+
+#define TEEC_PARAM_TYPES(entry0Type, entry1Type, entry2Type, entry3Type) \
+ ((entry0Type) | ((entry1Type) << 4) | \
+ ((entry2Type) << 8) | ((entry3Type) << 12))
+
+
+#endif /* __TEE_CLIENT_API_IMP_H__ */
diff --git a/security/tf_driver/tf_device.c b/security/tf_driver/tf_device.c
index 8f31bf35f90a..74af4a642e55 100644
--- a/security/tf_driver/tf_device.c
+++ b/security/tf_driver/tf_device.c
@@ -393,7 +393,7 @@ static int __init tf_device_register(void)
}
#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS
- error = tf_self_test_post_init(&(g_tf_dev.kobj));
+ error = tf_self_test_post_init(&(dev_stats->kobj));
/* N.B. error > 0 indicates a POST failure, which will not
prevent the module from loading. */
if (error < 0) {
diff --git a/security/tf_driver/tf_teec.c b/security/tf_driver/tf_teec.c
new file mode 100644
index 000000000000..38240e2b25b9
--- /dev/null
+++ b/security/tf_driver/tf_teec.c
@@ -0,0 +1,619 @@
+/**
+ * Copyright (c) 2011 Trusted Logic S.A.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifdef CONFIG_TF_TEEC
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+
+#include "tf_protocol.h"
+#include "tf_defs.h"
+#include "tf_util.h"
+#include "tf_comm.h"
+#include "tf_conn.h"
+#include "tf_teec.h"
+
+#include "tee_client_api.h"
+
+#define TF_COMMAND_BYTES(cmd) \
+ (sizeof(cmd) - sizeof(struct tf_command_header))
+#define TF_COMMAND_SIZE(cmd) \
+ (TF_COMMAND_BYTES(cmd) / sizeof(u32))
+
+/* Associate TEEC errors to POSIX/Linux errors. The matching is somewhat
+ arbitrary but one-to-one for supported error codes. */
+int TEEC_decode_error(TEEC_Result ret)
+{
+ switch (ret) {
+ case TEEC_SUCCESS: return 0;
+ case TEEC_ERROR_GENERIC: return -EIO;
+ case TEEC_ERROR_ACCESS_DENIED: return -EPERM;
+ case TEEC_ERROR_CANCEL: return -ECANCELED;
+ case TEEC_ERROR_ACCESS_CONFLICT: return -EBUSY;
+ case TEEC_ERROR_EXCESS_DATA: return -E2BIG;
+ case TEEC_ERROR_BAD_FORMAT: return -EDOM;
+ case TEEC_ERROR_BAD_PARAMETERS: return -EINVAL;
+ case TEEC_ERROR_BAD_STATE: return -EBADFD;
+ case TEEC_ERROR_ITEM_NOT_FOUND: return -ENOENT;
+ case TEEC_ERROR_NOT_IMPLEMENTED: return -EPROTONOSUPPORT;
+ case TEEC_ERROR_NOT_SUPPORTED: return -ENOSYS;
+ case TEEC_ERROR_NO_DATA: return -ENODATA;
+ case TEEC_ERROR_OUT_OF_MEMORY: return -ENOMEM;
+ case TEEC_ERROR_BUSY: return -EAGAIN;
+ case TEEC_ERROR_COMMUNICATION: return -EPIPE;
+ case TEEC_ERROR_SECURITY: return -ECONNABORTED;
+ case TEEC_ERROR_SHORT_BUFFER: return -EFBIG;
+ default: return -EIO;
+ }
+}
+EXPORT_SYMBOL(TEEC_decode_error);
+
+/* Associate POSIX/Linux errors to TEEC errors. The matching is somewhat
+ arbitrary, but TEEC_encode_error(TEEC_decode_error(x))==x for supported
+ error codes. */
+TEEC_Result TEEC_encode_error(int err)
+{
+ if (err >= 0)
+ return S_SUCCESS;
+
+ switch (err) {
+ case 0: return TEEC_SUCCESS;
+ case -EIO: return TEEC_ERROR_GENERIC;
+ case -EPERM: return TEEC_ERROR_ACCESS_DENIED;
+ case -ECANCELED: return TEEC_ERROR_CANCEL;
+ case -EBUSY: return TEEC_ERROR_ACCESS_CONFLICT;
+ case -E2BIG: return TEEC_ERROR_EXCESS_DATA;
+ case -EDOM: return TEEC_ERROR_BAD_FORMAT;
+ case -EINVAL: return TEEC_ERROR_BAD_PARAMETERS;
+ case -EBADFD: return TEEC_ERROR_BAD_STATE;
+ case -ENOENT: return TEEC_ERROR_ITEM_NOT_FOUND;
+ case -EPROTONOSUPPORT: return TEEC_ERROR_NOT_IMPLEMENTED;
+ case -ENOSYS: return TEEC_ERROR_NOT_SUPPORTED;
+ case -ENODATA: return TEEC_ERROR_NO_DATA;
+ case -ENOMEM: return TEEC_ERROR_OUT_OF_MEMORY;
+ case -EAGAIN: return TEEC_ERROR_BUSY;
+ case -EPIPE: return TEEC_ERROR_COMMUNICATION;
+ case -ECONNABORTED: return TEEC_ERROR_SECURITY;
+ case -EFBIG: return TEEC_ERROR_SHORT_BUFFER;
+ default: return TEEC_ERROR_GENERIC;
+ }
+}
+EXPORT_SYMBOL(TEEC_encode_error);
+
+/* Encode a TEEC time limit into an SChannel time limit. */
+static u64 TEEC_encode_timeout(const TEEC_TimeLimit *timeLimit)
+{
+ if (timeLimit == NULL)
+ return (u64)-1;
+ else
+ return *timeLimit;
+}
+
+/* Convert a timeout into a time limit in our internal format. */
+void TEEC_GetTimeLimit(TEEC_Context *sContext,
+ uint32_t nTimeout, /*ms from now*/
+ TEEC_TimeLimit *sTimeLimit)
+{
+ /*Use the kernel time as the TEE time*/
+ struct timeval now;
+ do_gettimeofday(&now);
+ *sTimeLimit =
+ ((TEEC_TimeLimit)now.tv_sec * 1000 +
+ now.tv_usec / 1000 +
+ nTimeout);
+}
+EXPORT_SYMBOL(TEEC_GetTimeLimit);
+
+#define TF_PARAM_TYPE_INPUT_FLAG 0x1
+#define TF_PARAM_TYPE_OUTPUT_FLAG 0x2
+#define TF_PARAM_TYPE_MEMREF_FLAG 0x4
+#define TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG 0x8
+
+/* Update the type of a whole memref with the direction deduced from
+ the INPUT and OUTPUT flags of the memref. */
+static void TEEC_encode_whole_memref_flags(u16 *param_types,
+ unsigned i,
+ u32 flags)
+{
+ if (flags & TEEC_MEM_INPUT)
+ *param_types |= TF_PARAM_TYPE_INPUT_FLAG << (4*i);
+ if (flags & TEEC_MEM_OUTPUT)
+ *param_types |= TF_PARAM_TYPE_OUTPUT_FLAG << (4*i);
+}
+
+/* Encode the parameters and type of an operation from the TEE API format
+ into an SChannel message. */
+void TEEC_encode_parameters(u16 *param_types,
+ union tf_command_param *params,
+ TEEC_Operation *operation)
+{
+ unsigned i;
+ if (operation == NULL) {
+ *param_types = 0;
+ return;
+ }
+ *param_types = operation->paramTypes;
+ for (i = 0; i < 4; i++) {
+ unsigned ty = TF_GET_PARAM_TYPE(operation->paramTypes, i);
+ TEEC_Parameter *op = operation->params + i;
+ if (ty & TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG) {
+ TEEC_SharedMemory *sm = op->memref.parent;
+ params[i].memref.block = sm->imp._block;
+ if (ty == TEEC_MEMREF_WHOLE) {
+ TEEC_encode_whole_memref_flags(param_types, i,
+ sm->flags);
+ params[i].memref.size = sm->size;
+ params[i].memref.offset = 0;
+ } else {
+ params[i].memref.size = op->memref.size;
+ params[i].memref.offset = op->memref.offset;
+ }
+ } else if (ty & TF_PARAM_TYPE_MEMREF_FLAG) {
+ /* Set up what tf_map_temp_shmem (called by
+ tf_open_client_session and
+ tf_invoke_client_command) expects:
+ .descriptor and .offset to both be set to the
+ address of the buffer. */
+ u32 address = (u32)op->tmpref.buffer;
+ params[i].temp_memref.descriptor = address;
+ params[i].temp_memref.size = op->tmpref.size;
+ params[i].temp_memref.offset = address;
+ } else if (ty & TF_PARAM_TYPE_INPUT_FLAG) {
+ params[i].value.a = op->value.a;
+ params[i].value.b = op->value.b;
+ } else {
+ /* output-only value or none, so nothing to do */
+ }
+ }
+}
+
+/* Decode updated parameters from an SChannel answer into the TEE API format. */
+void TEEC_decode_parameters(union tf_answer_param *params,
+ TEEC_Operation *operation)
+{
+ unsigned i;
+
+ if (operation == NULL)
+ return;
+
+ for (i = 0; i < 4; i++) {
+ unsigned ty = TF_GET_PARAM_TYPE(operation->paramTypes, i);
+ TEEC_Parameter *op = operation->params + i;
+ if (!(ty & TF_PARAM_TYPE_OUTPUT_FLAG)) {
+ /* input-only or none, so nothing to do */
+ } else if (ty & TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG) {
+ op->memref.size = params[i].size.size;
+ } else if (ty & TF_PARAM_TYPE_MEMREF_FLAG) {
+ op->tmpref.size = params[i].size.size;
+ } else {
+ op->value.a = params[i].value.a;
+ op->value.b = params[i].value.b;
+ }
+ }
+}
+
+/* Start a potentially-cancellable operation. */
+void TEEC_start_operation(TEEC_Context *context,
+ TEEC_Session *session,
+ TEEC_Operation *operation)
+{
+ if (operation != NULL) {
+ operation->imp._pSession = session;
+ /* Flush the assignment to imp._pSession, so that
+ RequestCancellation can read that field if started==1. */
+ barrier();
+ operation->started = 1;
+ }
+}
+
+/* Mark a potentially-cancellable operation as finished. */
+void TEEC_finish_operation(TEEC_Operation *operation)
+{
+ if (operation != NULL) {
+ operation->started = 2;
+ barrier();
+ }
+}
+
+
+
+TEEC_Result TEEC_InitializeContext(const char *name,
+ TEEC_Context *context)
+{
+ int error;
+ struct tf_connection *connection = NULL;
+
+ error = tf_open(tf_get_device(), NULL, &connection);
+ if (error != 0) {
+ dprintk(KERN_ERR "TEEC_InitializeContext(%s): "
+ "tf_open failed (error %d)!\n",
+ (name == NULL ? "(null)" : name), error);
+ goto error;
+ }
+ BUG_ON(connection == NULL);
+ connection->owner = TF_CONNECTION_OWNER_KERNEL;
+
+ error = tf_create_device_context(connection);
+ if (error != 0) {
+ dprintk(KERN_ERR "TEEC_InitializeContext(%s): "
+ "tf_create_device_context failed (error %d)!\n",
+ (name == NULL ? "(null)" : name), error);
+ goto error;
+ }
+
+ context->imp._connection = connection;
+ /*spin_lock_init(&context->imp._operations_lock);*/
+ return S_SUCCESS;
+
+error:
+ tf_close(connection);
+ return TEEC_encode_error(error);
+}
+EXPORT_SYMBOL(TEEC_InitializeContext);
+
+void TEEC_FinalizeContext(TEEC_Context *context)
+{
+ struct tf_connection *connection = context->imp._connection;
+ dprintk(KERN_DEBUG "TEEC_FinalizeContext: connection=%p", connection);
+ tf_close(connection);
+ context->imp._connection = NULL;
+}
+EXPORT_SYMBOL(TEEC_FinalizeContext);
+
+TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
+ TEEC_SharedMemory *sharedMem)
+{
+ union tf_command command_message = { { 0, } };
+ struct tf_command_register_shared_memory *cmd =
+ &command_message.register_shared_memory;
+ union tf_answer answer_message;
+ struct tf_answer_register_shared_memory *ans =
+ &answer_message.register_shared_memory;
+ TEEC_Result ret;
+ memset(&sharedMem->imp, 0, sizeof(sharedMem->imp));
+
+ cmd->message_size = TF_COMMAND_SIZE(*cmd);
+ cmd->message_type = TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY;
+ cmd->memory_flags = sharedMem->flags;
+ cmd->operation_id = (u32)&answer_message;
+ cmd->device_context = (u32)context;
+ /*cmd->block_id will be set by tf_register_shared_memory*/
+ cmd->shared_mem_size = sharedMem->size;
+ cmd->shared_mem_start_offset = 0;
+ cmd->shared_mem_descriptors[0] = (u32)sharedMem->buffer;
+
+ ret = TEEC_encode_error(
+ tf_register_shared_memory(context->imp._connection,
+ &command_message,
+ &answer_message));
+ if (ret == TEEC_SUCCESS)
+ ret = ans->error_code;
+
+ if (ret == S_SUCCESS) {
+ sharedMem->imp._context = context;
+ sharedMem->imp._block = ans->block;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(TEEC_RegisterSharedMemory);
+
+#define TEEC_POINTER_TO_ZERO_SIZED_BUFFER ((void *)0x010)
+
+TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
+ TEEC_SharedMemory *sharedMem)
+{
+ TEEC_Result ret;
+ dprintk(KERN_DEBUG "TEEC_AllocateSharedMemory: requested=%lu",
+ (unsigned long)sharedMem->size);
+ if (sharedMem->size == 0) {
+ /* Allocating 0 bytes must return a non-NULL pointer, but the
+ pointer doesn't need to be to memory that is mapped
+ anywhere. So we return a pointer into an unmapped page. */
+ sharedMem->buffer = TEEC_POINTER_TO_ZERO_SIZED_BUFFER;
+ } else {
+ sharedMem->buffer = internal_vmalloc(sharedMem->size);
+ if (sharedMem->buffer == NULL) {
+ dprintk(KERN_INFO "TEEC_AllocateSharedMemory: could "
+ "not allocate %lu bytes",
+ (unsigned long)sharedMem->size);
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ ret = TEEC_RegisterSharedMemory(context, sharedMem);
+ if (ret == TEEC_SUCCESS) {
+ sharedMem->imp._allocated = 1;
+ } else {
+ internal_vfree(sharedMem->buffer);
+ sharedMem->buffer = NULL;
+ memset(&sharedMem->imp, 0, sizeof(sharedMem->imp));
+ }
+ return ret;
+}
+EXPORT_SYMBOL(TEEC_AllocateSharedMemory);
+
+void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMem)
+{
+ TEEC_Context *context = sharedMem->imp._context;
+ union tf_command command_message = { { 0, } };
+ struct tf_command_release_shared_memory *cmd =
+ &command_message.release_shared_memory;
+ union tf_answer answer_message;
+
+ cmd->message_size = TF_COMMAND_SIZE(*cmd);
+ cmd->message_type = TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY;
+ cmd->operation_id = (u32)&answer_message;
+ cmd->device_context = (u32)context;
+ cmd->block = sharedMem->imp._block;
+
+ tf_release_shared_memory(context->imp._connection,
+ &command_message,
+ &answer_message);
+ if (sharedMem->imp._allocated) {
+ if (sharedMem->buffer != TEEC_POINTER_TO_ZERO_SIZED_BUFFER)
+ internal_vfree(sharedMem->buffer);
+
+ sharedMem->buffer = NULL;
+ sharedMem->size = 0;
+ }
+ memset(&sharedMem->imp, 0, sizeof(sharedMem->imp));
+}
+EXPORT_SYMBOL(TEEC_ReleaseSharedMemory);
+
+TEEC_Result TEEC_OpenSessionEx(TEEC_Context *context,
+ TEEC_Session *session,
+ const TEEC_TimeLimit *timeLimit,
+ const TEEC_UUID * destination,
+ u32 connectionMethod,
+ void *connectionData,
+ TEEC_Operation *operation,
+ u32 *errorOrigin)
+{
+ union tf_command command_message = { { 0, } };
+ struct tf_command_open_client_session *cmd =
+ &command_message.open_client_session;
+ union tf_answer answer_message = { { 0, } };
+ struct tf_answer_open_client_session *ans =
+ &answer_message.open_client_session;
+ TEEC_Result ret;
+
+ /* Note that we set the message size to the whole size of the
+ structure. tf_open_client_session will adjust it down
+ to trim the unnecessary portion of the login_data field. */
+ cmd->message_size = TF_COMMAND_SIZE(*cmd);
+ cmd->message_type = TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION;
+ cmd->operation_id = (u32)&answer_message;
+ cmd->device_context = (u32)context;
+ cmd->cancellation_id = (u32)operation;
+ cmd->timeout = TEEC_encode_timeout(timeLimit);
+ memcpy(&cmd->destination_uuid, destination,
+ sizeof(cmd->destination_uuid));
+ cmd->login_type = connectionMethod;
+ TEEC_encode_parameters(&cmd->param_types, cmd->params, operation);
+
+ switch (connectionMethod) {
+ case TEEC_LOGIN_PRIVILEGED:
+ case TEEC_LOGIN_PUBLIC:
+ break;
+ case TEEC_LOGIN_APPLICATION:
+ case TEEC_LOGIN_USER:
+ case TEEC_LOGIN_USER_APPLICATION:
+ case TEEC_LOGIN_GROUP:
+ case TEEC_LOGIN_GROUP_APPLICATION:
+ default:
+ return TEEC_ERROR_NOT_IMPLEMENTED;
+ }
+
+ TEEC_start_operation(context, session, operation);
+
+ ret = TEEC_encode_error(
+ tf_open_client_session(context->imp._connection,
+ &command_message,
+ &answer_message));
+
+ TEEC_finish_operation(operation);
+ TEEC_decode_parameters(ans->answers, operation);
+ if (errorOrigin != NULL) {
+ *errorOrigin = (ret == TEEC_SUCCESS ?
+ ans->error_origin :
+ TEEC_ORIGIN_COMMS);
+ }
+
+ if (ret == TEEC_SUCCESS)
+ ret = ans->error_code;
+
+ if (ret == S_SUCCESS) {
+ session->imp._client_session = ans->client_session;
+ session->imp._context = context;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(TEEC_OpenSessionEx);
+
+TEEC_Result TEEC_OpenSession(TEEC_Context *context,
+ TEEC_Session *session,
+ const TEEC_UUID * destination,
+ u32 connectionMethod,
+ void *connectionData,
+ TEEC_Operation *operation,
+ u32 *errorOrigin)
+{
+ return TEEC_OpenSessionEx(context, session,
+ NULL, /*timeLimit*/
+ destination,
+ connectionMethod, connectionData,
+ operation, errorOrigin);
+}
+EXPORT_SYMBOL(TEEC_OpenSession);
+
+void TEEC_CloseSession(TEEC_Session *session)
+{
+ if (session != NULL) {
+ TEEC_Context *context = session->imp._context;
+ union tf_command command_message = { { 0, } };
+ struct tf_command_close_client_session *cmd =
+ &command_message.close_client_session;
+ union tf_answer answer_message;
+
+ cmd->message_size = TF_COMMAND_SIZE(*cmd);
+ cmd->message_type = TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION;
+ cmd->operation_id = (u32)&answer_message;
+ cmd->device_context = (u32)context;
+ cmd->client_session = session->imp._client_session;
+
+ tf_close_client_session(context->imp._connection,
+ &command_message,
+ &answer_message);
+
+ session->imp._client_session = 0;
+ session->imp._context = NULL;
+ }
+}
+EXPORT_SYMBOL(TEEC_CloseSession);
+
+TEEC_Result TEEC_InvokeCommandEx(TEEC_Session *session,
+ const TEEC_TimeLimit *timeLimit,
+ u32 commandID,
+ TEEC_Operation *operation,
+ u32 *errorOrigin)
+{
+ TEEC_Context *context = session->imp._context;
+ union tf_command command_message = { { 0, } };
+ struct tf_command_invoke_client_command *cmd =
+ &command_message.invoke_client_command;
+ union tf_answer answer_message = { { 0, } };
+ struct tf_answer_invoke_client_command *ans =
+ &answer_message.invoke_client_command;
+ TEEC_Result ret;
+
+ cmd->message_size = TF_COMMAND_SIZE(*cmd);
+ cmd->message_type = TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND;
+ cmd->operation_id = (u32)&answer_message;
+ cmd->device_context = (u32)context;
+ cmd->client_session = session->imp._client_session;
+ cmd->timeout = TEEC_encode_timeout(timeLimit);
+ cmd->cancellation_id = (u32)operation;
+ cmd->client_command_identifier = commandID;
+ TEEC_encode_parameters(&cmd->param_types, cmd->params, operation);
+
+ TEEC_start_operation(context, session, operation);
+
+ ret = TEEC_encode_error(
+ tf_invoke_client_command(context->imp._connection,
+ &command_message,
+ &answer_message));
+
+ TEEC_finish_operation(operation);
+ TEEC_decode_parameters(ans->answers, operation);
+ if (errorOrigin != NULL) {
+ *errorOrigin = (ret == TEEC_SUCCESS ?
+ ans->error_origin :
+ TEEC_ORIGIN_COMMS);
+ }
+
+ if (ret == TEEC_SUCCESS)
+ ret = ans->error_code;
+ return ret;
+}
+EXPORT_SYMBOL(TEEC_InvokeCommandEx);
+
+TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
+ u32 commandID,
+ TEEC_Operation *operation,
+ u32 *errorOrigin)
+{
+ return TEEC_InvokeCommandEx(session,
+ NULL, /*timeLimit*/
+ commandID,
+ operation, errorOrigin);
+}
+EXPORT_SYMBOL(TEEC_InvokeCommand);
+
+TEEC_Result TEEC_send_cancellation_message(TEEC_Context *context,
+ u32 client_session,
+ u32 cancellation_id)
+{
+ union tf_command command_message = { { 0, } };
+ struct tf_command_cancel_client_operation *cmd =
+ &command_message.cancel_client_operation;
+ union tf_answer answer_message = { { 0, } };
+ struct tf_answer_cancel_client_operation *ans =
+ &answer_message.cancel_client_operation;
+ TEEC_Result ret;
+
+ cmd->message_size = TF_COMMAND_SIZE(*cmd);
+ cmd->message_type = TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND;
+ cmd->operation_id = (u32)&answer_message;
+ cmd->device_context = (u32)context;
+ cmd->client_session = client_session;
+ cmd->cancellation_id = cancellation_id;
+
+ ret = TEEC_encode_error(
+ tf_cancel_client_command(context->imp._connection,
+ &command_message,
+ &answer_message));
+
+ if (ret == TEEC_SUCCESS)
+ ret = ans->error_code;
+ return ret;
+}
+
+void TEEC_RequestCancellation(TEEC_Operation *operation)
+{
+ TEEC_Result ret;
+ while (1) {
+ u32 state = operation->started;
+ switch (state) {
+ case 0: /*The operation data structure isn't initialized yet*/
+ break;
+
+ case 1: /*operation is in progress in the client*/
+ ret = TEEC_send_cancellation_message(
+ operation->imp._pSession->imp._context,
+ operation->imp._pSession->imp._client_session,
+ (u32)operation);
+ if (ret == TEEC_SUCCESS) {
+ /*The cancellation was successful*/
+ return;
+ }
+ /* The command has either not reached the secure world
+ yet or has completed already. Either way, retry. */
+ break;
+
+ case 2: /*operation has completed already*/
+ return;
+ }
+ /* Since we're busy-waiting for the operation to be started
+ or finished, yield. */
+ schedule();
+ }
+}
+EXPORT_SYMBOL(TEEC_RequestCancellation);
+
+#endif /* defined(CONFIG_TF_TEEC) */
diff --git a/security/tf_driver/tf_teec.h b/security/tf_driver/tf_teec.h
new file mode 100644
index 000000000000..28b32878f800
--- /dev/null
+++ b/security/tf_driver/tf_teec.h
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2011 Trusted Logic S.A.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __TF_TEEC_H__
+#define __TF_TEEC_H__
+
+#ifdef CONFIG_TF_TEEC
+
+#include "tf_defs.h"
+#include "tee_client_api.h"
+
+TEEC_Result TEEC_encode_error(int err);
+int TEEC_decode_error(TEEC_Result ret);
+
+#endif /* defined(CONFIG_TF_TEEC) */
+
+#endif /* !defined(__TF_TEEC_H__) */