/*
 * Copyright (c) 2019, 2022 Qualcomm Technologies, Inc.
 * All Rights Reserved.
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 */

/* ----------------------------------------------------------------------------
 *   Includes
 * ---------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>

#include "tee_client_api.h"
#include "common.h"
#include "run_gp_basic.h"

#define BUFFER_SIZE 4096

// This is defined externally in ca_main.c
extern TEEC_UUID example_gpapp_ta_uuid;

/* ----------------------------------------------------------------------------
 *   Example basic Operation(s)
 * ---------------------------------------------------------------------------- */
/**
 * This function shows how to:
 *  1. Open a context
 *  2. Open a session to the GP TA
 *  3. Allocate a shared memory buffer
 *  4. Perform a multiplication on the shared memory buffer, each element is multiplied with value.a
 *  5. Print the result
 *  6. Release the shared memory
 *  7. Close the session
 *  8. Finalize the context
 */
TEEC_Result run_invoke_multiplyHLOSBuffer(void)
{
  TEEC_Context context = {0};
  TEEC_Session session = {0};
  TEEC_Operation operation = {0};
  TEEC_SharedMemory sharedMem = {0};
  TEEC_Result result = TEEC_ERROR_GENERIC;
  uint32_t returnOrigin = 0xFFFFFFFF;

  printf("+ Run Invoke Multiplication on HLOS Buffer \n");
  do {
    printf("1. Open a context\n");
    result = TEEC_InitializeContext(NULL, &context);
    if (result != TEEC_SUCCESS) {
      printf("Initialize context failed, ret = 0x%X.\n", result);
      break;
    }

    printf("2. Open a session\n");
    result = TEEC_OpenSession(
      &context, &session, &example_gpapp_ta_uuid, TEEC_LOGIN_USER, NULL, NULL, &returnOrigin);
    if (result != TEEC_SUCCESS) {
      printf("Open a session failed, ret = 0x%X.\n", result);
      break;
    }

    // Allocate shared memory
    sharedMem.size = BUFFER_SIZE;
    sharedMem.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;

    printf(
      "3. Allocate a shared buffer: size = 0%zX, flags = 0x%X \n", sharedMem.size, sharedMem.flags);
    result = TEEC_AllocateSharedMemory(&context, &sharedMem);
    if (result != TEEC_SUCCESS) {
      printf("Allocate shared memory failed, ret = 0x%X.\n", result);
      break;
    }

    // Initialize shared buffer to all 1's
    memset(sharedMem.buffer, 0x1, sharedMem.size);

    // Setup operation
    operation.paramTypes =
      TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_PARTIAL_INOUT, TEEC_NONE, TEEC_NONE);
    operation.params[0].value.a = 0x2A;
    operation.params[1].memref.parent = &sharedMem;
    operation.params[1].memref.offset = 0;
    operation.params[1].memref.size = BUFFER_SIZE;

    // Request multiply on the shared memory
    printf("4. Request multiplication on the shared buffer(every 1 byte) by 0x%X\n",
           operation.params[0].value.a);
    result =
      TEEC_InvokeCommand(&session, EXAMPLE_MULTIPLY_HLOS_BUFFER_CMD, &operation, &returnOrigin);
    if (result != TEEC_SUCCESS) {
      printf("Invoking TA failed, ret = 0x%X.\n", result);
      break;
    }

    // Print one byte of the resulted buffer as an example purpose
    printf("*5. Resulted buffer[0] = 0x%2X\n", ((uint8_t const *)sharedMem.buffer)[0]);

  } while (0);

  // Free resources
  if (sharedMem.imp != NULL) {
    printf("6. Release the shared buffer\n");
    TEEC_ReleaseSharedMemory(&sharedMem);
  }
  if (session.imp != NULL) {
    printf("7. Close the session\n");
    TEEC_CloseSession(&session);
  }
  if (context.imp != NULL) {
    printf("8. Finalize the context\n");
    TEEC_FinalizeContext(&context);
  }

  printf("- Run Invoke Multiplication on HLOS Buffer\n\n");

  return result;
}
