#include <tee_internal_api.h>
#include <tees_extension.h>
#include <stdio.h>

#include "bfAgentMain.h"

#include "mz_types.h"

#include "mz_log.h"
#include "tl_tlcApi.h"
#include "version_info.h"
#include "tl_handler.h"

#define USED_PARAM_INDEX    0

static tciMessage_t msg_buffer;

TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t commandID,
                                      uint32_t param_types, TEE_Param param[4])
{
    (void)sessionContext;

    tciMessage_t *tciBuffer;
    uint32_t tciBufferLen = 0;
    int32_t ret_value;
    tciReturnCode_t ret_app;

    MZ_LOG_EN(LOG_TAG, "[%s] Called\n", "ta.te");

    // Parameter Type
    // (see: http://mosaic.sec.samsung.net/kms/comty.do?comtyId=3012074&menuId=3012077&postId=356019566&page=view&type=LIST)
    if (TEE_PARAM_TYPE_MEMREF_INOUT != (TEE_PARAM_TYPE_GET(param_types, USED_PARAM_INDEX)))
    {
        MZ_LOG_E(LOG_TAG, MZ_RET_E_TA_BF_WRONG_INPUT_PARAM, "[%s] Input Param Type are wrong \n",
                  __func__);
        return RET_ERR;
    }

#if (TEEGRIS_SDK_VERSION > 20)
    // TA access right on buffer
    // (see: http://mosaic.sec.samsung.net/kms/comty.do?comtyId=3012074&menuId=3012077&postId=356019566&page=view&type=LIST)
    if (TEE_SUCCESS != TEES_IsREESharedMemory(
            TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_WRITE,
            param[USED_PARAM_INDEX].memref.buffer,
            param[USED_PARAM_INDEX].memref.size))
    {
        MZ_LOG_E(LOG_TAG, MZ_RET_E_TA_BF_WRONG_INPUT_PARAM,
                  "[%s] Input TA access right on buffer wrong \n", __func__);
        return RET_ERR;
    }
#endif /* if (TEEGRIS_SDK_VERSION > 20) */

    tciBuffer = (tciMessage_t *)(param[USED_PARAM_INDEX].memref.buffer);
    tciBufferLen = param[USED_PARAM_INDEX].memref.size;

    if (NULL == tciBuffer)
    {
        MZ_LOG_E(LOG_TAG, MZ_RET_E_NULL_POINTER, "[%s] ERROR. Invalid TCI \n", __func__);
        return RET_ERR;
    }

    if (sizeof(tciMessage_t) != tciBufferLen)
    {
        MZ_LOG_E(LOG_TAG, MZ_RET_E_LENGTH_MISMATCH,
                  "[%s] ERROR. Invalid TCI buffer len, sizeof(tciMessage_t) = %zu, tciBufferLen = %d\n",
                  __func__, sizeof(tciMessage_t), tciBufferLen);
        return RET_ERR;
    }

    // Copy TCI msg from shared memory to TL memory
    TEE_MemFill(&msg_buffer, 0, sizeof(msg_buffer));
    TEE_MemMove(&msg_buffer, tciBuffer, tciBufferLen);

    do
    {
        // PROCESS the command
        ret_value = TZ_COMMAND((void *)msg_buffer.msgData.buffer);
        ret_app = (ret_value == MZ_RET_SUC) ? RET_OK : RET_ERR;
    } while (0);

    msg_buffer.response.status = ret_value;
    msg_buffer.response.header.responseId = RSP_ID(commandID);
    msg_buffer.response.header.returnCode = ret_app;

    TEE_MemMove(tciBuffer, &msg_buffer, sizeof(msg_buffer));

    MZ_LOG_EN(LOG_TAG, "[%s] End\n", "ta.te");

    return (msg_buffer.response.header.returnCode == RET_OK) ? TEE_SUCCESS : TEE_ERROR_GENERIC;
}

TEE_Result TA_CreateEntryPoint(void)
{
    MZ_LOG_EN(LOG_TAG, "[%s] Create\n", "ta.te");

    return TEE_SUCCESS;
}

void TA_DestroyEntryPoint(void)
{
    MZ_LOG_EN(LOG_TAG, "[%s] Destroy\n", "ta.te");

#if defined(MALLOC_WRAPPER) && !defined(MZ_IOS)
    extern void malloc_wrapper_destructor();
    malloc_wrapper_destructor();
#endif // defined(MALLOC_WRAPPER) && !defined(MZ_IOS)
}

TEE_Result TA_OpenSessionEntryPoint(uint32_t paramTypes, TEE_Param params[4], void **sessionContext)
{
    (void)params;
    (void)paramTypes;
    (void)sessionContext;

    /* print vesrion info */
    print_version_info(MODULE_IDENTITY_TA);

    /* print trustlet name and version */
    MZ_LOG(err_level_info, LOG_TAG, "================================================\n");
    MZ_LOG(err_level_info, LOG_TAG, "  MZ trustlet version   : %s\n", VERSION_NUMBER);
    MZ_LOG(err_level_info, LOG_TAG, "  MZ trustlet stack size: 0x%x\n", TA_PROP_STACKSIZE);
    MZ_LOG(err_level_info, LOG_TAG, "================================================\n");

    return TEE_SUCCESS;
}

void TA_CloseSessionEntryPoint(void *sessionContext)
{
    (void)sessionContext;
    MZ_LOG(err_level_info, LOG_TAG, "[%s] Entry  \n", __func__);
}
