#include <tee_internal_api.h>

#include <em_ta_main.h>
#include <stdio.h>
#include <string.h>

#include "em_common.h"

char TZ_APP_NAME[] = "ENGMODE";

TEE_Result TA_CreateEntryPoint(void)
{
	LOGI("\n");
	return TEE_SUCCESS;
}

void TA_DestroyEntryPoint(void) { LOGI("\n"); }

TEE_Result TA_OpenSessionEntryPoint(uint32_t paramTypes, TEE_Param params[4], void **sessionContext)
{
	(void)paramTypes;
	(void)params;
	(void)sessionContext;

	LOGI("\n");

	return TEE_SUCCESS;
}

void TA_CloseSessionEntryPoint(void *sessionContext)
{
	(void)sessionContext;
	LOGI("\n");
}

TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t commandID, uint32_t paramTypes,
				      TEE_Param params[4])
{
	LOGI("EngineeringMode TA Here\n");
	LOGI("EngineeringMode TA Version : %s\n", EM_MODULE_VERSION);

	(void) sessionContext;
	(void) commandID;
	(void) paramTypes;
	(void) params;

	uint8_t *req_buf = NULL;
	uint8_t *rsp_buf = NULL;
	uint32_t req_buf_len = 0;
	uint32_t rsp_buf_len = 0;

	em_context *ctx = NULL;
	LOGI("size = %d\n", sizeof(ctx));
	LOGI("em_comtext = %d\n", sizeof(em_context));
	uint32_t ret = 0;

	ctx = (em_context *)em_calloc(1, sizeof(em_context));
	if (ctx == NULL) {
		LOGE("TEE malloc failed\n");
		ret = EM_ERR_TA_MAIN_CTX_MEM_ALLOC;
		goto out;
	}

	if (TEE_PARAM_TYPE_GET(paramTypes, 0) == TEE_PARAM_TYPE_MEMREF_INOUT) {
		req_buf_len = params[0].memref.size;
		if (params[0].memref.buffer == NULL) {
			LOGE("req buf is NULL\n");
			ret = EM_ERR_TA_MAIN_REQ_BUF_NULL;
			goto out;
		}

		if (req_buf_len != EM_STRUCT_REQ_PAYLOAD_SIZE) {
			LOGE("req buf len isn't matched(%d/%d)\n", req_buf_len, EM_STRUCT_REQ_PAYLOAD_SIZE);
			ret = EM_ERR_TA_MAIN_REQ_BUF_LEN;
			goto out;
		}

		if (TEES_IsREESharedMemory(TEE_MEMORY_ACCESS_READ, params[0].memref.buffer, req_buf_len) != TEE_SUCCESS) {
			LOGE("Memory access check error\n");
			ret = EM_ERR_TA_MAIN_REQ_BUF_MEM_ACCESS;
			goto out;
		}
		req_buf = (uint8_t*)em_malloc(req_buf_len);
		if (req_buf == NULL) {
			LOGE("TEE malloc failed\n");
			ret = EM_ERR_TA_MAIN_REQ_BUF_MEM_ALLOC;
			goto out;
		} else {
			TEE_MemMove(req_buf, (uint8_t *)params[0].memref.buffer, req_buf_len);
		}
	} else {
		LOGE("Error Invalid parameter");
		ret = EM_ERR_TA_MAIN_REQ_INVALID_ARG;
		goto out;
	}

	if (TEE_PARAM_TYPE_GET(paramTypes, 1) == TEE_PARAM_TYPE_MEMREF_INOUT) {
		rsp_buf_len = params[1].memref.size;
		if (params[1].memref.buffer == NULL) {
			LOGE("req buf is NULL\n");
			ret = EM_ERR_TA_MAIN_RSP_BUF_NULL;
			goto out;
		}

		if (rsp_buf_len != EM_STRUCT_RSP_PAYLOAD_SIZE) {
			LOGE("rsp buf len isn't matched(%d/%d)\n", rsp_buf_len, EM_STRUCT_RSP_PAYLOAD_SIZE);
			ret = EM_ERR_TA_MAIN_RSP_BUF_LEN;
			goto out;
		}

		if (TEES_IsREESharedMemory(TEE_MEMORY_ACCESS_WRITE, params[1].memref.buffer, rsp_buf_len) !=
		    TEE_SUCCESS) {
			LOGE("Memory access check error\n");
			ret = EM_ERR_TA_MAIN_RSP_BUF_MEM_ACCESS;
			goto out;
		}
	} else {
		LOGE("Error Invalid parameter\n");
		ret = EM_ERR_TA_MAIN_RSP_INVALID_ARG;
		goto out;
	}
	
	LOGW("Checking param done...\n");

	ret = em_context_make_request(req_buf, ctx);
	if (ret != EM_SUCCESS) {
		LOGE("Failed make context_request(0x%08x)\n", ret);
		//rsp.ret = ret;
		goto make_msg;
	}

	ret = em_cmd_handler(ctx);
	if (ret != EM_SUCCESS) {
		LOGE("Failed cmd processing(0x%08x)\n", ret);
		goto make_msg;
	}

	LOGI("command result %d\n", ret);
make_msg:
	ret = em_context_make_response(params[1].memref.buffer, ctx, ret);
	if (ret != EM_SUCCESS) {
		LOGE("Failed make context_response(0x%08x)\n", ret);
		goto out;
	}

	ret = TEE_SUCCESS;
out:
	if (req_buf != NULL)
		TEE_Free(req_buf);

	if (ctx != NULL) {
		memset(ctx, 0, sizeof(em_context));
		TEE_Free(ctx);
	}

	LOGI("EngineeringMode TA Bye\n");

	return ret;
}
