From e4539a4cb6f023d089c1676d7bcfe10c21976132 Mon Sep 17 00:00:00 2001 From: Karan Jhavar Date: Tue, 5 Jun 2012 16:23:35 -0700 Subject: 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 Reviewed-on: http://git-master/r/108025 (cherry picked from commit 3f2b434827ef9456b12dab23339de19afa1ff77c) Signed-off-by: Pritesh Raithatha Change-Id: I44399a9c79dba6439858d1bcdf8cd8add1fb3a8b Reviewed-on: http://git-master/r/109535 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Karan Jhavar Reviewed-by: Varun Wadekar --- security/tf_driver/Makefile | 1 + security/tf_driver/s_version.h | 2 +- security/tf_driver/tee_client_api.h | 180 ++++++++++ security/tf_driver/tee_client_api_ex.h | 60 ++++ security/tf_driver/tee_client_api_imp.h | 68 ++++ security/tf_driver/tf_device.c | 2 +- security/tf_driver/tf_teec.c | 619 ++++++++++++++++++++++++++++++++ security/tf_driver/tf_teec.h | 33 ++ 8 files changed, 963 insertions(+), 2 deletions(-) create mode 100644 security/tf_driver/tee_client_api.h create mode 100644 security/tf_driver/tee_client_api_ex.h create mode 100644 security/tf_driver/tee_client_api_imp.h create mode 100644 security/tf_driver/tf_teec.c create mode 100644 security/tf_driver/tf_teec.h (limited to 'security') 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 + +#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 + +/* 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 + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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__) */ -- cgit v1.2.3