/*
 * =====================================================================================
 *
 *       Filename:  mcAppMain.c
 *
 *    Description:  Entry point of Tbase trustzone app.
 *
 *        Version:  1.0
 *        Created:  03/28/2017 03:44:55 PM
 *       Compiler:  armcc
 *
 *         Author:  Dongwook Shim (), dw.shim@samsung.com
 *        Company:  Samsung Electronics
 *
 *        Copyright (c) 2017 by Samsung Electronics, All rights reserved. 
 *
 * =====================================================================================
 */

#include "tlStd.h"
#include "TlApi/TlApi.h"
#include "TlApi/TlApiMcSystem.h"

#include "commonConfig.h"
#include "cryptoEngine.h"
#include "log.h"
#include "mcStackProtection.h"
#include "secMemoryManager.h"
#include "teeCmdExecuter.h"
#include "version.h"
#ifndef DISABLE_LOG_ENCRYPTION
#include "logEncryptor.h"
#endif  // End of DISABLE_LOG_ENCRYPTION

#define TRUSTLET_MAIN_STACK_SIZE 0x10000
DECLARE_TRUSTLET_MAIN_STACK(TRUSTLET_MAIN_STACK_SIZE)

_TLAPI_ENTRY void tlMain(const addr_t tciBuffer, const uint32_t tciBufferLen)
{
	int32_t ret = NOT_ERROR;
	CmdReq_t req;
	CmdRsp_t rsp;

	// Print trustzone app's name and version.
	VERSIONIZE(TRUSTLET_TAG);

	// Apply stack protection - requested by yj0729.kim at 17.12.05.
	initStackProtection();

	// Check shared buffer.
	if(tciBuffer == NULL || tciBufferLen > sizeof(CmdReq_t))
	{
		LOGE("Invalid TCI(0x%08X, %d)",	tciBuffer, (int)tciBufferLen);
		ret = ERR_TA_INVALID_ARGUMENT;
		tlApiExit((uint32_t)ret);
	}

	if(!tlApiIsNwdBufferValid(tciBuffer, tciBufferLen))
	{
		LOGE("Invalid TCI buffer range (got 0x%08p, %d)", tciBuffer, (int)tciBufferLen);
		ret = ERR_TA_INVALID_ARGUMENT;
		tlApiExit((uint32_t)ret);
	}

	// Allocator initialize.
	if((ret = secMemoryManagerInit()) != NOT_ERROR)
		tlApiExit(ret);

	// crypto engine init
	CRYPTO_init();

	// Infinite loop waiting for MC TEE driver notification.
	while(1)
	{
		// Wait fo "ready to go" event from MC driver.
		tlApiWaitNotification(TLAPI_INFINITE_TIMEOUT);

		// Copy data to secure world. - Riscure request.
		memset(&req, 0, sizeof(req));
		memset(&rsp, 0, sizeof(rsp));
		memcpy(&req, (char *)tciBuffer, (tciBufferLen < sizeof(CmdReq_t)) ? tciBufferLen : sizeof(CmdReq_t));
		rsp.dataLen = sizeof(rsp.data);

		LOGD("Received Cmd = 0x%x with %d bytes in Cmd Buffer", req.cmdId, req.dataLen);

		if((rsp.status = taCmdExecute(req.cmdId, req.data, req.dataLen, rsp.data, &(rsp.dataLen))) != NOT_ERROR)
		{
			LOGE("Invoke Command data caused error! Ret = %d", rsp.status);
#ifndef DISABLE_LOG_ENCRYPTION
			if((ret = logEncrypt(rsp.data, sizeof(rsp.data))) > 0)
				rsp.dataLen = (uint32_t)ret;
			else
			{
				LOGE("Failed to log encryption with error %d.", ret);
				rsp.dataLen = 0;
			}
#else
			((CmdRsp_t *)tciBuffer)->status = rsp.status;
			goto cleanup;
#endif  // End of DISABLE_LOG_ENCRYPTION
		}

		// Treat out buffer size equal to max shared buffer length.
		if(rsp.dataLen > sizeof(rsp.data))
		{
			LOGE("Wrapped data is too big (%d bytes)", rsp.dataLen);
			((CmdRsp_t *)tciBuffer)->status = ERR_TA_BUFFER_OVERFLOW;
			goto cleanup;
		}

		//  Copy out data from temp static buffer to shared buffer.
		memcpy((char *)tciBuffer, &rsp, (tciBufferLen < sizeof(rsp)) ? tciBufferLen : sizeof(rsp));
        
		LOGD("Reply from Cmd = 0x%x with %d bytes in Cmd Buffer", req.cmdId, rsp.dataLen);

	cleanup:
		memset(&req, 0, sizeof(req));
		memset(&rsp, 0, sizeof(rsp));

		tlApiNotify();
	}
}
