
/*
 * =====================================================================================
 *
 *       Filename:  pebble_main.c
 *
 *    Description:  PEBBLE main
 *
 *        Version:  1.0
 *        Created:  06/03/2020
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2020 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "pebble_main.h"

/**
 * Global In/Out messages
 */
static tci_message_t rcvMsgCopy;
static tci_message_t rspMsgCopy;

//According TLC calcule size - mc_tlc_communication_private.h
//To allow CCM server and client have a consistent view, the alignment configurations should be consistent
#define MC_ALIGN_SIZE 0x40
#define MC_ALIGN_MASK (MC_ALIGN_SIZE - 1)
#define MC_ALIGN(x) \
	((x + MC_ALIGN_SIZE) & (~MC_ALIGN_MASK))

/**
 * @brief
 * TA_CreateEntryPoint
 * @return TEE_Result
 */
TEE_Result TA_CreateEntryPoint(void) {
        PEBBLE_LOG("CreateEntryPoint for PEBBLE\n");
        return TEE_SUCCESS;
}

/**
 * @brief
 * TA_DestroyEntryPoint
 */
void TA_DestroyEntryPoint(void) {
        PEBBLE_LOG("DestoryEntryPoint for PEBBLE\n");
}

/**
 * @brief
 * TA_OpenSessionEntryPoint
 * Open session
 *
 * @param[in] paramTypes     - paramTypes
 * @param[in] params[4]      - params[4]
 * @param[in] sessionContext - session context
 *
 * @return TEE_Result
 */
TEE_Result TA_OpenSessionEntryPoint(uint32_t paramTypes, TEE_Param params[4], void **sessionContext) {
        (void) paramTypes;
        (void) params;
        (void) sessionContext;

        PEBBLE_LOG("Open session for PEBBLE is success\n");
        return TEE_SUCCESS;
}

/**
 * @brief
 * TA_CloseSessionEntryPoint
 * Close session
 *
 * @param[in] sessionContext - session context
 */
void TA_CloseSessionEntryPoint(void *sessionContext) {
        PEBBLE_LOG("CloseSeesionEntryPoint for PEBBLE is success\n");
        (void) sessionContext;
}

/**
 * @brief
 * TA_InvokeCommandEntryPoint
 * Invoke command
 *
 * @param[in] sessionContext - session context
 * @param[in] commandID      - command id
 * @param[in] paramTypes     - paramTypes
 * @param[in] params[4]      - params[4]
 *
 * @return TEE_Result
 */
TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t commandID, uint32_t paramTypes, TEE_Param params[4]) {
        TEE_Result ret = TEE_SUCCESS;
        (void) sessionContext;
        (void) paramTypes;
        (void) params;

        PEBBLE_LOG_DEBUG("tz buildinfo: %s %s %s \n", CONFIG_BUILD_INFO, CONFIG_TARGET_CHIPSET, CONFIG_SEC_SDK);
        PEBBLE_LOG_DEBUG("paramTypes:%d, TEE_PARAM_TYPES:%d\n", paramTypes,
                TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

        if (paramTypes != (uint32_t)TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, 
                                TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE)) {
                PEBBLE_LOG("Bad Parameters in PEBBLE invoke command \n");
                PEBBLE_LOG("min_fixdddd : skip! \n");

                return TEE_ERROR_BAD_PARAMETERS;
        }

        /* param[0]: INOUT */
        if (TEES_IsREESharedMemory (TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_WRITE,
                        params[0].memref.buffer, params[0].memref.size) != TEE_SUCCESS) {
                PEBBLE_LOG("Memory access check error\n");
                return TEE_ERROR_ACCESS_DENIED;
        }

        /* param[1]: OUTPUT */
        if (TEES_IsREESharedMemory (TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_WRITE,
                        params[1].memref.buffer, params[1].memref.size) != TEE_SUCCESS) {
                PEBBLE_LOG("Memory access check error\n");
                return TEE_ERROR_ACCESS_DENIED;
        }

        PEBBLE_LOG("InvokeCommandEntryPoint for PEBBLE is success\n");

        if (params[0].memref.buffer == NULL) {
                PEBBLE_LOG("inBuffer is null");
                return TEE_ERROR_BAD_PARAMETERS;
        }
        if (params[0].memref.size != MC_ALIGN(sizeof(tci_message_t))) {
                PEBBLE_LOG("inBuffer has invalid size");
                PEBBLE_LOG_DEBUG("inBuffer has invalid size paramSize=%d sizeof=%d\n", params[0].memref.size, sizeof(tci_message_t));
                return TEE_ERROR_BAD_PARAMETERS;
        }
        if (params[1].memref.buffer == NULL) {
                PEBBLE_LOG("outBuffer is null");
                return TEE_ERROR_BAD_PARAMETERS;
        }
        if (params[1].memref.size != MC_ALIGN(sizeof(tci_message_t))) {
                PEBBLE_LOG("outBuffer has invalid size");
                PEBBLE_LOG_DEBUG("outBuffer has invalid size paramSize=%d sizeof=%d\n", params[1].memref.size, sizeof(tci_message_t));
                return TEE_ERROR_BAD_PARAMETERS;
        }

        tci_message_t* rcvMsg = NULL;
        tci_message_t* respmsg = NULL;

        /* Create local copy of WSM buffer to prevent Race Condition */
        TEE_MemFill(&rcvMsgCopy, 0, sizeof(tci_message_t));
        TEE_MemFill(&rspMsgCopy, 0, sizeof(tci_message_t));
        TEE_MemMove(&rcvMsgCopy, params[0].memref.buffer, sizeof(tci_message_t));
        
        rcvMsg = &rcvMsgCopy;
        respmsg = &rspMsgCopy;

        ret = process_cmd(commandID, rcvMsg, respmsg);

        respmsg->header.id = RSP_ID(commandID);
        respmsg->header.status = ret;

        TEE_MemMove(params[1].memref.buffer, &rspMsgCopy, sizeof(tci_message_t));

        TEE_MemFill(&rcvMsgCopy, 0, sizeof(tci_message_t));
        TEE_MemFill(&rspMsgCopy, 0, sizeof(tci_message_t));

        return TEE_SUCCESS;
}
