diff options
Diffstat (limited to 'mobicore/MobiCoreDriverLib/ClientLib/GP/tee_client_api.cpp')
-rw-r--r-- | mobicore/MobiCoreDriverLib/ClientLib/GP/tee_client_api.cpp | 848 |
1 files changed, 848 insertions, 0 deletions
diff --git a/mobicore/MobiCoreDriverLib/ClientLib/GP/tee_client_api.cpp b/mobicore/MobiCoreDriverLib/ClientLib/GP/tee_client_api.cpp new file mode 100644 index 0000000..45c5adf --- /dev/null +++ b/mobicore/MobiCoreDriverLib/ClientLib/GP/tee_client_api.cpp @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2013-2014 TRUSTONIC LIMITED + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the TRUSTONIC LIMITED nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#undef LOG_TAG +#define LOG_TAG "GpClient" +#include "tee_client_api.h" +#include "log.h" +#include "MobiCoreDriverApi.h" +#include "Mci/mcinq.h" +#include <sys/mman.h> +#include "GpTci.h" +#include "../Session.h" + +//------------------------------------------------------------------------------ +// Macros +#define _TEEC_GET_PARAM_TYPE(t, i) (((t) >> (4*i)) & 0xF) + +//Parameter number +#define _TEEC_PARAMETER_NUMBER 4 + + +//------------------------------------------------------------------------------ +//Local satic functions +static void _libUuidToArray( + const TEEC_UUID *uuid, + uint8_t *uuid_str); + + +static TEEC_Result _TEEC_UnwindOperation( + _TEEC_TCI *tci, + mcSessionHandle_t *handle, + TEEC_Operation *operation, + bool copyValues, + uint32_t *returnOrigin); + +static TEEC_Result _TEEC_SetupOperation( + _TEEC_TCI *tci, + mcSessionHandle_t *handle, + TEEC_Operation *operation, + uint32_t *returnOrigin); + +//------------------------------------------------------------------------------ +static void _libUuidToArray( + const TEEC_UUID *uuid, + uint8_t *uuidArr) +{ + uint8_t *pIdentifierCursor = (uint8_t *)uuid; + /* offsets and syntax constants. See explanations above */ +#ifdef S_BIG_ENDIAN + uint32_t offsets = 0; +#else + uint32_t offsets = 0xF1F1DF13; +#endif + uint32_t i; + + for (i = 0; i < sizeof(TEEC_UUID); i++) { + /* Two-digit hex number */ + uint8_t number; + int32_t offset = ((int32_t)((offsets & 0xF) << 28)) >> 28; + number = pIdentifierCursor[offset]; + offsets >>= 4; + pIdentifierCursor++; + + uuidArr[i] = number; + } +} + +//------------------------------------------------------------------------------ +static TEEC_Result _TEEC_SetupOperation( + _TEEC_TCI *tci, + mcSessionHandle_t *handle, + TEEC_Operation *operation, + uint32_t *returnOrigin) +{ + uint32_t i; + _TEEC_ParameterInternal *imp; + TEEC_Parameter *ext; + mcResult_t mcRet = MC_DRV_OK; + TEEC_Result teecResult = TEEC_SUCCESS; + + LOG_I(" %s()", __func__); + + tci->operation.isCancelled = false; + tci->operation.paramTypes = 0; + + //operation can be NULL + if (operation != NULL) { + + operation->started = 1; + + //This design allows a non-NULL buffer with a size of 0 bytes to allow trivial integration with any + //implementations of the C library malloc, in which is valid to allocate a zero byte buffer and receive a non- + //NULL pointer which may not be de-referenced in return. + + for (i = 0; i < _TEEC_PARAMETER_NUMBER; i++) { + uint8_t paramType = _TEEC_GET_PARAM_TYPE(operation->paramTypes, i); + + imp = &tci->operation.params[i]; + ext = &operation->params[i]; + + switch (paramType) { + case TEEC_VALUE_OUTPUT: + LOG_I(" cycle %d, TEEC_VALUE_OUTPUT", i); + break; + case TEEC_NONE: + LOG_I(" cycle %d, TEEC_NONE", i); + break; + case TEEC_VALUE_INPUT: + case TEEC_VALUE_INOUT: { + LOG_I(" cycle %d, TEEC_VALUE_IN*", i); + imp->value.a = ext->value.a; + imp->value.b = ext->value.b; + break; + } + case TEEC_MEMREF_TEMP_INPUT: + case TEEC_MEMREF_TEMP_OUTPUT: + case TEEC_MEMREF_TEMP_INOUT: { + //TODO: A Temporary Memory Reference may be null, which can be used to denote a special case for the + //parameter. Output Memory References that are null are typically used to request the required output size. + LOG_I(" cycle %d, TEEC_TEMP_IN*", i); + imp->memref.mapInfo.sVirtualLen = 0; + if ((ext->tmpref.size) && (ext->tmpref.buffer)) { + mcRet = mcMap(handle, ext->tmpref.buffer, ext->tmpref.size, &imp->memref.mapInfo); + if (mcRet != MC_DRV_OK) { + LOG_E("mcMap failed, mcRet=0x%08X", mcRet); + *returnOrigin = TEEC_ORIGIN_COMMS; + i = _TEEC_PARAMETER_NUMBER; + } + } else { + LOG_I(" cycle %d, TEEC_TEMP_IN* - zero pointer or size", i); + } + break; + } + case TEEC_MEMREF_WHOLE: { + LOG_I(" cycle %d, TEEC_MEMREF_WHOLE", i); + imp->memref.mapInfo.sVirtualLen = 0; + if (ext->memref.parent->size) { + mcRet = mcMap(handle, ext->memref.parent->buffer, ext->memref.parent->size, &imp->memref.mapInfo); + if (mcRet != MC_DRV_OK) { + LOG_E("mcMap failed, mcRet=0x%08X", mcRet); + *returnOrigin = TEEC_ORIGIN_COMMS; + i = _TEEC_PARAMETER_NUMBER; + } + } + /* We don't transmit that the mem ref is the whole shared mem */ + /* Magic number 4 means that it is a mem ref */ + paramType = ext->memref.parent->flags | 4; + break; + } + case TEEC_MEMREF_PARTIAL_INPUT: + case TEEC_MEMREF_PARTIAL_OUTPUT: + case TEEC_MEMREF_PARTIAL_INOUT: { + LOG_I(" cycle %d, TEEC_PARTIAL_IN*", i); + //Check data flow consistency + if ((((ext->memref.parent->flags & (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)) == TEEC_MEM_INPUT) && + (paramType == TEEC_MEMREF_PARTIAL_OUTPUT)) || + (((ext->memref.parent->flags & (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)) == TEEC_MEM_OUTPUT) && + (paramType == TEEC_MEMREF_PARTIAL_INPUT))) { + LOG_E("PARTIAL data flow inconsistency"); + *returnOrigin = TEEC_ORIGIN_API; + teecResult = TEEC_ERROR_BAD_PARAMETERS; + i = _TEEC_PARAMETER_NUMBER; + break; + } + /* We don't transmit that the mem ref is partial */ + paramType &= TEEC_MEMREF_TEMP_INOUT; + + if (ext->memref.offset + ext->memref.size > ext->memref.parent->size) { + LOG_E("PARTIAL offset/size error"); + *returnOrigin = TEEC_ORIGIN_API; + teecResult = TEEC_ERROR_BAD_PARAMETERS; + i = _TEEC_PARAMETER_NUMBER; + break; + } + imp->memref.mapInfo.sVirtualLen = 0; + if (ext->memref.size) { + mcRet = mcMap(handle, (uint8_t *)ext->memref.parent->buffer + ext->memref.offset, ext->memref.size, &imp->memref.mapInfo); + if (mcRet != MC_DRV_OK) { + LOG_E("mcMap failed, mcRet=0x%08X", mcRet); + *returnOrigin = TEEC_ORIGIN_COMMS; + i = _TEEC_PARAMETER_NUMBER; + } + } + break; + } + default: + LOG_E("cycle %d, default", i); + *returnOrigin = TEEC_ORIGIN_API; + teecResult = TEEC_ERROR_BAD_PARAMETERS; + i = _TEEC_PARAMETER_NUMBER; + break; + } + tci->operation.paramTypes |= (paramType<<i*4); + } + + if (tci->operation.isCancelled) { + LOG_E("the operation has been cancelled in COMMS"); + *returnOrigin = TEEC_ORIGIN_COMMS; + teecResult = TEEC_ERROR_CANCEL; + } + + if ((mcRet != MC_DRV_OK) || (teecResult != TEEC_SUCCESS)) { + uint32_t retOrigIgnored; + _TEEC_UnwindOperation(tci, handle, operation, false, &retOrigIgnored); + //Zeroing out tci->operation + memset(&tci->operation, 0, sizeof(tci->operation)); + if (teecResult != TEEC_SUCCESS) return teecResult; + return TEEC_ERROR_GENERIC; + } + } + + //Copy version indicator field + memcpy(tci->header, "TCIGP000", sizeof(tci->header)); + + // Fill in invalid values for secure world to overwrite + tci->returnStatus = TEEC_ERROR_BAD_STATE; + + // Signal completion of request writing + tci->ready = 1; + + return teecResult; +} + +//------------------------------------------------------------------------------ +static TEEC_Result _TEEC_UnwindOperation( + _TEEC_TCI *tci, + mcSessionHandle_t *handle, + TEEC_Operation *operation, + bool copyValues, + uint32_t *returnOrigin) +{ + uint32_t i; + _TEEC_ParameterInternal *imp; + TEEC_Parameter *ext; + uint8_t *buffer; + + //operation can be NULL + if (operation == NULL) return TEEC_SUCCESS; + + LOG_I(" %s()", __func__); + + operation->started = 2; + + // Some sanity checks + if (tci->returnOrigin == 0 || + ((tci->returnOrigin != TEEC_ORIGIN_TRUSTED_APP) && (tci->returnStatus != TEEC_SUCCESS))) { + *returnOrigin = TEEC_ORIGIN_COMMS; + return TEEC_ERROR_COMMUNICATION; + } + *returnOrigin = tci->returnOrigin; + + //Clear sVirtualLen to unMap further + for (i = 0; i < _TEEC_PARAMETER_NUMBER; i++) { + imp = &tci->operation.params[i]; + ext = &operation->params[i]; + buffer = NULL; + + switch (_TEEC_GET_PARAM_TYPE(operation->paramTypes, i)) { + case TEEC_VALUE_INPUT: + LOG_I(" cycle %d, TEEC_VALUE_INPUT", i); + break; + case TEEC_NONE: + LOG_I(" cycle %d, TEEC_NONE", i); + break; + case TEEC_VALUE_OUTPUT: + case TEEC_VALUE_INOUT: { + LOG_I(" cycle %d, TEEC_VALUE_*OUT", i); + if (copyValues) { + ext->value.a = imp->value.a; + ext->value.b = imp->value.b; + } + break; + } + case TEEC_MEMREF_TEMP_OUTPUT: + case TEEC_MEMREF_TEMP_INPUT: + case TEEC_MEMREF_TEMP_INOUT: { + LOG_I(" cycle %d, TEEC_TEMP*", i); + if ((copyValues) && (_TEEC_GET_PARAM_TYPE(operation->paramTypes, i) != TEEC_MEMREF_TEMP_INPUT)) { + ext->tmpref.size = imp->memref.outputSize; + } + buffer = (uint8_t *)ext->tmpref.buffer; + break; + } + case TEEC_MEMREF_WHOLE: { + LOG_I(" cycle %d, TEEC_MEMREF_WHOLE", i); + if ((copyValues) && (ext->memref.parent->flags != TEEC_MEM_INPUT)) { + ext->memref.size = imp->memref.outputSize; + } + buffer = (uint8_t *)ext->memref.parent->buffer; + break; + } + + case TEEC_MEMREF_PARTIAL_OUTPUT: + case TEEC_MEMREF_PARTIAL_INOUT: + case TEEC_MEMREF_PARTIAL_INPUT: { + LOG_I(" cycle %d, TEEC_MEMREF_PARTIAL*", i); + if ((copyValues) && (_TEEC_GET_PARAM_TYPE(operation->paramTypes, i) != TEEC_MEMREF_PARTIAL_INPUT)) { + ext->memref.size = imp->memref.outputSize; + } + buffer = (uint8_t *)ext->memref.parent->buffer + ext->memref.offset; + break; + } + default: + LOG_E("cycle %d, bad parameter", i); + break; + } + + if ((buffer != NULL) && (imp->memref.mapInfo.sVirtualLen != 0)) { + // This function assumes that we cannot handle error of mcUnmap + (void)mcUnmap(handle, buffer, &imp->memref.mapInfo); + } + } + + return tci->returnStatus; +} + +//------------------------------------------------------------------------------ +//TEEC_InitializeContext: TEEC_SUCCESS, Another error code from Table 4-2. +//MC_DRV_OK, MC_DRV_ERR_INVALID_OPERATION, MC_DRV_ERR_DAEMON_UNREACHABLE, MC_DRV_ERR_UNKNOWN_DEVICE, MC_DRV_ERR_INVALID_DEVICE_FILE +TEEC_Result TEEC_InitializeContext( + const char *name, + TEEC_Context *context) +{ + LOG_I("== %s() ==============", __func__); + + if (context == NULL) return TEEC_ERROR_BAD_PARAMETERS; + context->imp.reserved = MC_DEVICE_ID_DEFAULT; + + switch (mcOpenDevice(MC_DEVICE_ID_DEFAULT)) { + case MC_DRV_OK: + return TEEC_SUCCESS; + case MC_DRV_ERR_DAEMON_UNREACHABLE: + return TEEC_ERROR_COMMUNICATION; + case MC_DRV_ERR_UNKNOWN_DEVICE: + return TEEC_ERROR_BAD_PARAMETERS; + case MC_DRV_ERR_INVALID_DEVICE_FILE: + return TEEC_ERROR_COMMUNICATION; + } + + return TEEC_ERROR_GENERIC; +} + +//------------------------------------------------------------------------------ +//mcCloseDevice: MC_DRV_OK, MC_DRV_ERR_UNKNOWN_DEVICE, MC_DRV_ERR_SESSION_PENDING, MC_DRV_ERR_DAEMON_UNREACHABLE +//TEEC_FinalizeContext: void + +//TODO: The implementation of this function MUST NOT be able to fail: after this function returns the Client +//Application must be able to consider that the Context has been closed. + +void TEEC_FinalizeContext(TEEC_Context *context) +{ + mcResult_t mcRet; + + LOG_I("== %s() ==============", __func__); + + //The parameter context MUST point to an initialized TEE Context. + //Just realized: The function implementation MUST do nothing if context is NULL. + if (context == NULL) { + LOG_E("context is NULL"); + return; + } + + //The implementation of this function MUST NOT be able to fail: after this function returns the Client + //Application must be able to consider that the Context has been closed. + mcRet = mcCloseDevice(context->imp.reserved); + if (mcRet != MC_DRV_OK) { + LOG_E("mcCloseDevice failed (%08x)", mcRet); + /* continue even in case of error */; + } +} + +//------------------------------------------------------------------------------ +static TEEC_Result _TEEC_CallTA( + TEEC_Session *session, + TEEC_Operation *operation, + uint32_t *returnOrigin) +{ + mcResult_t mcRet; + TEEC_Result teecRes; + TEEC_Result teecError = TEEC_SUCCESS; + + LOG_I(" %s()", __func__); + + // Phase 1: start the operation and wait for the result + teecRes = _TEEC_SetupOperation((_TEEC_TCI *)session->imp.tci, &session->imp.handle, operation, returnOrigin); + if (teecRes != TEEC_SUCCESS ) { + LOG_E("_TEEC_SetupOperation failed (%08x)", teecRes); + return teecRes; + } + + // Signal the Trusted App + mcRet = mcNotify(&session->imp.handle); + if (MC_DRV_OK != mcRet) { + LOG_E("Notify failed (%08x)", mcRet); + teecError = TEEC_ERROR_COMMUNICATION; + goto end; + } + + // ------------------------------------------------------------- + // Wait for the Trusted App response + mcRet = mcWaitNotification(&session->imp.handle, MC_INFINITE_TIMEOUT); + if (mcRet != MC_DRV_OK) { + teecError = TEEC_ERROR_COMMUNICATION; + if (mcRet == MC_DRV_INFO_NOTIFICATION) { + int32_t lastErr = SESSION_ERR_NO; + mcGetSessionErrorCode(&session->imp.handle, &lastErr); + if (lastErr == TA_EXIT_CODE_FINISHED) { + // We may get here if the TA_OpenSessionEntryPoint returns an error and TA goes fast through DestroyEntryPoint and exits the TA. + teecError = TEEC_SUCCESS; + } else if (lastErr != ERR_INVALID_SID && lastErr != ERR_SID_NOT_ACTIVE) { + LOG_E("Target is DEAD"); + + *returnOrigin = TEEC_ORIGIN_TEE; + teecError = TEEC_ERROR_TARGET_DEAD; + } else { + LOG_E("mcWaitNotification failed (%08x)", mcRet); + LOG_E("mcGetSessionErrorCode returned %d", lastErr); + } + } + } + // Phase 2: Return values and cleanup +end: + // unmap memory and copy values if no error + teecRes = _TEEC_UnwindOperation((_TEEC_TCI *)session->imp.tci, &session->imp.handle, operation, + (teecError == TEEC_SUCCESS), returnOrigin); + if (teecRes != TEEC_SUCCESS ) { + LOG_E("_TEEC_UnwindOperation (%08x)", teecRes); + /* continue even in case of error */; + } + + // Cleanup + if (teecError != TEEC_SUCCESS) { + // Previous interactions failed, either TA is dead or communication error + mcRet = mcCloseSession(&session->imp.handle); + if (mcRet != MC_DRV_OK) { + LOG_E("mcCloseSession failed (%08x)", mcRet); + /* continue even in case of error */; + } + session->imp.active = false; + if (teecError == TEEC_ERROR_COMMUNICATION) { + *returnOrigin = TEEC_ORIGIN_COMMS; + } + munmap(session->imp.tci, sysconf(_SC_PAGESIZE)); + session->imp.tci = NULL; + } + return teecError; +} + +//------------------------------------------------------------------------------ +__MC_CLIENT_LIB_API mcResult_t mcOpenGPTA( + mcSessionHandle_t *session, + const mcUuid_t *uuid, + uint8_t *tci, + uint32_t len +); +//------------------------------------------------------------------------------ +//TEEC_OpenSession: if the returnOrigin is different from TEEC_ORIGIN_TRUSTED_APP, an error code from Table 4-2 +// If the returnOrigin is equal to TEEC_ORIGIN_TRUSTED_APP, a return code defined by the +//protocol between the Client Application and the Trusted Application. +TEEC_Result TEEC_OpenSession ( + TEEC_Context *context, + TEEC_Session *session, + const TEEC_UUID *destination, + uint32_t connectionMethod, + void *connectionData, + TEEC_Operation *operation, + uint32_t *returnOrigin) +{ + mcResult_t mcRet; + TEEC_Result teecRes; + uint32_t returnOrigin_local; + mcUuid_t tauuid; + + LOG_I("== %s() ==============", __func__); + // ------------------------------------------------------------- + //The parameter context MUST point to an initialized TEE Context. + if (context == NULL) { + LOG_E("context is NULL"); + if (returnOrigin != NULL) *returnOrigin = TEEC_ORIGIN_API; + return TEEC_ERROR_BAD_PARAMETERS; + } + + if (session == NULL) { + LOG_E("session is NULL"); + if (returnOrigin != NULL) *returnOrigin = TEEC_ORIGIN_API; + return TEEC_ERROR_BAD_PARAMETERS; + } + + if (connectionMethod != TEEC_LOGIN_PUBLIC) { + //JACKET: Client authorization is not supported. The connectionMethod parameter + //must be TEEC LOGIN PUBLIC, otherwise return TEEC ERROR NOT IMPLEMENTED. + LOG_E("connectionMethod != TEEC_LOGIN_PUBLIC"); + if (returnOrigin != NULL) *returnOrigin = TEEC_ORIGIN_API; + return TEEC_ERROR_NOT_IMPLEMENTED; + } + + // ------------------------------------------------------------- + session->imp.active = false; + + _libUuidToArray((TEEC_UUID *)destination, (uint8_t *)tauuid.value); + + if (operation) operation->imp.session = &session->imp; + + //Allocate a 4kB page with mmap, zero it out, and set session->imp.tci to its address. + session->imp.tci = NULL; + void *bulkBuf = (void *)mmap(0, sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (bulkBuf == MAP_FAILED) { + LOG_E("mmap failed on tci buffer allocation"); + if (returnOrigin != NULL) *returnOrigin = TEEC_ORIGIN_API; + return TEEC_ERROR_OUT_OF_MEMORY; + } + + session->imp.tci = bulkBuf; + memset(session->imp.tci, 0, sysconf(_SC_PAGESIZE)); + + pthread_mutex_init(&session->imp.mutex_tci, NULL); + pthread_mutex_lock(&session->imp.mutex_tci); + + //Fill the TCI buffer session.tci with the destination UUID. + memcpy(&(((_TEEC_TCI *)session->imp.tci)->destination), destination, sizeof(TEEC_UUID)); + // ------------------------------------------------------------- + memset(&session->imp.handle, 0, sizeof(mcSessionHandle_t)); + session->imp.handle.deviceId = context->imp.reserved ; // The device ID (default device is used) + mcRet = mcOpenGPTA( + &session->imp.handle, + &tauuid, + (uint8_t *)session->imp.tci, + sizeof(_TEEC_TCI)); + if (mcRet != MC_DRV_OK) { + LOG_E("mcOpenGPTA failed (%08x)", mcRet); + if (returnOrigin != NULL) *returnOrigin = TEEC_ORIGIN_COMMS; + if (mcRet == MC_DRV_ERR_TRUSTED_APPLICATION_NOT_FOUND) { + teecRes = TEEC_ERROR_ITEM_NOT_FOUND; + } else { + //TODO: Improve the error codes + teecRes = TEEC_ERROR_GENERIC; + } + goto error; + } + + session->imp.active = true; + + // Let TA go through entry points + LOG_I(" let TA go through entry points"); + ((_TEEC_TCI *)session->imp.tci)->operation.type = _TA_OPERATION_OPEN_SESSION; + teecRes = _TEEC_CallTA(session, operation, &returnOrigin_local); + + // Check for error on communication level + if (teecRes != TEEC_SUCCESS ) { + LOG_E("_TEEC_CallTA failed(%08x)", teecRes); + // Nothing to do here because _TEEC_CallTA closes broken sessions + if (returnOrigin != NULL) *returnOrigin = returnOrigin_local; + goto error; + } + LOG_I(" no errors in com layer"); + + // Check for error from TA + if (returnOrigin != NULL) *returnOrigin = ((_TEEC_TCI *)session->imp.tci)->returnOrigin; + teecRes = ((_TEEC_TCI *)session->imp.tci)->returnStatus; + if (teecRes != TEEC_SUCCESS ) { + LOG_E("TA OpenSession EP failed(%08x)", teecRes); + goto error; + } + + LOG_I(" %s() = TEEC_SUCCESS ", __func__); + pthread_mutex_unlock(&session->imp.mutex_tci); + + if (returnOrigin != NULL) *returnOrigin = TEEC_ORIGIN_TRUSTED_APP; + return TEEC_SUCCESS; + + // ------------------------------------------------------------- +error: + if (session->imp.active) { + // After notifying us, TA went to Destry EP, so close session now + mcRet = mcCloseSession(&session->imp.handle); + if (mcRet != MC_DRV_OK) { + LOG_E("mcCloseSession failed (%08x)", mcRet); + /* continue even in case of error */; + } + session->imp.active = false; + } + + pthread_mutex_unlock(&session->imp.mutex_tci); + pthread_mutex_destroy(&session->imp.mutex_tci); + if (session->imp.tci) { + munmap(session->imp.tci, sysconf(_SC_PAGESIZE)); + session->imp.tci = NULL; + } + + LOG_I(" %s() = 0x%x", __func__, teecRes); + return teecRes; +} + +//------------------------------------------------------------------------------ +TEEC_Result TEEC_InvokeCommand( + TEEC_Session *session, + uint32_t commandID, + TEEC_Operation *operation, + uint32_t *returnOrigin) +{ + TEEC_Result teecRes; + uint32_t returnOrigin_local; + + LOG_I("== %s() ==============", __func__); + + // ------------------------------------------------------------- + if (session == NULL) { + LOG_E("session is NULL"); + if (returnOrigin != NULL) *returnOrigin = TEEC_ORIGIN_API; + return TEEC_ERROR_BAD_PARAMETERS; + } + + if (!session->imp.active) { + LOG_E("session is inactive"); + if (returnOrigin != NULL) *returnOrigin = TEEC_ORIGIN_API; + return TEEC_ERROR_BAD_STATE; + } + // ------------------------------------------------------------- + if (operation) operation->imp.session = &session->imp; + + pthread_mutex_lock(&session->imp.mutex_tci); + + // Call TA + ((_TEEC_TCI *)session->imp.tci)->operation.commandId = commandID; + ((_TEEC_TCI *)session->imp.tci)->operation.type = _TA_OPERATION_INVOKE_COMMAND; + teecRes = _TEEC_CallTA(session, operation, &returnOrigin_local); + if (teecRes != TEEC_SUCCESS ) { + LOG_E("_TEEC_CallTA failed(%08x)", teecRes); + if (returnOrigin != NULL) *returnOrigin = returnOrigin_local; + } else { + if (returnOrigin != NULL) *returnOrigin = ((_TEEC_TCI *)session->imp.tci)->returnOrigin; + teecRes = ((_TEEC_TCI *)session->imp.tci)->returnStatus; + } + + pthread_mutex_unlock(&session->imp.mutex_tci); + LOG_I(" %s() = 0x%x", __func__, teecRes); + return teecRes; +} + +//------------------------------------------------------------------------------ +void TEEC_CloseSession(TEEC_Session *session) +{ + mcResult_t mcRet; + TEEC_Result teecRes = TEEC_SUCCESS; + uint32_t returnOrigin; + + LOG_I("== %s() ==============", __func__); + + // ------------------------------------------------------------- + //The Implementation MUST do nothing if the session parameter is NULL. + if (session == NULL) { + LOG_E("session is NULL"); + return; + } + + // ------------------------------------------------------------- + if (session->imp.active) { + // Let TA go through CloseSession and Destroy entry points + LOG_I(" let TA go through close entry points"); + pthread_mutex_lock(&session->imp.mutex_tci); + ((_TEEC_TCI *)session->imp.tci)->operation.type = _TA_OPERATION_CLOSE_SESSION; + teecRes = _TEEC_CallTA(session, NULL, &returnOrigin); + if (teecRes != TEEC_SUCCESS ) { + /* continue even in case of error */; + LOG_E("_TEEC_CallTA failed(%08x)", teecRes); + } + + if (session->imp.active) { + // Close Session + mcRet = mcCloseSession(&session->imp.handle); + if (mcRet != MC_DRV_OK) { + LOG_E("mcCloseSession failed (%08x)", mcRet); + /* ignore error and also there shouldn't be one */ + } + } + pthread_mutex_unlock(&session->imp.mutex_tci); + } + + pthread_mutex_destroy(&session->imp.mutex_tci); + if (session->imp.tci) { + munmap(session->imp.tci, sysconf(_SC_PAGESIZE)); + session->imp.tci = NULL; + } + session->imp.active = false; + + LOG_I(" %s() = 0x%x", __func__, teecRes); +} + +//------------------------------------------------------------------------------ +TEEC_Result TEEC_RegisterSharedMemory( + TEEC_Context *context, + TEEC_SharedMemory *sharedMem) +{ + LOG_I("== %s() ==============", __func__); + + //The parameter context MUST point to an initialized TEE Context. + if (context == NULL) { + LOG_E("context is NULL"); + return TEEC_ERROR_BAD_PARAMETERS; + } + //The parameter sharedMem MUST point to the Shared Memory structure defining + //the memory region to register. + if (sharedMem == NULL) { + LOG_E("sharedMem is NULL"); + return TEEC_ERROR_BAD_PARAMETERS; + } + //The buffer field MUST point to the memory region to be shared, and MUST not be NULL. + if (sharedMem->buffer == NULL) { + LOG_E("sharedMem->buffer is NULL"); + return TEEC_ERROR_BAD_PARAMETERS; + } + if ((sharedMem->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)) != 0) { + LOG_E("sharedMem->flags is incorrect"); + return TEEC_ERROR_BAD_PARAMETERS; + } + if (sharedMem->flags == 0) { + LOG_E("sharedMem->flags is incorrect"); + return TEEC_ERROR_BAD_PARAMETERS; + } + + sharedMem->imp.implementation_allocated = false; + return TEEC_SUCCESS; +} + +//------------------------------------------------------------------------------ +TEEC_Result TEEC_AllocateSharedMemory( + TEEC_Context *context, + TEEC_SharedMemory *sharedMem) +{ + //No connection to "context"? + LOG_I("== %s() ==============", __func__); + + //The parameter context MUST point to an initialized TEE Context. + if (context == NULL) { + LOG_E("context is NULL"); + return TEEC_ERROR_BAD_PARAMETERS; + } + //The parameter sharedMem MUST point to the Shared Memory structure defining + //the memory region to register. + if (sharedMem == NULL) { + LOG_E("sharedMem is NULL"); + return TEEC_ERROR_BAD_PARAMETERS; + } + if ((sharedMem->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)) != 0) { + LOG_E("sharedMem->flags is incorrect"); + return TEEC_ERROR_BAD_PARAMETERS; + } + if (sharedMem->flags == 0) { + LOG_E("sharedMem->flags is incorrect"); + return TEEC_ERROR_BAD_PARAMETERS; + } + + sharedMem->buffer = malloc(sharedMem->size); + if (sharedMem->buffer == NULL) { + LOG_E("malloc failed"); + return TEEC_ERROR_OUT_OF_MEMORY; + } + sharedMem->imp.implementation_allocated = true; + + return TEEC_SUCCESS; +} + +//------------------------------------------------------------------------------ +void TEEC_ReleaseSharedMemory ( + TEEC_SharedMemory *sharedMem) +{ + //No connection to "context"? + LOG_I("== %s() ==============", __func__); + + //The Implementation MUST do nothing if the sharedMem parameter is NULL + if (sharedMem == NULL) { + LOG_E("sharedMem is NULL"); + return; + } + + //For a memory buffer allocated using TEEC_AllocateSharedMemory the Implementation + //MUST free the underlying memory + if (sharedMem->imp.implementation_allocated) { + if (sharedMem->buffer) { + free(sharedMem->buffer); + sharedMem->buffer = NULL; + sharedMem->size = 0; + } + } + + //TODO: Attempting to release Shared Memory which is used by a pending operation. + +} + +//------------------------------------------------------------------------------ +void TEEC_RequestCancellation( + TEEC_Operation *operation) +{ + LOG_I("== %s() ==============", __func__); + + while (operation->started == 0); + + LOG_I("while(operation->started ==0) passed"); + + if (operation->started > 1) { + LOG_I("The operation has finished"); + return; + } + + TEEC_Session_IMP *session = operation->imp.session; + operation->started = 2; + + if (!session->active) { + LOG_I("Corresponding session is not active"); + return; + } + ((_TEEC_TCI *)session->tci)->operation.isCancelled = true; + + // Step 4.3: signal the Trustlet + mcResult_t mcRet = mcNotify(&session->handle); + if (MC_DRV_OK != mcRet) { + LOG_E("Notify failed (%08x)", mcRet); + } +} + +//------------------------------------------------------------------------------ |