security: tf_driver integrate TL's latest SDK
Karan Jhavar [Tue, 5 Jun 2012 23:23:35 +0000 (16:23 -0700)]
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>

Rebase-Id: Rce02b64cbc12267dc9cb9f9534ac6b21015d0e78

security/tf_driver/Makefile
security/tf_driver/s_version.h
security/tf_driver/tee_client_api.h [new file with mode: 0644]
security/tf_driver/tee_client_api_ex.h [new file with mode: 0644]
security/tf_driver/tee_client_api_imp.h [new file with mode: 0644]
security/tf_driver/tf_device.c
security/tf_driver/tf_teec.c [new file with mode: 0644]
security/tf_driver/tf_teec.h [new file with mode: 0644]

index 5c48f62..a4fac54 100644 (file)
@@ -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
index d812cdc..5459693 100644 (file)
@@ -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 (file)
index 0000000..1dbbab1
--- /dev/null
@@ -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 (file)
index 0000000..3025308
--- /dev/null
@@ -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 (file)
index 0000000..e3053b3
--- /dev/null
@@ -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__ */
index 8f31bf3..74af4a6 100644 (file)
@@ -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 (file)
index 0000000..38240e2
--- /dev/null
@@ -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 (file)
index 0000000..28b3287
--- /dev/null
@@ -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__) */