/*
 * app_main.c
 */

#include <comdef.h>
#include <object.h>
#include <stdio.h>

#include <qsee_log.h>
#include <qsee_heap.h>

#include "CICCCSaveData.h"
#include "CICCCSaveData_open.h"
#include "CICCCReadData.h"
#include "CICCCReadData_open.h"
#include "CICCCGetDeviceStatus.h"
#include "CICCCGetDeviceStatus_open.h"

#include "app_version.h"

#include "app_main.h"
#include "app_core.h"
#include "app_bootloader.h"
#include "app_allowlist.h"
#include "app_saveData.h"
#include "app_readData.h"
#include "app_getDeviceStatus.h"
#include "app_attestation.h"

#include "tz_iccc_comdef.h"

/*
 * Modify the app name to your specific app name
 */
char TZ_APP_NAME[] = {"tz_iccc"};

int32_t tz_module_open(uint32_t uid, Object cred, Object *objOut)
{
    uint32_t ret = Object_ERROR_INVALID;
    char caller_ta_name[TA_NAME_SIZE] = {0, };
    size_t caller_ta_name_size = 0;

    ICCC_LOG("TZ_ICCC: tz buildinfo: version %s", TZ_ICCC_VERSION);
    ICCC_LOG("TZ_ICCC: tz_module_open() uid: %d", uid);

    ret = get_app_name(cred, caller_ta_name, TA_NAME_SIZE, &caller_ta_name_size);
    if (!Object_isOK(ret)) {
        ICCC_LOG("TZ_ICCC: tz_module_open() error on get_app_name");
        goto error;
    }

    ICCC_LOG("TZ_ICCC: caller_ta_name = %s && caller_ta_name_size = %d", caller_ta_name, caller_ta_name_size);

    switch (uid) {
        case CICCCSaveData_UID:
            return CICCCSaveData_open(cred, objOut);
        case CICCCReadData_UID:
            return CICCCReadData_open(cred, objOut);
        case CICCCGetDeviceStatus_UID:
            return CICCCGetDeviceStatus_open(cred, objOut);
        default:
            ret = Object_ERROR_INVALID;
            break;
    }

error:
    *objOut = Object_NULL;
    return ret;
}

/*
 * Add any app specific initialization code here
 * QSEE will call this function after secure app is loaded and authenticated
 */
static uint8_t qsee_log_mask;

void tz_app_init(void)
{
    qsee_log_mask = qsee_log_get_mask();
    qsee_log_set_mask(QSEE_LOG_MSG_ERROR | QSEE_LOG_MSG_FATAL);
    /* App specific initialization code*/
    ICCC_LOG("TZ_ICCC: init");
}

/*
 * App specific command handler
 * App executes code based on input command
 */
void tz_app_cmd_handler(void *cmd, uint32 cmdlen, void *rsp, uint32 rsplen)
{
    int ret = ICCC_SUCCESS;
    tciMessage_t *sendmsg = NULL;
    tciMessage_t *respmsg = NULL;
    uint32_t cmd_id;

    ICCC_LOG("TZ_ICCC: tz buildinfo: version %s", TZ_ICCC_VERSION);

    if (cmd == NULL || cmdlen < sizeof(tciMessage_t) || rsp == NULL || rsplen < sizeof(tciMessage_t)
        || ((cmd < rsp) && ((void *)((uint8_t *)cmd + cmdlen) > rsp))
        || ((rsp < cmd) && ((void *)((uint8_t *)rsp + rsplen) > cmd))) {
        ICCC_LOG("TZ_ICCC: invalid input buffer");
        return;
    }

    /* Local buffer to prevent Race Condition */
    sendmsg = (tciMessage_t*)qsee_malloc(sizeof(tciMessage_t));
    respmsg = (tciMessage_t*)qsee_malloc(sizeof(tciMessage_t));
    if (!sendmsg) {
        ICCC_LOG("TZ_ICCC: sendmsg pointer is NULL");
        goto exit;
    }
    memset((void *)sendmsg, 0, sizeof(tciMessage_t));
    memcpy((void *)sendmsg, cmd, sizeof(tciMessage_t));

    if (!respmsg) {
        ICCC_LOG("TZ_ICCC: respmsg pointer is NULL");
        goto exit;
    }
    memset((void *)respmsg, 0, sizeof(tciMessage_t));
    memcpy((void *)respmsg, rsp, sizeof(tciMessage_t));

    cmd_id = sendmsg->header.id;
    ICCC_LOG("TZ_ICCC: tz_iccc_cmd_handler: cmd_id: %d", cmd_id);

    /* Process command message */
    switch (cmd_id) {
        case CMD_ICCC_SAVEDATA:
            ret = ICCC_save_data(&sendmsg->payload.generic, &respmsg->payload.generic);
            break;
        case CMD_ICCC_READDATA:
            ret = ICCC_read_data(&sendmsg->payload.generic, &respmsg->payload.generic);
            break;
        case CMD_ICCC_DEVICE_STATUS:
            ret = ICCC_device_status(&sendmsg->payload.status, &respmsg->payload.status);
            break;
        case CMD_ICCC_ATTESTATION:
            ret = ICCC_attestation(&sendmsg->payload.attestation, &respmsg->payload.attestation);
            break;
        case SEC_BOOT_CMD1_SET_ICCC_BL_DATA:
            ret = tzbsp_oem_write_iccc_bl_info(&sendmsg->payload.bootloader.content.iccc_req.data.bl_secure_info);
            break;
        case SEC_BOOT_CMD2_SET_ICCC_ROT_BL_DATA:
            ret = tzbsp_oem_write_iccc_rot_bl_info(&sendmsg->payload.bootloader.content.iccc_req.data.bl_secure_info_rot);
            break;
        case SEC_BOOT_CMD3_SET_ICCC_SVB_BL_DATA:
            ret = tzbsp_oem_write_iccc_svb_bl_info(&sendmsg->payload.bootloader.content.iccc_req.data.bl_secure_info_sys);
            break;
        case SEC_BOOT_CMD4_SET_ICCC_KERN_DATA:
            ret = tzbsp_oem_write_iccc_kern_info(&sendmsg->payload.bootloader.content.iccc_req.data.bl_secure_info_kern);
            break;
        default:
            ICCC_LOG("TZ_ICCC: received unknown command: %d!", cmd_id);
            ret = ICCC_UNKNOWN_CMD;
            respmsg->payload.generic.content.iccc_rsp.ret = ret;
            break;
    }

    respmsg->header.id = RSP_ID(cmd_id);
    respmsg->header.status = ret;

exit:
    if (sendmsg) {
        memcpy(cmd, (void *)sendmsg, sizeof(tciMessage_t));
        qsee_free(sendmsg);
    }

    if (respmsg) {
        memcpy(rsp, (void *)respmsg, sizeof(tciMessage_t));
        qsee_free(respmsg);
    }

    ICCC_LOG("TZ_ICCC: tz_app_cmd_handler: ret: %d", ret);
}

/*
 * App specific shutdown
 * App will be given a chance to shutdown gracefully
 */
void tz_app_shutdown(void)
{
    /* App specific shutdown code*/
    ICCC_LOG("TZ_ICCC: shutdown");
    return;
}
