/*
 * @file app_main.c
 * @brief QUESTAPP handler entry point
 * Copyright (c) 2015, Samsung Electronics Corporation. All rights reserved.
 */
#include <comdef.h>
#include <qsee_services.h>
#include <qsee_log.h>
#include <qsee_heap.h>
#include "questapp_smdresult.h"

#define PAGE_SIZE (4096)
#define PAGE_MASK (~(PAGE_SIZE -1))

#define SMD_QUEST_CMD0_GET_RESULT         0
#define SMD_QUEST_CMD1_SET_RESULT         1

#define FAIL_CMD_BUF_TOO_SMALL_FOR_CMD_ID   -1
#define FAIL_CMD_RSP_BUFS_TOO_SMALL         -2
#define FAIL_CMD_BL_BOOT_COMPLETE           -3
#define FAIL_CMD_BUFFER_ALLOC_FAIL          -4
#define FAIL_UNDEFINED_COMMAND              -9

/**
 * Modify the app name to your specific app name
 */
static uint8_t qsee_log_mask;
/**
  @brief
    Add any app specific initialization code here
    QSEE will call this function after secure app is loaded and
    authenticated
*/
void tz_app_init(void)
{
  qsee_log_mask = qsee_log_get_mask();
  qsee_log_set_mask(QSEE_LOG_MSG_ERROR | QSEE_LOG_MSG_FATAL | QSEE_LOG_MSG_DEBUG);
  /*  App specific initialization code*/
  qsee_log(QSEE_LOG_MSG_DEBUG, "QUEST Init ");
}

void tz_constructor(void)
{
   qsee_log_mask = qsee_log_get_mask();
   qsee_log_set_mask(QSEE_LOG_MSG_ERROR | QSEE_LOG_MSG_FATAL | QSEE_LOG_MSG_DEBUG);
   qsee_log(QSEE_LOG_MSG_DEBUG, "QUEST constructor");
}

void tz_constructor2(void)
{
   qsee_log(QSEE_LOG_MSG_DEBUG, "QUEST constructor2");
}

void tz_destructor(void)
{
   qsee_log(QSEE_LOG_MSG_DEBUG, "QUEST destructor");
   qsee_log_set_mask(qsee_log_mask);
}

void tz_destructor2(void)
{
   qsee_log(QSEE_LOG_MSG_DEBUG, "QUEST destructor2");
}

/**
@brief
Data structure

@param[in]   cmd_id      Requested command
@param[in]   data        information (could be data or a pointer to the memory that holds the data
@param[in]   len         if data is ptr to some buffer, len indicates length of the buffer
@param[in]   test_buf_size  When running crypto test, this indicates the test packet size
*/

typedef struct quest_cmd{
	uint32_t cmd_id;
	uint64_t data;
} quest_cmd_t;

typedef struct quest_rsp {
	uint64_t data;
	int32_t status;
} quest_rsp_t;

/**
  @brief
    App specific command handler
    App executes code based on input command
*/
void tz_app_cmd_handler(void* cmd, uint32_t cmdlen,
                        void* rsp, uint32_t rsplen)
{
	uint32_t cmd_id = 0;
	uint32_t expected_cmdlen;
	uint32_t expected_rpslen;

	struct quest_cmd   *cmd_ptr = NULL;
	struct quest_rsp   *rsp_ptr = NULL;
	struct quest_rsp   *error_rsp = (struct quest_rsp *)rsp;

	qsee_log(QSEE_LOG_MSG_DEBUG, "questapp Handler start ");

	expected_cmdlen = sizeof(quest_cmd_t);
	expected_rpslen = sizeof(quest_rsp_t);

	if(cmdlen < expected_cmdlen || rsplen < expected_rpslen)
	{
	  qsee_log(QSEE_LOG_MSG_FATAL, "Cmd/rsp buffer len insufficient - %x, %x, expected - %x, %x, ERROR OUT", cmdlen, rsplen, expected_cmdlen, expected_rpslen);
	  goto out;
	}

	if(cmd == NULL || rsp == NULL)
	{
	  qsee_log(QSEE_LOG_MSG_FATAL, "Cmd/rsp buffer insufficient - %x, %x, ERROR OUT", cmd, rsp);
	  goto out;
	}

	cmd_ptr = (struct quest_cmd *)qsee_malloc(cmdlen);
	rsp_ptr = (struct quest_rsp *)qsee_malloc(rsplen);

	if (!cmd_ptr)
	{
	  qsee_log(QSEE_LOG_MSG_FATAL, "Command pointer equals NULL !!");
	  error_rsp->status = FAIL_CMD_BUFFER_ALLOC_FAIL;
	  goto out;
	}
	memset((void *)cmd_ptr, 0, cmdlen);	
	memcpy((void *)cmd_ptr, cmd, cmdlen);

	if (!rsp_ptr)
	{
	  qsee_log(QSEE_LOG_MSG_FATAL, "Command pointer equals NULL !!");
	  error_rsp->status = FAIL_CMD_BUFFER_ALLOC_FAIL;
	  goto out;
	}
	memset((void *)rsp_ptr, 0, rsplen);
	memcpy((void *)rsp_ptr, rsp, rsplen);

	/*Determine the command id*/
	/*We check if the command buffer is large enough to support the uint32 read for cmd_id*/
	/*It is assumed that the first member of the command buffer is the cmd_id*/
	if(cmdlen < sizeof(uint32))
	{
	  qsee_log(QSEE_LOG_MSG_FATAL, "Command buffer len insufficient for reading cmd_id, ERROR OUT");
	  rsp_ptr->status = FAIL_CMD_BUF_TOO_SMALL_FOR_CMD_ID;
	  goto out;
	}

	cmd_id = cmd_ptr->cmd_id;
	qsee_log(QSEE_LOG_MSG_DEBUG, "TZ App cmd handler, cmd_id = %d", cmd_id);

	switch(cmd_id)
	{
	  case SMD_QUEST_CMD0_GET_RESULT :
		  rsp_ptr->status = get_smd_quest_result_fuse(&(rsp_ptr->data));
		  break;
	  case SMD_QUEST_CMD1_SET_RESULT :
		  rsp_ptr->status = set_smd_quest_result_fuse(cmd_ptr->data);
		  break;
	  default :
		  rsp_ptr->status = FAIL_UNDEFINED_COMMAND;
		  qsee_log(QSEE_LOG_MSG_DEBUG, "Unsupported command: %d.  Test not yet implemented or commented out.", cmd_ptr->cmd_id);
	}

out:
	if(cmd_ptr)
		qsee_free(cmd_ptr);

	if(rsp_ptr) {
		memcpy(rsp, (void *)rsp_ptr, rsplen);
		qsee_free(rsp_ptr);
	}
	qsee_log(QSEE_LOG_MSG_DEBUG, "questapp Handler End");
}
/**
  @brief
    App specific shutdown
    App will be given a chance to shutdown gracefully
*/
void tz_app_shutdown(void)
{
  /* app specific shutdown code*/
  qsee_log(QSEE_LOG_MSG_DEBUG, "questapp shutdown");
  return;
}
