/*
 * @file app_main.c
 * @brief BKSECAPP 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 "bksecapp_fuse_location.h"
#include "bksecapp_wrap_unrap.h"
#include "bksecapp_bl_boot_complete.h"
#include "bksecapp_anti-rollback.h"
#include "bksecapp_secboot.h"
#include "bksecapp_trustedboot.h"
#include "bksecapp_em_fuse.h"
#include "bksecapp_warranty.h"
#include "bksecapp_rpmb.h"
#include "bksecapp_kaslr.h"

#define PAGE_SIZE (4096)
#define PAGE_MASK (~(PAGE_SIZE -1))

#define SEC_BOOT_CMD0_GET_WARRANTY_BIT         0
#define SEC_BOOT_CMD1_SET_WARRANTY_BIT         1
#define SEC_BOOT_CMD7_GET_RP_ENABLE            7
#define SEC_BOOT_CMD8_GET_RP_IGNORE            8
#if 0
#define SEC_BOOT_CMD9_SET_ICCC_BL_DATA         9   // not support
#define SEC_BOOT_CMD10_SET_ICCC_ROT_BL_DATA    10  // not support
#define SEC_BOOT_CMD33_SET_ICCC_SVB_BL_DATA    33 // not support
#define SEC_BOOT_CMD35_SET_ICCC_KERN_DATA      35 // not support
#endif
#define SEC_BOOT_CMD11_IS_SECBOOT_ENABLE       11
#define SEC_BOOT_CMD12_STORE_MEASURE           12
#define SEC_BOOT_CMD13_GET_RP_COUNT_XBL        13
#define SEC_BOOT_CMD14_GET_RP_COUNT_PIL        14
#define SEC_BOOT_CMD15_GET_RP_COUNT_RPM        15
#define SEC_BOOT_CMD16_GET_RP_COUNT_TZ         16
#define SEC_BOOT_CMD17_GET_RP_COUNT_HYP        17
#define SEC_BOOT_CMD18_GET_RP_COUNT_DP         18
#define SEC_BOOT_CMD19_GET_RP_COUNT_DEV_CFG    19
#define SEC_BOOT_CMD20_GET_RP_COUNT_ABL        20
#define SEC_BOOT_CMD21_GET_RPMB_FUSE           21
#define SEC_BOOT_CMD22_GET_RP_COUNT_PMIC       22
#define SEC_BOOT_CMD24_GET_EK_FUSE             24
#define SEC_BOOT_CMD25_SET_EK_FUSE_DEV         25
#define SEC_BOOT_CMD26_SET_EK_FUSE_USER        26
#define SEC_BOOT_CMD27_SET_EK_FUSE_FORCE_USER  27
#define SEC_BOOT_CMD28_SET_BL_BOOT_COMPLETE    28
#define SEC_BOOT_CMD29_WRAP_KEY_DATA           29
#define SEC_BOOT_CMD30_UNWRAP_KEY_DATA         30
#define SEC_BOOT_CMD31_GET_MEM_ACC_FUSE        31
#define SEC_BOOT_CMD32_GET_RP_COUNT_XBL_CONFIG 32
#define SEC_BOOT_CMD34_SET_VBMETA_DIGEST       34
#define SEC_BOOT_CMD36_STORE_RPMB_DATA         36
#define SEC_BOOT_CMD37_READ_RPMB_DATA          37
#define SEC_BOOT_CMD100_SET_KASLR_DATA	       100
#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
 */
char TZ_APP_NAME[] = {"bksecapp"};

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, "BKSECAPP Init ");
}

/**
@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 send_cmd{
	uint32 cmd_id;
	union {
		trusted_boot_bl_status_t bl_secure_info3;
		wrap_unwrap_key_status_t bl_secure_info_key;
		kaslr_bl_status_t bl_secure_info2;
		rpmb_data_t rpmb_data;
	} data;
} send_cmd_t;

typedef struct send_cmd_rsp {
	union {
		uint32 data;
		wrap_unwrap_key_status_t wrapdata;
		rpmb_data_t rpmb_data;
	} data;
	int32 status;
} send_cmd_rsp_t;


void BK_Hex_dumpss(uint8_t* log_ptr, uint32_t log_size)
{
	int i = 0;
	for(i = 0; i < log_size; i+=16)
	{
		qsee_log(QSEE_LOG_MSG_FATAL,"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x"
			,log_ptr[i+0],log_ptr[i+1],log_ptr[i+2],log_ptr[i+3]
			,log_ptr[i+4],log_ptr[i+5],log_ptr[i+6],log_ptr[i+7]
			,log_ptr[i+8],log_ptr[i+9],log_ptr[i+10],log_ptr[i+11]
			,log_ptr[i+12],log_ptr[i+13],log_ptr[i+14],log_ptr[i+15]);
	}
}

/**
  @brief
    App specific command handler
    App executes code based on input command
*/
void tz_app_cmd_handler(void* cmd, uint32 cmdlen,
                        void* rsp, uint32 rsplen)
{
	uint32 cmd_id = 0;
	uint32 expected_cmdlen;
	uint32 expected_rpslen;

	struct send_cmd       *cmd_ptr = NULL;
	struct send_cmd_rsp   *rsp_ptr = NULL;
	struct send_cmd_rsp   *error_rsp = (struct send_cmd_rsp *)rsp;


	qsee_log(QSEE_LOG_MSG_DEBUG, "BKSECAPP Handler start ");

	expected_cmdlen = sizeof(send_cmd_t);
	expected_rpslen = sizeof(send_cmd_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 send_cmd *)qsee_malloc(cmdlen);
	rsp_ptr = (struct send_cmd_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);

	if(get_bl_boot_complete() != BL_BOOT_NOT_COMPLETE) {
		qsee_log(QSEE_LOG_MSG_FATAL, "BL boot completed. Operation not allowed! cmd_id = %d", cmd_id);
		rsp_ptr->status = FAIL_CMD_BL_BOOT_COMPLETE;
		goto out;
	}

	switch(cmd_id)
	{
	  case SEC_BOOT_CMD0_GET_WARRANTY_BIT :
		  rsp_ptr->status = get_warranty_bit_fuse();
		  break;
	  case SEC_BOOT_CMD1_SET_WARRANTY_BIT :
		  rsp_ptr->status = set_warranty_bit_fuse();
		  break;
	  case SEC_BOOT_CMD7_GET_RP_ENABLE :
		  rsp_ptr->status = get_anti_rollback_en();
		  break;
	  case SEC_BOOT_CMD8_GET_RP_IGNORE :
		  rsp_ptr->status = get_anti_rollback_ignore();
		  break;
	  case SEC_BOOT_CMD11_IS_SECBOOT_ENABLE :
		  rsp_ptr->status = is_secboot_enable();
		  break;
/* svb isn't used 		  
	  case SEC_BOOT_CMD12_STORE_MEASURE :
		  rsp_ptr->status = store_measure((void*)&cmd_ptr->data.bl_secure_info3);
		  break;
*/
	  case SEC_BOOT_CMD13_GET_RP_COUNT_XBL :
		  rsp_ptr->status = get_anti_rollback_xbl_ver();
		  break;
	  case SEC_BOOT_CMD14_GET_RP_COUNT_PIL :
		  rsp_ptr->status = get_anti_rollback_pil_ver();
		  break;
	  case SEC_BOOT_CMD15_GET_RP_COUNT_RPM :
		  rsp_ptr->status = get_anti_rollback_rpm_ver(); // For aop image RP count check
		  break;
	  case SEC_BOOT_CMD16_GET_RP_COUNT_TZ :
		  rsp_ptr->status = get_anti_rollback_tz_ver();
		  break;
	  case SEC_BOOT_CMD17_GET_RP_COUNT_HYP :
		  rsp_ptr->status = get_anti_rollback_hyp_ver();
		  break;
	  case SEC_BOOT_CMD18_GET_RP_COUNT_DP :
		  rsp_ptr->status = get_anti_rollback_dp_ver();
		  break;
	  case SEC_BOOT_CMD19_GET_RP_COUNT_DEV_CFG :
		  rsp_ptr->status = get_anti_rollback_dev_cfg_ver();
		  break;
	  case SEC_BOOT_CMD20_GET_RP_COUNT_ABL:
		  rsp_ptr->status = get_anti_rollback_pil_ver();  // RP version bits shared with PIL
		  break;
	  case SEC_BOOT_CMD21_GET_RPMB_FUSE:
		  rsp_ptr->status = get_rpmb_fuse();
		  break;
	  case	SEC_BOOT_CMD22_GET_RP_COUNT_PMIC:
		  rsp_ptr->status = get_anti_rollback_xbl_ver();  // RP version bits shared with XBL
		  break;
	  case	SEC_BOOT_CMD32_GET_RP_COUNT_XBL_CONFIG:
		  rsp_ptr->status = get_anti_rollback_xbl_config_ver();
		  break;
	  case SEC_BOOT_CMD24_GET_EK_FUSE :
		  rsp_ptr->status = get_ek_fuse();
		  break;
	  case SEC_BOOT_CMD25_SET_EK_FUSE_DEV :
		  rsp_ptr->status = set_ek_fuse(EK_FUSE_DEV);
		  break;
	  case SEC_BOOT_CMD26_SET_EK_FUSE_USER :
		  rsp_ptr->status = set_ek_fuse(EK_FUSE_USER);
		  break;
	  case SEC_BOOT_CMD27_SET_EK_FUSE_FORCE_USER :
		  rsp_ptr->status = get_ek_fuse();
		  if(rsp_ptr->status == EK_FUSE_DEV)
			  rsp_ptr->status = set_ek_fuse(EK_FUSE_FORCE_USER);
		  else
			  qsee_log(QSEE_LOG_MSG_DEBUG, "[EM] Fail to force EK_FUSE_USER %d", rsp_ptr->status);
		  break;
	  case SEC_BOOT_CMD28_SET_BL_BOOT_COMPLETE:
		  rsp_ptr->status = set_bl_boot_complete();
		  break;
	  case SEC_BOOT_CMD29_WRAP_KEY_DATA:
		  rsp_ptr->status = bk_wrap_function((void*)&cmd_ptr->data.bl_secure_info_key,(void*)&rsp_ptr->data.wrapdata);
		  break;
	  case SEC_BOOT_CMD30_UNWRAP_KEY_DATA:
		  rsp_ptr->status = bk_unwrap_function((void*)&cmd_ptr->data.bl_secure_info_key,(void*)&rsp_ptr->data.wrapdata);
		  break;
	  case SEC_BOOT_CMD34_SET_VBMETA_DIGEST :
		  rsp_ptr->status = store_vbmeta((void*)&cmd_ptr->data.bl_secure_info3);
		  break;
	  case SEC_BOOT_CMD36_STORE_RPMB_DATA :
		  rsp_ptr->status = bksecapp_rpmb_write((void*)&cmd_ptr->data.rpmb_data);
		  break;
	  case SEC_BOOT_CMD37_READ_RPMB_DATA :
		  rsp_ptr->status = bksecapp_rpmb_read((void*)&rsp_ptr->data.rpmb_data);
		  break;
	  case SEC_BOOT_CMD100_SET_KASLR_DATA :
		  rsp_ptr->status = set_kaslr_flag((void*)&cmd_ptr->data.bl_secure_info2);
		  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, "BKSECAPP 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, "BKSECAPP shutdown");
  return;
}
