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

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

#include "CAppLoader.h"
#include "IAppController.h"
#include "IAppLoader.h"
#include "IClientEnv.h"
#include "ISMCIExample.h"
#include "TZCom.h"
#include "map_trusted_application.h"
#include "object.h"

#include "alog.h"
#include "smci_skeleton.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 demonstrates how to open a TA using SMCInvoke APIs. */
int32_t run_smcinvoke_ta_example(ta_image_data *img_data)
{
  int32_t ret = Object_OK;

  Object clientEnv = Object_NULL;      // A Client Environment that can be used to
                                       // get an IAppLoader object
  Object appLoader = Object_NULL;      // IAppLoader object that allows us to load
                                       // the TA in the trusted environment
  Object appController = Object_NULL;  // AppController contains a reference to
                                       // the app itself, after loading
  Object appObj = Object_NULL;         // An interface to our TA that allows us to send
                                       // commands to it.
  uint32_t val1 = 2;
  uint32_t val2 = 5;
  uint32_t addResult = 0;

  /* Before we can obtain an AppLoader object, a ClientEnv object is required
   * from the emulated TZ daemon. */
  ret = TZCom_getClientEnvObject(&clientEnv);

  if (Object_isERROR(ret)) {
    ALOGE("Failed to obtain clientenv from TZCom!");
    clientEnv = Object_NULL;
    goto cleanup;
  }

  /* Using the ClientEnv object we retrieved, obtain an appLoader by
   * specifying its UID */
  ret = IClientEnv_open(clientEnv, CAppLoader_UID, &appLoader);
  if (Object_isERROR(ret)) {
    ALOGE("Failed to get apploader object with %d!", ret);
    appLoader = Object_NULL;
    goto cleanup;
  }

  ALOGV("Succeeded in getting apploader object.");

  /* load the application */
  ret = IAppLoader_loadFromBuffer(appLoader, img_data->buffer, img_data->buffer_size, &appController);
  if (Object_isERROR(ret)) {
    ALOGE("Loading the application failed with %d!", ret);
    appController = Object_NULL;
    goto cleanup;
  }

  ALOGV("Loading the application succeeded.");

  ret = IAppController_getAppObject(appController, &appObj);
  if (Object_isERROR(ret)) {
    ALOGE("Getting the application object failed with %d!", ret);
    appObj = Object_NULL;
    goto cleanup;
  }

  ALOGV("Getting the application object succeeded.");

  /* run the ISMCIExample_add function from the ISMCIExample interface. */
  ret = ISMCIExample_add(appObj, val1, val2, &addResult);

  if (Object_isERROR(ret)) {
    ALOGE("Addition returned error %d!", ret);
  } else {
    ALOGD("Add result: %d", addResult);
  }

cleanup:
  Object_ASSIGN_NULL(appObj);
  Object_ASSIGN_NULL(appController);
  Object_ASSIGN_NULL(appLoader);
  Object_ASSIGN_NULL(clientEnv);
  return ret;
}
