#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <em_ta.h>
#include "qsee_log.h"
#include "qsee_fuse.h"
#include "qsee_core.h"

#ifdef QSEE_OLD_INIT_INVOCATION_STYLE
#define INIT_FUNCTION_NAME tz_app_init_ex
#else
#define INIT_FUNCTION_NAME tz_app_init
#endif

// The variable contains TZ application name,
// it is used for logging as well. Due to SCrypto library uses it,
// in case of the variable is undefined, link error will happen
char TZ_APP_NAME[] = { "engmode" };

void INIT_FUNCTION_NAME (void)
{
	/*  App specific initialization code*/
}

void tz_app_cmd_handler(void* req_, uint32_t reqlen, void* rsp_, uint32_t rsplen)
{
	uint8_t *req_buf = NULL;
	em_rsp_payload *rsp_buf = NULL;
	uint32_t ret = 0;
	em_context *ctx = NULL;
	uint32_t req_buf_len = 0;

	LOGW("EngineeringMode TA is open v%s\n", EM_MODULE_VERSION);

	ctx = (em_context *)em_calloc(1, sizeof(em_context));
	if (ctx == NULL) {
		LOGE("%s : TEE malloc failed\n", __func__);
		ret = EM_ERR_TA_MAIN_CTX_MEM_ALLOC;
		goto out;
	}

	/*ret = em_ta_check_rp();
	if (ret != EM_SUCCESS) {
		LOGE("%s : Blocked to load TA(0x%08x)\n", __func__, ret);
		ret = -1;
		goto out;
	}*/

	if (qsee_is_ns_range(req_, reqlen)) {
		LOGE("req data is not in secure memory.\n");
		ret = -1;
		goto out;
	}

	if (qsee_is_ns_range(rsp_, rsplen)) {
		LOGE("rsp data is not in secure memory.\n");
		ret = -1;
		goto out;
	}

	if (reqlen != EM_STRUCT_REQ_PAYLOAD_SIZE) {
		LOGE("Unexpected reqlen(%u), should be(%u)\n", reqlen, (uint32_t)EM_STRUCT_REQ_PAYLOAD_SIZE);
		ret = -1;
		goto out;
	}

	if (rsplen != EM_STRUCT_RSP_PAYLOAD_SIZE) {
		LOGE("Unexpected rsplen(%u), should be(%u)\n", rsplen, (uint32_t)EM_STRUCT_RSP_PAYLOAD_SIZE);
		ret = -1;
		goto out;
	}

	req_buf_len = reqlen;
	req_buf = (uint8_t*)em_malloc(req_buf_len);
	if (req_buf == NULL) {
		LOGE("%s : TEE malloc failed\n", __func__);
		ret = -1;
		goto out;
	} else {
		memcpy(req_buf, (uint8_t *)req_, req_buf_len);
	}

	LOGW("Checking param done...\n");

	ret = em_context_make_request((uint8_t *)req_, ctx);
	if (ret != EM_SUCCESS) {
		LOGE("%s : Failed make context_request(0x%08x)\n", __func__, ret);
		goto make_msg;
	}

	ret = em_cmd_handler(ctx);
	if (ret != EM_SUCCESS) {
		LOGE("%s : Failed cmd processing(0x%08x)\n", __func__, ret);
		goto make_msg;
	}

make_msg:
	ret = em_context_make_response((uint8_t*)rsp_, ctx, ret);
	if (ret != EM_SUCCESS) {
		LOGE("%s : Failed make context_response(0x%08x)\n", __func__, ret);
		goto out;
	}

	ret = TEE_SUCCESS;
out:
	if (req_buf != NULL)
		free(req_buf);

	if (ctx != NULL) {
		memset(ctx, 0, sizeof(em_context));
		free(ctx);
	}

	LOGW("EngineeringMode TA Bye(0x%08x)\n", ret);
	return;
}

void tz_app_shutdown(void)
{
	/* App specific shutdown code*/
	LOGI("App shutdown\n");
	return;
}
