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

#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

#include "alog.h"
#include "map_trusted_application.h"
#include "object.h"
#include "qtee_init.h"  // QTEE off-target environment initialization
#include "smci_skeleton.h"
#include "stringl.h"

/* Similar to Android LOG_TAG, define a tag that appears when logging from this
 * application */
static char const LOG_TAG[] = "SMCInvoke_skeleton_CA";

/* This function builds the path to our TA using strlcpy(), using the TA name
 * SMCI_SKELETON_TA_NAME - this is defined in the TA SConscript.
 *
 * Returns the path on success and NULL on failure.
 */
static char const *create_image_path(void)
{
/* ensure PATH_MAX is defined */
#if !defined(PATH_MAX)
#define PATH_MAX 4096
#endif

  static const char testTAName[] = SMCI_SKELETON_TA_NAME;
  static char imageName[PATH_MAX];

  /* TA_PATH_DEFINE is defined in the offtarget client app builder. */
  if (strlcpy(imageName, TA_PATH_DEFINE, sizeof(imageName)) >= sizeof(imageName)) {
    goto bail;
  }

  if (strlcat(imageName, testTAName, sizeof(imageName)) >= sizeof(imageName)) {
    goto bail;
  }

  if (strlcat(imageName, ".so", sizeof(imageName)) >= sizeof(imageName)) {
    goto bail;
  }

  return imageName;

bail:
  ALOGE("TA image path does not fit in buffer with size: %zu!", sizeof(imageName));
  return NULL;
}

int main(void)
{
  int ret = Object_ERROR;         // Return value for qtee_emu calls
  int exampleRet = Object_ERROR;  // Return value for these examples

  ta_image_data img_data = {0};   // A struct containing information from map_trusted_application

  /*
   * Initialize QTEEEmu.
   *
   * A null pointer can be passed to use the default settings. Alternatively, a path to a JSON file
   * specifying desired settings can be provided. See 'qtee_init.h'.
   */
  ret = qtee_emu_init(NULL);
  if (ret) {
    ALOGE("QTEE Emu initialization failed with %d!", ret);
    return ret;
  }

  ALOGV("QTEE Emu initialized.");

  /* Before we can load our TA, we have to load it into a buffer. */
  const char *imageName = create_image_path();
  if (!imageName) {
    ALOGE("Failed to create TA image path!");
    ret = Object_ERROR;
    goto cleanup;
  }

  /* Here we call map_trusted_application, which maps the TA specified in the path we created
   * into a buffer inside img_data. */
  ret = map_trusted_application(imageName, &img_data);

  if (ret) {
    ALOGE("Error mapping TA!");
    memset(&img_data, 0, sizeof(img_data));
    ret = Object_ERROR;
    goto cleanup;
  }

  /* Run the SMCInvoke skeleton example from smci_skeleton.c */
  exampleRet = run_smcinvoke_ta_example(&img_data);

  if (exampleRet) {
    ALOGE("Errors were encountered during execution: %d!", exampleRet);
  } else {
    ALOGD("CA executed successfully.");
  }

cleanup:
  unmap_trusted_application(&img_data);

  ret = qtee_emu_deinit();
  if (ret) {
    ALOGE("Error occurred during QTEE Emu deinit: %d!", ret);
  }
  return (ret || exampleRet);
}

