/**
 * @file    mcAgentMain.c
 * @brief   WSM MC trustlet entry point
 * @author  Sergii Sidorov (s.sidorov@samsung.com)
 * @version 1.0.1
 * @date Created April 14, 2015 11:00 AM
 * @par In Samsung Ukraine R&D Center (SURC) under a contract between
 * @par LLC "Samsung Electronics Ukraine Company" (Kyiv, Ukraine) and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 * @par Copyright: (c) Samsung Electronics Co, Ltd 2015. All rights reserved.
 **/

#include <locale.h>

#include "tlStd.h"
#include "TlApi/TlApi.h"

#include "wsm_log.h"
#include "tl_tlcApi.h"
#include "version_info.h"
#include "tl_handler.h"
#include "stack_protection.h"
#include "tz_proca_handler.h"

#include "wsm_rand.h"
#include "wsm_types.h"

#ifdef USE_SCRYPTO
char TZ_APP_NAME[] = { "wsm" };
#endif /* ifdef USE_SCRYPTO */

/* Termination Code */
#define EXIT_ERROR ((uint32_t)(-1))

#define TRUSTLET_MAIN_STACK_SIZE    64 * 1024
#define TRUSTLET_HEAP_SIZE          128 * 1024

DECLARE_TRUSTLET_MAIN_STACK(TRUSTLET_MAIN_STACK_SIZE)

// Local TCI buffer, TA should not work directly with Shared memory data
static tciMessage_t msg_buffer;

// Reserve HEAP
#ifndef USE_SCRYPTO
#include "libc_functions/inc/memmgrs.h"
// Reserve HEAP
static uint8_t heap[TRUSTLET_HEAP_SIZE];
#endif /* ifndef USE_SCRYPTO */

_TLAPI_ENTRY void tlMain(const addr_t tciBuffer, const uint32_t tciBufferLen)
{
    // Trustonic request
    // Randomize the canary variable so we can use it as a stack protector
    // It is only used due to incomplete functionality in DS-5 compiler
    #ifdef NO_STACK_CHK_IMPLEMENTED
    stack_protection_init();
    #endif /* ifndef NO_STACK_CHK_IMPLEMENTED */

    /* print vesrion info */
    print_version_info(MODULE_IDENTITY_TA);

    /* Print trustlet name and version */
    WSM_LOG(err_level_info, LOG_TAG, "================================================");
    WSM_LOG(err_level_info, LOG_TAG, "  WSM trustlet version: " VERSION_NUMBER);
    WSM_LOG(err_level_info, LOG_TAG, "  heap : %d, stack : %d ", TRUSTLET_HEAP_SIZE,
            TRUSTLET_MAIN_STACK_SIZE);
    WSM_LOG(err_level_info, LOG_TAG, "================================================");

    // setlocale should be without "ifdef"
    // The issue related to libc.a is being used
    // The functionality is needed by different kind of string/char conversions,
    // characters treating etc. The last is important for crypto operations like keywrapping
    // As instance, well known that Qualcomm doesn recommend to use internal NHLOS libc and use another one instead
    setlocale(LC_ALL, "C");

#ifndef USE_SCRYPTO
    if (1 != memmngr_init(heap, sizeof(heap)))
    {
        WSM_LOG_E(LOG_TAG, WSM_RET_E_CRYPTOCORE_HEAP_INIT, " Heap init error \n");
        tlApiExit(EXIT_ERROR);
    }
#endif /* ifndef USE_SCRYPTO */

    WSM_LOG(err_level_info, LOG_TAG, "[%s] Mem allocator inited \n", __func__);

    if (NULL == tciBuffer)
    {
        WSM_LOG_E(LOG_TAG, WSM_RET_E_NULL_POINTER, "[%s] ERROR. Invalid TCI \n", __func__);
        tlApiExit(EXIT_ERROR);
    }

    if (sizeof(tciMessage_t) != tciBufferLen)
    {
        WSM_LOG_E(LOG_TAG, WSM_RET_E_LENGTH, "invalid TCI (got 0x%08X, %d, need %d), exit\n",
                  tciBuffer, tciBufferLen, sizeof(tciMessage_t));
        tlApiExit(EXIT_ERROR);
    }

    for (;;)
    {
        tlApiWaitNotification(TLAPI_INFINITE_TIMEOUT);

        WSM_LOG_EN(LOG_TAG, "%s: Called\n", "ta.mc");
        // Copy TCI msg from shared memory to TL memory
        memset(&msg_buffer, 0, sizeof(msg_buffer));
        if (sizeof(msg_buffer) >= tciBufferLen)
        {
            memcpy(&msg_buffer, tciBuffer, tciBufferLen);
        }
        else
        {
            WSM_LOG_E(LOG_TAG, WSM_RET_E_OVERFLOW, "[%s] Too big command length\n", __func__);

            msg_buffer.response.status = WSM_RET_E_OVERFLOW;
            tlApiNotify();
            continue;
        }

        // PROCA->check Daemon
        return_t pa_result_daemon;

        pa_result_daemon = proca_tz_auth();
        if ((WSM_RET_SUC != pa_result_daemon))
        {
            WSM_LOG_E(LOG_TAG, WSM_ERR_PROCA_AUTH_SWD, "[%s] Proca auth fail\n", __func__);
            msg_buffer.response.status = pa_result_daemon;
            memcpy(tciBuffer, &msg_buffer, sizeof(msg_buffer));

            tlApiNotify();
            continue;
        }

        msg_buffer.response.status = TZ_COMMAND((void *)msg_buffer.msgData.buffer);
        WSM_LOG_HEX(err_level_info, LOG_TAG, "Reply data = ", (char *)&msg_buffer,
                    sizeof(msg_buffer));

        memcpy(tciBuffer, &msg_buffer, sizeof(msg_buffer));

        WSM_LOG_EN(LOG_TAG, "%s: Notify to daemon\n", "ta.mc");
        tlApiNotify();
        WSM_LOG_EN(LOG_TAG, "%s: End\n", "ta.mc");
    }
}
