/**
 * @file tee_sys.c
 * @brief GP System API implementation for qsee
 * @author Iaroslav Makarchuk (i.makarchuk@samsung.com)
 * @date Created Oct 3, 2016
 * @par In Samsung Ukraine R&D Center (SURC) under a contract between
 * @par LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * @par "Samsung Elecrtronics Co", Ltd (Seoul, Republic of Korea)
 * @par Copyright: (c) Samsung Electronics Co, Ltd 2015. All rights reserved.
 *
 * This software is proprietary of Samsung Electronics.
 * No part of this software, either material or conceptual may be copied
 * or distributed, transmitted, transcribed, stored in a retrieval system
 * or translated into any human or computer language in any form by any means,
 * electronic, mechanical, manual or otherwise, or disclosed to third parties
 * without the express written permission of Samsung Electronics.
 */

#include <tee_internal_api.h>

#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include <tees_log.h>
#include <tees_mem.h>

#include <qsee_heap.h>
#include <qsee_timer.h>

#define USEC_PER_MILLIS  1000
#define MILLIS_PER_SEC   1000
#define USEC_PER_SEC     1000000

static void *g_instance_data = NULL;

extern void qsee_err_fatal(void) __attribute__ ((noreturn));

void TEE_SetInstanceData(void *instanceData) {
  g_instance_data = instanceData;
}

void *TEE_GetInstanceData(void) {
  return g_instance_data;
}

void *TEE_Malloc(uint32_t size, uint32_t hint) {
  void *retval = NULL;

  retval = qsee_malloc(size);

  if (retval && HINT_FILL_WITH_ZEROS == hint) {
    memset(retval, 0x00, size);
  }

  return retval;
}

void *TEE_Realloc(const void *buffer, uint32_t newSize) {
#ifdef USE_QSEE_REALLOC
  // Only msm8996+ devices support this feature
  return qsee_realloc((void *)buffer, newSize);

#else
  (void)buffer;
  (void)newSize;
  return NULL;
#endif
}

void TEE_Free(void *buffer) {
  qsee_free(buffer);
}

void TEE_MemMove(void *dest, const void *src, uint32_t size) {
  memmove(dest, src, size);
}

int32_t TEE_MemCompare(const void *buffer1,
                       const void *buffer2,
                       uint32_t size) {
  return memcmp(buffer1, buffer2, size);
}

void TEE_MemFill(void *buffer, uint32_t x, uint32_t size) {
  memset(buffer, x, size);
}

void TEE_GetSystemTime(TEE_Time *time) {
  unsigned long long uptime = qsee_get_uptime();

  time->seconds = uptime / MILLIS_PER_SEC;
  time->millis = uptime % MILLIS_PER_SEC;
}

void _TEE_Panic(TEE_Result panic_code, const char *szSrcFuncName,
                int nSrcFileLine) {
  TEES_LOG(TEES_LOG_LEVEL_ERROR, "TEE_Panic(%x) in %s:%d\n",
           panic_code, szSrcFuncName, nSrcFileLine);
  qsee_err_fatal();
}

/* The below function is not present in some of qsee implementations */
void *secure_memset(void *ptr, int value, size_t len) __attribute__ ((weak));

void *secure_memset(void *ptr, int value, size_t len) {
  if (ptr) {
    memset(ptr, value, len);
  }
  return ptr;
}

