/**
 * @file tee_param_utils.c
 * @brief Utility functionality for parsing/filling protocol data in SWd
 * implementation
 * @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_param_utils.h>

#include <protocol.h>

/* Needed for max sharedmem size */
#ifdef MB_QSEE
#include <tee_client_api.h>
#endif

#ifdef MB_TBASE
#include "tlStd.h"
#include "TlApi/TlApi.h"
#endif

uint32_t GetParamType(uint32_t param_index, uint32_t param_types) {
  uint32_t mask = 0xF << (param_index * 4);

  return (param_types & mask) >> (param_index * 4);
}

TEE_Result FillCommandArgs(uint32_t param_types, ProtocolCmd *command,
                           TEE_Param params[PARAMS_NUM]) {
  TEE_Result ret = TEE_SUCCESS;
  uint32_t i = 0;

  if (!command) {
    ret = TEE_ERROR_BAD_PARAMETERS;
    goto exit;
  }

  for (i = 0; i < PARAMS_NUM; i++) {
    switch (GetParamType(i, param_types)) {
      case TEE_PARAM_TYPE_VALUE_OUTPUT:
      case TEE_PARAM_TYPE_VALUE_INOUT: {
        command->params[i].value.a = params[i].value.a;
        command->params[i].value.b = params[i].value.b;
        break;
      }
      case TEE_PARAM_TYPE_MEMREF_OUTPUT:
      case TEE_PARAM_TYPE_MEMREF_INOUT: {
        command->params[i].memref.size = params[i].memref.size;
        break;
      }
      case TEE_PARAM_TYPE_NONE:
      case TEE_PARAM_TYPE_MEMREF_INPUT:
      case TEE_PARAM_TYPE_VALUE_INPUT: {
        break;
      }
      default: {
        ret = TEE_ERROR_NOT_SUPPORTED;
        goto exit;
      }
    }
  }

exit:
  return ret;
}

TEE_Result FillParamValues(uint32_t param_types, TEE_Param params[4],
                           ProtocolCmd *command) {
  TEE_Result ret = TEE_SUCCESS;
  uint32_t i = 0;

  if (!command) {
    ret = TEE_ERROR_BAD_PARAMETERS;
    goto exit;
  }

  for (i = 0; i < PARAMS_NUM; i++) {
    switch (GetParamType(i, param_types)) {
      case TEE_PARAM_TYPE_VALUE_INPUT:
      case TEE_PARAM_TYPE_VALUE_INOUT: {
        params[i].value.a = command->params[i].value.a;
        params[i].value.b = command->params[i].value.b;
        break;
      }
      case TEE_PARAM_TYPE_MEMREF_OUTPUT:
      case TEE_PARAM_TYPE_MEMREF_INPUT:
      case TEE_PARAM_TYPE_MEMREF_INOUT: {
        if (!command->params[i].memref.buffer) {
          params[i].memref.buffer = command->param_buffers[i];
        } else {
#ifndef MB_QSEE

          /* For t-base and emulator we assume command->params[i].memref.buffer to be a
           * mapped pointer.
           */
#ifdef MB_TBASE
          if (!tlApiIsNwdBufferValid((void *)(uintptr_t)command->params[i].memref.buffer,
                                     command->params[i].memref.size)) {
            ret = TEE_ERROR_BAD_PARAMETERS;
            goto exit;
          }
#endif

          void *aux_ptr = (void *)&(params[i].memref.buffer);
          uint32_t *ptr = aux_ptr;
          *ptr = command->params[i].memref.buffer;
#else

          /* For QSEE we assume command->params[i].memref.buffer to be
           * an offset from the beginning of ion_sbuffer.
           */
          uint8_t *ptr = (uint8_t *)command;

          /* Check if the offset is valid (buffer for shared memory goes
           * right after ProtocolCmd and has size
           * MAX_SHAREDMEM_SIZE): */
          if (command->params[i].memref.buffer < sizeof(ProtocolCmd) ||
              command->params[i].memref.buffer >
                (sizeof(ProtocolCmd) + MAX_SHAREDMEM_SIZE)) {
            ret = TEE_ERROR_BAD_PARAMETERS;
            goto exit;
          }

          ptr += command->params[i].memref.buffer;
          params[i].memref.buffer = ptr;
#endif
        }

        params[i].memref.size = command->params[i].memref.size;
        break;
      }
      case TEE_PARAM_TYPE_NONE:
      case TEE_PARAM_TYPE_VALUE_OUTPUT: {
        break;
      }
      default: {
        ret = TEE_ERROR_NOT_SUPPORTED;
        goto exit;
      }
    }
  }

exit:
  return ret;
}

