/*
 * StoreRTCTime_tl.c
 */

 #include "tlStd.h"
 #include "TlApi/TlApiTime.h"

#include <string.h>

#include "StoreRTCTime_tl.h"
#include "tz_arcounter_errors.h"
#include "tz_arcounter_defs.h"

#ifdef ICCC_v4
#include "icccOperations_v4.h"
#else
#include "icccOperations.h"
#endif

uint32_t process_StoreRTCTime(
	tl_arcounter_ctx_t * ctx,
	tz_arcounter_storertctime_payload_t * sendmsg,
	tz_arcounter_storertctime_payload_t * respmsg,
	uint8_t beEnable
)
{
	uint32_t ret = RET_TL_TZ_ARCOUNTER_INTERNAL_ERR;
	TEE_Result tee_ret = TEE_SUCCESS;
	uint32_t iccc_ret;
	int rpmb_ret;

	uint8_t rpmb_buffer[TZ_RPMB_ARCOUNTER_BLOCK_SIZE];
	TEE_Time curr_time;
	TEE_Time pers_time;
	uint32_t ref_time = 0x0;
	uint32_t old_ref_time = 0x0;
	uint32_t old_tz_time = 0x0;
	int32_t delta = 0x0;
	uint32_t tz_time = 0x0;
	uint8_t unwrapped_cache_buff[MAX_ARCOUNTER_WRAP_BUFFER] = {0x0};
	uint32_t cached_ref_time = 0;
	uint32_t cached_tz_time = 0;
	uint8_t flag = 0x0;
	uint32_t status = 0x0;

	TTY_LOG("TL_TZ_ARCOUNTER: process_StoreRTCTime: entering");
	respmsg->payload.resp.return_code = TZ_ARCOUNTER_INTERNAL_ERROR;

	if (sendmsg->payload.cmd.boot_time > TZ_ARCOUNTER_MAX_REF_TIME) {
		TTY_LOG("TL_TZ_ARCOUNTER: boot_time is bigger than MAX time");
		ret = TZ_ARCOUNTER_WRONG_DATA;
		goto exit;
	}

	rpmb_ret = arcounter_rpmb_read(0, rpmb_buffer);
	if (rpmb_ret != ARCOUNTER_RPMB_SUCCESS) {
		respmsg->payload.resp.return_code = rpmb_ret;
		TTY_LOG("TL_TZ_ARCOUNTER: rpmb read failed 0x%x", rpmb_ret);
		goto exit;
	}

	memcpy(&flag, rpmb_buffer+ENABLE_FLAG_OFFSET, ENABLE_FLAG_SIZE);
	if (beEnable) {
		if (flag == 1) {
			TTY_LOG("TZ_ARCOUNTER: arcounter is already enabled");
			respmsg->payload.resp.return_code = TZ_ARCOUNTER_ALREADY_ENABLED;
			ret = RET_TL_TZ_ARCOUNTER_OK;
			goto exit;
		}
		flag = 1;
		memcpy(rpmb_buffer+ENABLE_FLAG_OFFSET, &flag, ENABLE_FLAG_SIZE);
	}
	else {
		if (flag != 1) {
			TTY_LOG("TZ_ARCOUNTER: arcounter is not enabled");
			respmsg->payload.resp.return_code = TZ_ARCOUNTER_SUCCESS;
			goto exit;
		}
	}

	if (get_attn(ATTN_SC_STATUS, &status) == ICCC_SUCCESS) {
		if (status == SC_ENABLED) {
		TTY_LOG("TZ_ARCOUNTER: arcounter is already enabled");
			respmsg->payload.resp.return_code = TZ_ARCOUNTER_ALREADY_ENABLED;
			goto exit;
		}
	}
	else {
		TTY_LOG("TZ_ARCOUNTER: get status is failed");
		goto exit;
	}

	if (sendmsg->payload.cmd.cache_size == MAX_ARCOUNTER_WRAP_BUFFER) {
		uint32_t temp_size = MAX_ARCOUNTER_WRAP_BUFFER;
		ret = unwrap_time(sendmsg->payload.cmd.cached_time, sendmsg->payload.cmd.cache_size, unwrapped_cache_buff, &temp_size);
		if (TEE_SUCCESS != ret) {
			TTY_LOG("TL_TZ_ARCOUNTER: failed to wrap cached time 0x%x", ret);
			cached_ref_time = 0;
			cached_tz_time = 0;
		}
	  else {
		  memcpy(&cached_ref_time, unwrapped_cache_buff, REF_TIME_SIZE);
		  memcpy(&cached_tz_time, unwrapped_cache_buff+REF_TIME_SIZE, TZ_TIME_SIZE);
#ifdef DEBUG
		  TTY_LOG("TL_TZ_ARCOUNTER: temp_size : 0x%x", temp_size);
		  TTY_LOG("TL_TZ_ARCOUNTER: cached_ref_time : 0x%x", cached_ref_time);
		  TTY_LOG("TL_TZ_ARCOUNTER: cached_tz_time : 0x%x", cached_tz_time);
#endif
		}
	}

	memcpy(&old_ref_time, rpmb_buffer+REF_TIME_OFFSET, REF_TIME_SIZE);
	memcpy(&delta, rpmb_buffer+DELTA_OFFSET, DELTA_SIZE);
	memcpy(&old_tz_time, rpmb_buffer+TZ_TIME_OFFSET, TZ_TIME_SIZE);

	if (old_ref_time == 0xffffffff) {
		old_ref_time = 0;
	}
	if (delta == 0xffffffff) {
		delta = 0;
	}
	if (old_tz_time == 0xffffffff) {
		old_tz_time = 0;
	}
#ifdef DEBUG
	TTY_LOG("TL_TZ_ARCOUNTER: old ref.time : 0x%x", old_ref_time);
	TTY_LOG("TL_TZ_ARCOUNTER: delta : 0x%x", delta);
	TTY_LOG("TL_TZ_ARCOUNTER: old_tz_time : 0x%x", old_tz_time);
	TTY_LOG("TL_TZ_ARCOUNTER: cached_time : 0x%x", cached_ref_time);
#endif
	if (cached_ref_time > old_ref_time) {
		old_ref_time = cached_ref_time;
	}
	if (cached_tz_time > old_tz_time) {
		old_tz_time = cached_tz_time;
	}

	TTY_LOG("TL_TZ_ARCOUNTER: boot_time : %d 0x%x", sendmsg->payload.cmd.boot_time, sendmsg->payload.cmd.boot_time);
	TEE_GetSystemTime(&curr_time);
#if 0
	pers_time.seconds = 0;
	pers_time.millis = 0;
	if (TEE_SUCCESS != (tee_ret = TEE_GetTAPersistentTime(&pers_time))) {
		TTY_LOG("TL_TZ_ARCOUNTER: TEE_GetTAPersistentTime failed tee_ret : %d", tee_ret);
		tee_ret = TEE_SetTAPersistentTime(&curr_time);
	}
  TTY_LOG("TL_TZ_ARCOUNTER: pers_time : sec %d", pers_time.seconds);
#endif
#ifdef DEBUG
	TTY_LOG("TL_TZ_ARCOUNTER: tee_ret : %d", tee_ret);
	TTY_LOG("TL_TZ_ARCOUNTER: curr_time : sec %d", curr_time.seconds);

#endif
	ref_time = sendmsg->payload.cmd.boot_time + delta;
	delta = ref_time - sendmsg->payload.cmd.boot_time;
	tz_time = curr_time.seconds;

	if (ref_time > TZ_ARCOUNTER_MAX_REF_TIME || sendmsg->payload.cmd.boot_time > ref_time) {
		ref_time = TZ_ARCOUNTER_MAX_REF_TIME;
	}
	else if (old_ref_time > ref_time) {
		ref_time = old_ref_time;
	}

	memcpy(rpmb_buffer+REF_TIME_OFFSET, &ref_time, REF_TIME_SIZE);
	memcpy(rpmb_buffer+DELTA_OFFSET, &delta, DELTA_SIZE);
	memcpy(rpmb_buffer+TZ_TIME_OFFSET, &tz_time, TZ_TIME_SIZE);

	rpmb_ret = arcounter_rpmb_write(0, rpmb_buffer);
	if (rpmb_ret != ARCOUNTER_RPMB_SUCCESS) {
		respmsg->payload.resp.return_code = rpmb_ret;
		TTY_LOG("TL_TZ_ARCOUNTER: rpmb write (boot_time) failed 0x%x", rpmb_ret);
		goto exit;
	}

	respmsg->payload.resp.return_code = TZ_ARCOUNTER_SUCCESS;
	ret = RET_TL_TZ_ARCOUNTER_OK;

	if (set_attn(ATTN_SC_REF_TIME, ref_time) == ICCC_SUCCESS) {
		TTY_LOG("TL_TZ_ARCOUNTER: ref_time is updated to attn.");
	}

	if (beEnable && set_attn(ATTN_SC_STATUS, SC_ENABLED)) {
		TTY_LOG("TL_TZ_ARCOUNTER: sc status is updated to attn.");
	}
#ifdef DEBUG
	memset(rpmb_buffer, 0, TZ_RPMB_ARCOUNTER_BLOCK_SIZE);
	rpmb_ret = arcounter_rpmb_read(0, rpmb_buffer);
	if (rpmb_ret != ARCOUNTER_RPMB_SUCCESS) {
		respmsg->payload.resp.return_code = rpmb_ret;
		TTY_LOG("TL_TZ_ARCOUNTER: rpmb read (old ref.time) failed 0x%x", rpmb_ret);
		goto exit;
	}

	memcpy(&ref_time, rpmb_buffer, 4);
	memcpy(&delta, rpmb_buffer+4, 4);
	memcpy(&tz_time, rpmb_buffer+8, 4);

	TTY_LOG("StoreRTCTime DEBUG LOG");
	TTY_LOG("TL_TZ_ARCOUNTER: ref.time : 0x%x", ref_time);
	TTY_LOG("TL_TZ_ARCOUNTER: delta : 0x%x", delta);
	TTY_LOG("TL_TZ_ARCOUNTER: tz time : 0x%x", tz_time);
	TTY_LOG("TL_TZ_ARCOUNTER: diff : 0x%x", ref_time - tz_time);
#endif
exit:
	return ret;
}
