/*
 * icccOperations.c
 */

#ifndef ICCC_v4

#include <errno.h> // errno
#include <fcntl.h> // O_RDWR
#include <string.h>
#include <sys/ioctl.h> // ioctl
#include <unistd.h> // close

#include "tl_tz_iccc_init.h" // ICCC_INIT_ERROR, ICCC_INIT_UNINITIALIZED_SECURE_MEM

#include "icccOperations.h"

//#define UINT8_MAX 0xff /* 255U */

char iccc_log_msg[LOG_MSG_SIZE];

/* For ICCC secure address */
static uint32_t iccc_sec_mem_addr = ICCC_SECURE_MEM_BASE_ADDR;

/* START OF DEPENDENCY REMOVAL */
// .../tima_common/inc/logging.h
#define SVC_ICCCUTIL_ID        0x00070000
#define ICCCUTIL_CREATE_CMD(x) (SVC_ICCCUTIL_ID | x)

// .../tima_common/inc/tima_ioctl.h
typedef enum {
    ICCCUTIL_DEBUG_LOG_WRITE       = ICCCUTIL_CREATE_CMD(0x00000000),
    ICCCUTIL_DEBUG_LOG_READ        = ICCCUTIL_CREATE_CMD(0x00000001),
    ICCCUTIL_SECURE_LOG_WRITE      = ICCCUTIL_CREATE_CMD(0x00000002),
    ICCCUTIL_SECURE_LOG_READ       = ICCCUTIL_CREATE_CMD(0x00000003),
    ICCCUTIL_SECURE_PHYS_READ      = ICCCUTIL_CREATE_CMD(0x00000041),
    ICCCUTIL_SECURE_PHYS_WRITE     = ICCCUTIL_CREATE_CMD(0x00000042),
    DMV_SRAM_READ_RECOVERY         = ICCCUTIL_CREATE_CMD(0x00000121)
} icccutil_cmd_type;

// .../tima_common/inc/tima_ioctl.h
struct ioctl_mem_access_data {
    uint32_t phys_addr;
    uint32_t len;
    char* rw_addr;
    int32_t status;
};

// .../tima_common/inc/tima_ioctl.h
#if defined(SEC_SDK40)
static const char drv_name[] = "tima_driver"; // /dev/tima_driver
#else
static const char drv_name[] = "dev://my_driver";
#endif
static int drv_fd = -1;

// .../tima_common/src/TZ_Vendor_tl.c
uint32_t Iccc_phys_write(void *offset, uint32_t length, void *data_buf)
{
    uint32_t ret = ICCC_SUCCESS;
    struct ioctl_mem_access_data data;
    int drv_ret = 0;

    data.phys_addr = (uint32_t)offset;
    data.len = length;
    data.status = -1;
    data.rw_addr = data_buf;
    drv_fd = open(drv_name, O_RDWR, 0);
    if (drv_fd < 0) {
        ICCC_LOG("ICCC: Iccc_phys_write: drv_open_client failed errno = %d", errno);
        return drv_fd;
    }

    drv_ret = ioctl(drv_fd, ICCCUTIL_SECURE_PHYS_WRITE, (unsigned long)&data);
    if (drv_ret < 0) {
        ICCC_LOG("ICCC: Iccc_phys_write: ioctl error, errno = %d", errno);
        ret = ICCC_ERROR_WRITE_FAILED;
        goto exit;
    }

    if (data.status < 0) {
        ICCC_LOG("ICCC: Iccc_phys_write: data.status = %d", data.status);
        ret = ICCC_ERROR_WRITE_FAILED;
        goto exit;
    }

exit:
    drv_ret = close(drv_fd);
    if (drv_ret < 0) {
        ICCC_LOG("Iccc_phys_write: drv_client_close(): close error, errno = %d\n", errno);
        return drv_ret;
    }

    return ret;
}

// .../tima_common/src/TZ_Vendor_tl.c
uint32_t Iccc_phys_read(void *offset, uint32_t length, void *ret_buf) {
    uint32_t ret = ICCC_SUCCESS;
    struct ioctl_mem_access_data data;
    int drv_ret = 0;

    data.phys_addr = (uint32_t)offset;
    data.len = length;
    data.status = -1;
    data.rw_addr = ret_buf;
    drv_fd = open(drv_name, O_RDWR, 0);
    if (drv_fd < 0) {
        ICCC_LOG("ICCC: Iccc_phys_read: drv_open_client failed errno = %d", errno);
        return drv_fd;
    }

    TEE_MemFill(data.rw_addr, 0, length);
    drv_ret = ioctl(drv_fd, ICCCUTIL_SECURE_PHYS_READ, (unsigned long)&data);
    if (drv_ret < 0) {
        ICCC_LOG("ICCC: Iccc_phys_read: ioctl error, errno = %d", errno);
        ret = ICCC_ERROR_READ_FAILED;
        goto exit;
    }

    if (data.status < 0) {
        ICCC_LOG("ICCC: Iccc_phys_read: data.status = %d", data.status);
        ret = ICCC_ERROR_READ_FAILED;
        goto exit;
    }

exit:
    drv_ret = close(drv_fd);
    if (drv_ret < 0) {
        ICCC_LOG("ICCC: Iccc_phys_read: drv_client_close(): close error, errno = %d", errno);
        return drv_ret;
    }

    return ret;
}

// .../tima_common/inc/TZ_Vendor_tl.h
#define TZ_API_OK 0
#define TZ_API_ERROR 1
#define SHA1_DIGEST_LENGTH 20
#define SHA256_DIGEST_LENGTH 32
#define TEE_MAX_KEY_SIZE 256
#define ATTR_COUNT 2
#define SIGN_ATTR_COUNT 3
#define MAX_SIGNATURE_SIZE 256

// .../tima_common/src/TZ_Vendor_tl.c
uint32_t Iccc_verify_CKM_SHA1_RSA_PKCS(
    uint8_t* keyMod, uint32_t keyModLen,
    uint8_t* keyPubExp, uint32_t keyPubExpLen,
    uint8_t* messageData, uint32_t messageLen,
    uint8_t* signature, uint32_t sigLen,
    bool* isValidSig)
{
    uint32_t ret = TZ_API_OK;
    TEE_Result teeRet = TEE_SUCCESS;
    uint8_t digest[SHA1_DIGEST_LENGTH];
    size_t digestLen = sizeof(digest);
    TEE_Attribute attr[ATTR_COUNT];
    TEE_OperationHandle op;
    TEE_OperationHandle digest_op;
    uint32_t keyModLenInBits;
    TEE_ObjectHandle key_obj;

    if (keyMod == NULL || keyModLen == 0) {
        printf("invalid input key modulus \n");
        return TZ_API_ERROR;
    }

    if (keyPubExp == NULL || keyPubExpLen == 0) {
        printf("invalid input key public exponent \n");
        return TZ_API_ERROR;
    }

    if (messageData == NULL || messageLen == 0) {
        printf("invalid input signing data \n");
        return TZ_API_ERROR;
    }

    if (signature == NULL || sigLen == 0) {
        printf("invalid output signature data \n");
        return TZ_API_ERROR;
    }

    if (isValidSig == NULL) {
        printf("invalid isValidSig pointer \n");
        return TZ_API_ERROR;
    }

    keyModLenInBits = keyModLen * 8;

    teeRet = TEE_AllocateOperation(&digest_op, TEE_ALG_SHA1, TEE_MODE_DIGEST, keyModLenInBits);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_AllocateOperation for digest failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto exit;
    }

    teeRet = TEE_DigestDoFinal(digest_op, (void*)messageData, messageLen, digest, &digestLen);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_DigestDoFinal  failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto digest_op_exit;
    }

    TEE_InitRefAttribute(&attr[0], TEE_ATTR_RSA_MODULUS, keyMod, keyModLen);
    TEE_InitRefAttribute(&attr[1], TEE_ATTR_RSA_PUBLIC_EXPONENT, keyPubExp, keyPubExpLen);

    teeRet = TEE_AllocateTransientObject(TEE_TYPE_RSA_PUBLIC_KEY, keyModLenInBits, &key_obj);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_AllocateTransientObject failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto digest_op_exit;
    }

    teeRet = TEE_PopulateTransientObject(key_obj, attr, ATTR_COUNT);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_PopulateTransientObject failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto key_obj_exit;
    }

    teeRet = TEE_AllocateOperation(&op, TEE_ALG_RSASSA_PKCS1_V1_5_SHA1, TEE_MODE_VERIFY, keyModLenInBits);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_AllocateOperation failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto key_obj_exit;
    }

    teeRet = TEE_SetOperationKey(op, key_obj);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_SetOperationKey failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto op_exit;
    }

    teeRet = TEE_AsymmetricVerifyDigest(op, NULL, 0, digest, digestLen, signature, (size_t)sigLen);
    if (teeRet == TEE_SUCCESS) {
        printf("TEE_AsymmetricVerifyDigest PASSED \n");
        *isValidSig = true;
        ret = TZ_API_OK;
    }
    else if (teeRet == TEE_ERROR_SIGNATURE_INVALID) {
        printf("Error: TEE_AsymmetricVerifyDigest invalid signature \n");
        *isValidSig = false;
        ret = TZ_API_ERROR;
    }
    else {
        printf("Error: TEE_AsymmetricVerifyDigest failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
    }

op_exit:
    TEE_FreeOperation(op);
key_obj_exit:
    TEE_FreeTransientObject(key_obj);
digest_op_exit:
    TEE_FreeOperation(digest_op);
exit:
    return ret;
}

uint32_t Iccc_verify_CKM_SHA256_RSA_PKCS(
    uint8_t* keyMod, uint32_t keyModLen,
    uint8_t* keyPubExp, uint32_t keyPubExpLen,
    uint8_t* messageData, uint32_t messageLen,
    uint8_t* signature, uint32_t sigLen,
    bool* isValidSig)
{
    uint32_t ret = TZ_API_OK;
    TEE_Result teeRet = TEE_SUCCESS;
    uint8_t digest[SHA256_DIGEST_LENGTH];
    size_t digestLen = sizeof(digest);
    TEE_Attribute attr[ATTR_COUNT];
    TEE_OperationHandle op;
    TEE_OperationHandle digest_op;
    uint32_t keyModLenInBits;
    TEE_ObjectHandle key_obj;

    if (keyMod == NULL || keyModLen == 0) {
        printf("invalid input key modulus \n");
        return TZ_API_ERROR;
    }

    if (keyPubExp == NULL || keyPubExpLen == 0) {
        printf("invalid input key public exponent \n");
        return TZ_API_ERROR;
    }

    if (messageData == NULL || messageLen == 0) {
        printf("invalid input signing data \n");
        return TZ_API_ERROR;
    }

    if (signature == NULL || sigLen == 0) {
        printf("invalid output signature data \n");
        return TZ_API_ERROR;
    }

    if (isValidSig == NULL) {
        printf("invalid isValidSig pointer \n");
        return TZ_API_ERROR;
    }

    keyModLenInBits = keyModLen * 8;

    teeRet = TEE_AllocateOperation(&digest_op, TEE_ALG_SHA256, TEE_MODE_DIGEST, keyModLenInBits);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_AllocateOperation for digest failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto exit;
    }

    teeRet = TEE_DigestDoFinal(digest_op, (void*)messageData, messageLen, digest, &digestLen);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_DigestDoFinal  failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto digest_op_exit;
    }

    TEE_InitRefAttribute(&attr[0], TEE_ATTR_RSA_MODULUS, keyMod, keyModLen);
    TEE_InitRefAttribute(&attr[1], TEE_ATTR_RSA_PUBLIC_EXPONENT, keyPubExp, keyPubExpLen);

    teeRet = TEE_AllocateTransientObject(TEE_TYPE_RSA_PUBLIC_KEY, keyModLenInBits, &key_obj);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_AllocateTransientObject failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto digest_op_exit;
    }

    teeRet = TEE_PopulateTransientObject(key_obj, attr, ATTR_COUNT);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_PopulateTransientObject failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto key_obj_exit;
    }

    teeRet = TEE_AllocateOperation(&op, TEE_ALG_RSASSA_PKCS1_V1_5_SHA256, TEE_MODE_VERIFY, keyModLenInBits);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_AllocateOperation failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto key_obj_exit;
    }

    teeRet = TEE_SetOperationKey(op, key_obj);
    if (teeRet != TEE_SUCCESS) {
        printf("Error: TEE_SetOperationKey failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
        goto op_exit;
    }

    teeRet = TEE_AsymmetricVerifyDigest(op, NULL, 0, digest, digestLen, signature, (size_t)sigLen);
    if (teeRet == TEE_SUCCESS) {
        printf("TEE_AsymmetricVerifyDigest PASSED \n");
        *isValidSig = true;
        ret = TZ_API_OK;
    }
    else if (teeRet == TEE_ERROR_SIGNATURE_INVALID) {
        printf("Error: TEE_AsymmetricVerifyDigest invalid signature \n");
        *isValidSig = false;
        ret = TZ_API_ERROR;
    }
    else {
        printf("Error: TEE_AsymmetricVerifyDigest failed tee_result = %x \n", teeRet);
        ret = TZ_API_ERROR;
    }

op_exit:
    TEE_FreeOperation(op);
key_obj_exit:
    TEE_FreeTransientObject(key_obj);
digest_op_exit:
    TEE_FreeOperation(digest_op);
exit:
    return ret;
}

uint32_t Iccc_digest_SHA256(
    uint8_t *messageData,
    uint32_t messageLen,
    uint8_t *digest,
    uint32_t *pDigestLen
)
{
    uint32_t ret = ICCC_SUCCESS;
    TEE_OperationHandle opHandle = NULL;
    TEE_Result teeRet = TZ_API_OK;

    printf("generate digest \n");

    if (messageData == NULL || messageLen == 0) {
        printf("invalid input data buffer \n");
        return ICCC_ERROR_ATTESTATION_FAILED;
    }

    if (digest == NULL || pDigestLen == NULL) {
        printf("invalid output digest data buffer \n");
        return ICCC_ERROR_ATTESTATION_FAILED;
    }

    if (*pDigestLen < SHA256_DIGEST_LENGTH) {
        printf("pDigestLen < SHA256_DIGEST_LENGTH \n");
        return ICCC_ERROR_ATTESTATION_FAILED;
    }

    teeRet = TEE_AllocateOperation(&opHandle, TEE_ALG_SHA256, TEE_MODE_DIGEST, TEE_MAX_KEY_SIZE);
    if (TEE_SUCCESS != teeRet) {
        printf("Error: TEE_AllocateOperation failed with ret = %x \n", teeRet);
        ret = ICCC_ERROR_ATTESTATION_FAILED;
        goto exit;
    }

    teeRet = TEE_DigestDoFinal(opHandle, messageData, messageLen, digest, pDigestLen);
    if (TEE_SUCCESS != teeRet) {
        printf("Error: TEE_DigestDoFinal() failed with ret = %x \n", teeRet);
        ret = ICCC_ERROR_ATTESTATION_FAILED;
        goto exit;
    } else {
        printf("TEE_DigestDoFinal() digest len = %d \n", *pDigestLen);
    }

    printf("TEE_DigestDoFinal() succeeds \n");
    // TEE_DigestDoFinal() has a bug with which pDigestLen is not returned correctly.
    // So here pDigestLen is set mannually
    *pDigestLen = SHA256_DIGEST_LENGTH;

    ret = ICCC_SUCCESS;

exit:
    if (NULL != opHandle) {
        TEE_FreeOperation(opHandle);
    }

    return ret;
}

uint32_t Iccc_sign_CKM_SHA256_RSA_PKCS_PSS(
    uint8_t *keyMod,
    uint32_t keyModLen,
    uint8_t *keyPubExp,
    uint32_t keyPubExpLen,
    uint8_t *keyPriExp,
    uint32_t keyPriExpLen,
    uint8_t *messageData,
    uint32_t messageLen,
    uint8_t *signature,
    uint32_t *pSigLen
)
{
    TEE_OperationHandle opHandle = NULL;
    TEE_ObjectHandle keyHandle = NULL;
    uint32_t ret = TZ_API_OK;
    uint8_t digest[SHA256_DIGEST_LENGTH] = {0};
    uint32_t digestLen = sizeof(digest);

    TEE_Attribute attrs[SIGN_ATTR_COUNT];

    printf("sign using RSA key \n");

    if (keyMod == NULL || keyModLen == 0) {
        printf("invalid input key modulus \n");
        return TZ_API_ERROR;
    }

    printf("keyModLen %d \n", keyModLen);
    if (keyModLen > MAX_SIGNATURE_SIZE) {
        printf("signature length exceeds MAX_SIGNATURE_SIZE \n");
        return TZ_API_ERROR;
    }

    if (keyPubExp == NULL || keyPubExpLen == 0) {
        printf("invalid input key public exponent \n");
        return TZ_API_ERROR;
    }

    if (keyPriExp == NULL || keyPriExpLen == 0) {
        printf("invalid input key private exponent \n");
        return TZ_API_ERROR;
    }

    if (messageData == NULL || messageLen == 0) {
        printf("invalid input signing data \n");
        return TZ_API_ERROR;
    }

    if (signature == NULL || pSigLen == NULL|| *pSigLen == 0) {
        printf("invalid output signature data \n");
        return TZ_API_ERROR;
    }

    ret = Iccc_digest_SHA256(messageData, messageLen, digest, &digestLen);
    if (TZ_API_OK != ret) {
        printf("Iccc_digest_SHA256() returns an error code 0x%x \n", ret);
        return TZ_API_ERROR;
    }

    ret = TEE_AllocateTransientObject(TEE_TYPE_RSA_KEYPAIR, 8*keyModLen, &keyHandle);
    if (TEE_SUCCESS != ret) {
        printf("TEE_AllocateTransientObject failed with ret = %d \n", ret);
        goto exit;
    }
    TEE_InitRefAttribute(&attrs[0], TEE_ATTR_RSA_MODULUS, keyMod, keyModLen);
    TEE_InitRefAttribute(&attrs[1], TEE_ATTR_RSA_PUBLIC_EXPONENT, keyPubExp, keyPubExpLen);
    TEE_InitRefAttribute(&attrs[2], TEE_ATTR_RSA_PRIVATE_EXPONENT, keyPriExp, keyPriExpLen);

    ret = TEE_PopulateTransientObject(keyHandle, attrs, SIGN_ATTR_COUNT);
    if (TEE_SUCCESS != ret) {
        printf("TEE_PopulateTransientObject failed with ret = %d \n", ret);
        goto exit;
    }

    ret = TEE_AllocateOperation(&opHandle, TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256, TEE_MODE_SIGN, 8*keyModLen);
    if (TEE_SUCCESS != ret) {
        printf("TEE_AllocateOperation failed with ret = %d \n", ret);
        goto exit;
    }

    ret = TEE_SetOperationKey(opHandle, keyHandle);
    if (TEE_SUCCESS != ret) {
        printf("TEE_SetOperationKey failed with ret = %d \n", ret);
        goto exit;
    }

    ret = TEE_AsymmetricSignDigest(opHandle, NULL, 0, digest, digestLen, signature, pSigLen);
    if (TEE_SUCCESS != ret) {
        printf("TEE_AsymmetricSignDigest failed with ret = %d \n", ret);
        goto exit;
    }

    ret = TZ_API_OK;

exit:

    if (keyHandle != NULL) {
        TEE_FreeTransientObject(keyHandle);
    }
    if (opHandle != NULL) {
        TEE_FreeOperation(opHandle);
    }
    return ret;
}

uint32_t get_sec_ICCC_address(int type)
{
    if (iccc_sec_mem_addr == 0) {
        ICCC_LOG("ICCC: Wrong ICCC_SECURE_MEM_BASE_ADDR");
        return ICCC_MEM_ADDR_ERROR;
    }
    ICCC_LOG_DEBUG("ICCC: get_sec_ICCC_address iccc_sec_mem_addr : %X", iccc_sec_mem_addr);

    switch(type){
        case PARAM_FOR_ICCC_SEC_MEM:
            return iccc_sec_mem_addr;
        case PARAM_FOR_ICCC_BOOT_MSR:
            return (uint32_t)(iccc_sec_mem_addr + ICCC_BOOT_MSR_ADDR_OFFSET);
        case PARAM_FOR_ICCC_GOLDEN_MSR:
            return (uint32_t)(iccc_sec_mem_addr + ICCC_GOLDEN_MSR_ADDR_OFFSET);
        case PARAM_FOR_ICCC_WARRANTY_STRING:
            return (uint32_t)(iccc_sec_mem_addr + ICCC_BOOT_WARRANTY_ADDR_OFFSET);
        default:
            return ICCC_MEM_ADDR_ERROR;
    }
}
/* END OF DEPENDENCY REMOVAL */

int is_type_valid(uint32_t type)
{
    switch (type) {
        case RP_VER ... EM_TOKEN:
        case PKM_TEXT ... ATN_BLOB_HASH:
        case DMV_STATUS ... VERIFIEDBOOT_HASH:
        case SYSSCOPE_FLAG ... TIMA_VERSION_FLAG:
#ifdef CONFIG_ROT_IN_ICCC
        case VERIFIEDBOOTSTATE_FLAG ... ROT_STRUCT:
#endif
            return 1;
        default:
            return 0;
    }
}

/* return 0 if not locked */
uint32_t Iccc_check_lock_status(uint32_t type, uint32_t secure_mem_addr)
{
    uint32_t iccc_lock;
    uint32_t ret = ICCC_SUCCESS;

    if ((type != (uint32_t)SYSSCOPE_FLAG) && (type != (uint32_t)TRUSTBOOT_FLAG) && (type != (uint32_t)TIMA_VERSION_FLAG)
     && (type != (uint32_t)PKM_TEXT) && (type != (uint32_t)PKM_RO)) {
        ICCC_LOG("ICCC: not locked");
        ICCC_LOG_DEBUG("ICCC: only SYSSCOPE_FLAG, TRUSTBOOT_FLAG, TIMA_VERSION_FLAG, PKM_TEXT, PKM_RO are lock protected");
        return 0;
    }

    if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_LOCK_FLAG_OFFSET), ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)(&iccc_lock)))) {
        ICCC_LOG("ICCC: failed to read iccc lock, ret = 0x%x", ret);
        return ret;
    }

    ICCC_LOG_DEBUG("ICCC: Iccc_check_lock_status : iccc lock is %x", iccc_lock);
    if (type == (uint32_t)SYSSCOPE_FLAG)
        iccc_lock = iccc_lock & (uint32_t)ICCC_SYSSCOPE_LOCK;
    else if (type == (uint32_t)TRUSTBOOT_FLAG)
        iccc_lock = iccc_lock & (uint32_t)ICCC_TRUSTBOOT_LOCK;
    else if (type == (uint32_t)TIMA_VERSION_FLAG)
        iccc_lock = iccc_lock & (uint32_t)ICCC_TIMA_VERSION_LOCK;
    else if (type == (uint32_t)PKM_TEXT)
        iccc_lock = iccc_lock & (uint32_t)ICCC_LOCK_PKM_TEXT;
    else if (type == (uint32_t)PKM_RO)
        iccc_lock = iccc_lock & (uint32_t)ICCC_LOCK_PKM_RO;

    if (iccc_lock == 0)
        return 0; // not locked
    else
        return 1; // locked
}

uint32_t Iccc_lock_on_failure(uint32_t type, uint32_t value)
{
    uint32_t ret = 0;
    switch (type) {
        case PKM_TEXT:
            if (value != TEXT_REG_SUCCESS)
                ret = 1;
            break;
        case PKM_RO:
            if (value != TEXT_RO_SUCCESS)
                ret = 1;
            break;
        default:
            ret = 1;
    }

    return ret;
}

uint32_t Iccc_update_lock(uint32_t type, uint32_t secure_mem_addr, uint32_t value)
{
    uint32_t iccc_lock;
    uint32_t ret = ICCC_SUCCESS;

    if ((type != (uint32_t)SYSSCOPE_FLAG) && (type != (uint32_t)TRUSTBOOT_FLAG) && (type != (uint32_t)TIMA_VERSION_FLAG)
     && (type != (uint32_t)PKM_TEXT) && (type != (uint32_t)PKM_RO)){
        ICCC_LOG("ICCC: not Locked");
        ICCC_LOG_DEBUG("ICCC: only SYSSCOPE_FLAG, TRUSTBOOT_FLAG, TIMA_VERSION_FLAG, PKM_TEXT, PKM_RO are lock protected");
        return 0;
    }

    if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_LOCK_FLAG_OFFSET), ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)(&iccc_lock)))) {
        ICCC_LOG("ICCC: failed to read iccc lock, ret = 0x%x", ret);
        return ret;
    }

    ICCC_LOG_DEBUG("ICCC: Iccc_update_lock : iccc lock is %x ", iccc_lock);

    if (!Iccc_lock_on_failure(type, value)) {
        ICCC_LOG("ICCC: Restriction to update the iccc lock");
        return 0;
    }

    if (type == (uint32_t)SYSSCOPE_FLAG)
        iccc_lock = iccc_lock | (uint32_t)ICCC_SYSSCOPE_LOCK;
    else if (type == (uint32_t)TRUSTBOOT_FLAG)
        iccc_lock = iccc_lock | (uint32_t)ICCC_TRUSTBOOT_LOCK;
    else if (type == (uint32_t)TIMA_VERSION_FLAG)
        iccc_lock = iccc_lock | (uint32_t)ICCC_TIMA_VERSION_LOCK;
    else if (type == (uint32_t)PKM_TEXT)
        iccc_lock = iccc_lock | (uint32_t)ICCC_LOCK_PKM_TEXT;
    else if (type == (uint32_t)PKM_RO)
        iccc_lock = iccc_lock | (uint32_t)ICCC_LOCK_PKM_RO;

    if (0 != (ret = Iccc_phys_write((void *)(secure_mem_addr + ICCC_LOCK_FLAG_OFFSET), ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)(&iccc_lock)))) {
        ICCC_LOG("ICCC: failed to write iccc lock, ret = 0x%x", ret);
        return ret;
    }

    return 0;
}

uint32_t Iccc_check_magic(uint32_t secure_param_type, uint32_t secure_mem_addr, uint16_t *magic_str)
{
    uint32_t ret = ICCC_SUCCESS;
    secure_param_header_t header = {0};

    ICCC_LOG_DEBUG("ICCC: Iccc_check_magic: secure_param_type = %#x secure_mem_addr = %#x", secure_param_type, secure_mem_addr);
    if (secure_param_type == 0xF) {
        if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET), sizeof(secure_param_header_t), (void *)(&header)))) {
            ICCC_LOG("ICCC: Iccc_phys_read failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET) = 0x%x, ret = 0x%x", (secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET), ret);
            ret = ICCC_ERROR_READ_FAILED;
        }
    } else if (secure_param_type == 0x0) {
        if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET), sizeof(secure_param_header_t), (void *)(&header)))) {
            ICCC_LOG("ICCC: Iccc_phys_read failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET) = 0x%x, ret = 0x%x", (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET), ret);
            ret = ICCC_ERROR_READ_FAILED;
        }
    } else if (secure_param_type == 0x1) {
        if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET), sizeof(secure_param_header_t), (void *)(&header)))) {
            ICCC_LOG("ICCC: Iccc_phys_read failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET) = 0x%x, ret = 0x%x", (secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET), ret);
            ret = ICCC_ERROR_READ_FAILED;
        }
    } else if (secure_param_type == 0x2) {
        if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET), sizeof(secure_param_header_t), (void *)(&header)))) {
            ICCC_LOG("ICCC: Iccc_phys_read failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET) = 0x%x, ret = 0x%x", (secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET), ret);
            ret = ICCC_ERROR_READ_FAILED;
        }
    }
#ifdef CONFIG_ROT_IN_ICCC
    else if (secure_param_type == 0x3) {
        if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET), sizeof(secure_param_header_t), (void *)(&header)))) {
            ICCC_LOG("ICCC: Iccc_phys_read failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET) = 0x%x, ret = 0x%x",(secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET), ret);
            ret = ICCC_ERROR_READ_FAILED;
        }
    }
#endif
    else {
        ICCC_LOG("ICCC: unknown block ");
        ret = ICCC_ERROR_READ_FAILED;
    }

    ICCC_LOG_DEBUG("ICCC: magic = %x , ret = %x ", header.magic_str, ret);
    *magic_str = header.magic_str;
    return ret;
}

uint32_t Iccc_SaveData_TA(uint32_t type, uint32_t value)
{
    uint32_t ret = ICCC_SUCCESS;
    uint32_t secure_param_type;
    uint32_t secure_param_addr;
    uint32_t secure_mem_addr;
    uint16_t magic_str = 0;

    if (!is_type_valid(type)) {
        ICCC_LOG_DEBUG("ICCC: Unknown type");
        ret = ICCC_UNKNOWN_TYPE;
        goto exit;
    }

    secure_mem_addr = get_sec_ICCC_address(PARAM_FOR_ICCC_SEC_MEM);
    secure_param_type = (type >> 20) & (0xF);
    secure_param_addr = (uint32_t)((type & (0x1F)) * ICCC_SECURE_PARAMETERS_READING_LENGTH);
    ICCC_LOG_DEBUG("ICCC: secure_param_type = %x", secure_param_type);
    ICCC_LOG_DEBUG("ICCC: secure_param_addr = %x", secure_param_addr);

    ICCC_LOG("ICCC: Iccc_SaveData_TA@#");

    ret = Iccc_check_magic(secure_param_type, secure_mem_addr, &magic_str);
    if (ret) {
        ICCC_LOG("ICCC: check magic failed");
        ICCC_LOG_DEBUG("ICCC: Iccc_check_magic failed with ret = %x ", ret);
        return ICCC_ERROR_WRITE_FAILED;
    }

    if (secure_param_type == 0xF && magic_str == BL_MAGIC_STR) {
        if (secure_param_addr > sizeof(bl_secure_info_t)) {
            ICCC_LOG("ICCC: secure_param_addr error");
            ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(bl_secure_info_t)");
            return ICCC_ERROR_WRITE_FAILED;
        }
        ICCC_LOG("ICCC: type already set");
        ICCC_LOG_DEBUG("ICCC: Bootloader parameters were set during bootup by bootloader. No further modifications are allowed");
#ifndef ICCC_TEST_CODE_ENABLED
        ret = ICCC_PERMISSION_DENIED;
#else
        if (0 != (ret = Iccc_phys_write((void *)(secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)(&value)))) {
            ICCC_LOG("ICCC: Iccc_phys_write failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_write failed: (secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                          (secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
            ret = ICCC_ERROR_WRITE_FAILED;
        }
#endif
    } else if (secure_param_type == 0x1 && magic_str == KERN_MAGIC_STR) {
        if (secure_param_addr > sizeof(kern_secure_info_t)) {
            ICCC_LOG("ICCC: secure_param_addr error");
            ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(kern_secure_info_t)");
            return ICCC_ERROR_WRITE_FAILED;
        }
        if (type == DMV_STATUS || type == VERIFIEDBOOT_HASH) {
            ICCC_LOG("ICCC: special type");
            ICCC_LOG_DEBUG("ICCC: DMV_STATUS, VERIFIEDBOOT_HASH parameter can be set by SMC call only.");
#ifndef ICCC_TEST_CODE_ENABLED
            return ICCC_PERMISSION_DENIED;
#endif
        }
        if (0 != (ret = Iccc_phys_write((void *)(secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                 ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)(&value)))) {
            ICCC_LOG("ICCC: Iccc_phys_write failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_write failed: (secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                          (secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
            ret = ICCC_ERROR_WRITE_FAILED;
        }
    } else if((secure_param_type == 0x2 && magic_str == SYS_MAGIC_STR) || (secure_param_type == 0x0 && magic_str == TA_MAGIC_STR)) {
        if (secure_param_addr > sizeof(sys_secure_info_t)) {
            ICCC_LOG("ICCC: secure_param_addr error");
            ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(sys_secure_info_t)");
            return ICCC_ERROR_WRITE_FAILED;
        }
        if (Iccc_check_lock_status(type, secure_mem_addr)) {
            ICCC_LOG("ICCC: type is locked");
            ICCC_LOG_DEBUG("ICCC: only one write is allowed on this type");
#ifndef ICCC_TEST_CODE_ENABLED
            return  ICCC_PERMISSION_DENIED;
#endif
        }
        if (secure_param_type == 0x2 && magic_str == SYS_MAGIC_STR) {
            if (secure_param_addr > sizeof(sys_secure_info_t)) {
                ICCC_LOG("ICCC: secure_param_addr error");
                ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(sys_secure_info_t)");
                return ICCC_ERROR_WRITE_FAILED;
            }
            if (0 != (ret = Iccc_phys_write((void *)(secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), 
                                                     ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)(&value)))) {
                ICCC_LOG("ICCC: Iccc_phys_write failed");
                ICCC_LOG_DEBUG("ICCC: Iccc_phys_write failed: (secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                              (secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
                ret = ICCC_ERROR_WRITE_FAILED;
            }
        } else if (secure_param_type == 0x0 && magic_str == TA_MAGIC_STR) {
            if (secure_param_addr > sizeof(ta_secure_info_t)) {
                ICCC_LOG("ICCC: secure_param_addr error");
                ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(ta_secure_info_t)");
                return ICCC_ERROR_WRITE_FAILED;
            }
            if (0 != (ret = Iccc_phys_write((void *)(secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                     ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)(&value)))) {
                ICCC_LOG("ICCC: Iccc_phys_write failed");
                ICCC_LOG_DEBUG("ICCC: Iccc_phys_write failed: (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                              (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
                ret = ICCC_ERROR_WRITE_FAILED;
            }
        }
        if (0 != (ret = Iccc_update_lock(type, secure_mem_addr, value))) {
            ICCC_LOG("ICCC: Update Lock failed");
            ICCC_LOG_DEBUG("ICCC: iccc_update_lock failed with error = 0x%x", ret);
            ret = ICCC_ERROR_WRITE_FAILED;
        }
    }
#ifdef CONFIG_ROT_IN_ICCC
    else if (secure_param_type == 0x3 && magic_str == ROT_MAGIC_STR){
            ICCC_LOG("ICCC: Iccc_phys_write failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_write failed: RoT locked");
            ret = ICCC_ERROR_WRITE_FAILED;
    }
#endif
    else {
        ICCC_LOG("ICCC: Iccc_phys_write failed");
        ICCC_LOG_DEBUG("ICCC: Iccc_phys_write failed: unknown error");
        ret = ICCC_ERROR_WRITE_FAILED;
    }

exit:
    return ret;
}

uint32_t Iccc_ReadData_TA(uint32_t type, uint32_t *value)
{
    uint32_t ret = ICCC_SUCCESS;
    uint32_t secure_param_type;
    uint32_t secure_param_addr;
    uint32_t secure_mem_addr;
    uint16_t magic_str = 0;

    if (!is_type_valid(type)) {
        ICCC_LOG_DEBUG("ICCC: Unknown type");
        ret = ICCC_UNKNOWN_TYPE;
        goto exit;
    }

    secure_mem_addr = get_sec_ICCC_address(PARAM_FOR_ICCC_SEC_MEM);
    secure_param_type = (type >> 20) & (0xF);
    secure_param_addr = (uint32_t)((type & (0x1F)) * ICCC_SECURE_PARAMETERS_READING_LENGTH);
    ICCC_LOG_DEBUG("ICCC: secure_param_type = %x", secure_param_type);
    ICCC_LOG_DEBUG("ICCC: secure_param_addr = %x", secure_param_addr);

    ICCC_LOG("ICCC: Iccc_ReadData_TA@#");

    ret = Iccc_check_magic(secure_param_type, secure_mem_addr, &magic_str);
    if (ret) {
        ICCC_LOG("ICCC: check magic failed");
        ICCC_LOG_DEBUG("ICCC: Iccc_check_magic failed with ret = %x ", ret);
        return ICCC_ERROR_READ_FAILED;
    }

    if (secure_param_type == 0xF && magic_str == BL_MAGIC_STR) {
        if (secure_param_addr > sizeof(bl_secure_info_t)) {
            ICCC_LOG("ICCC: secure_param_addr error");
            ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(bl_secure_info_t)");
            return ICCC_ERROR_READ_FAILED;
        }
        if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)value))) {
            ICCC_LOG("ICCC: Iccc_phys_read failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                         (secure_mem_addr + ICCC_BL_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
            ret = ICCC_ERROR_READ_FAILED;
        }
    } else if (secure_param_type == 0x0 && magic_str == TA_MAGIC_STR) {
        if (secure_param_addr > sizeof(ta_secure_info_t)) {
            ICCC_LOG("ICCC: secure_param_addr error");
            ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(ta_secure_info_t)");
            return ICCC_ERROR_READ_FAILED;
        }
        if (type == ATN_BLOB_HASH) {
            if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                    SHA256_DIGEST_LENGTH, (void *)value))) {
                ICCC_LOG("ICCC: Iccc_phys_read failed");
                ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                             (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
                ret = ICCC_ERROR_READ_FAILED;
            }
        } else {
            if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                    ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)value))) {
                ICCC_LOG("ICCC: Iccc_phys_read failed");
                ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                             (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
                ret = ICCC_ERROR_READ_FAILED;
            }
        }
    } else if (secure_param_type == 0x1 && magic_str == KERN_MAGIC_STR) {
        if (secure_param_addr > sizeof(kern_secure_info_t)) {
            ICCC_LOG("ICCC: secure_param_addr error");
            ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(kern_secure_info_t)");
            return ICCC_ERROR_READ_FAILED;
        }
        if (type == VERIFIEDBOOT_HASH) {
            if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                    ICCC_ROT_KEY_LENGTH, (void *)value))) {
                ICCC_LOG("ICCC: Iccc_phys_read failed");
                ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                             (secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
                ret = ICCC_ERROR_READ_FAILED;
            }
        } else {
            if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                    ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)value))) {
                ICCC_LOG("ICCC: Iccc_phys_read failed");
                ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                             (secure_mem_addr + ICCC_KERN_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
                ret = ICCC_ERROR_READ_FAILED;
            }
        }
    } else if (secure_param_type == 0x2 && magic_str == SYS_MAGIC_STR) {
        if (secure_param_addr > sizeof(sys_secure_info_t)) {
            ICCC_LOG("ICCC: secure_param_addr error");
            ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(sys_secure_info_t)");
            return ICCC_ERROR_READ_FAILED;
        }
        if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)value))) {
            ICCC_LOG("ICCC: ;Iccc_phys_read failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                         (secure_mem_addr + ICCC_SYS_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
            ret = ICCC_ERROR_READ_FAILED;
        }
    }
#ifdef CONFIG_ROT_IN_ICCC
    else if (secure_param_type == 0x3 && magic_str == ROT_MAGIC_STR) {
        if (type == ROT_STRUCT) { // exceptional cases ((0xFF3000FF & 0x1F) x 0x4 = 124, rot_secure_info_t = 64)
            if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET),
                                                    ICCC_ROT_DATA_LENGTH, (void *)value))) {
                ICCC_LOG("ICCC: Iccc_phys_read failed");
                ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET) = 0x%x, ret = 0x%x",
                                                             (secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET + secure_param_addr), ret);
                ret = ICCC_ERROR_READ_FAILED;
            }
        } else {
            if (secure_param_addr > sizeof(rot_secure_info_t)) {
                ICCC_LOG("ICCC: secure_param_addr error");
                ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(rot_secure_info_t)");
                return ICCC_ERROR_READ_FAILED;
            }
            if (type == VERIFIEDBOOTKEY_FLAG) {
                if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                        ICCC_ROT_KEY_LENGTH, (void *)value))) {
                    ICCC_LOG("ICCC: Iccc_phys_read failed");
                    ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                                 (secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
                    ret = ICCC_ERROR_READ_FAILED;
                }
            } else {
                if (0 != (ret = Iccc_phys_read((void *)(secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                        ICCC_SECURE_PARAMETERS_READING_LENGTH, (void *)value))) {
                    ICCC_LOG("ICCC: Iccc_phys_read failed");
                    ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: (secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                                 (secure_mem_addr + ICCC_ROT_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
                    ret = ICCC_ERROR_READ_FAILED;
                }
            }
        }
    }
#endif
    else {
        ICCC_LOG("ICCC: Iccc_phys_read failed");
        ICCC_LOG_DEBUG("ICCC: Iccc_phys_read failed: unknown error");
        ret = ICCC_ERROR_READ_FAILED;
    }

exit:

#ifdef DEBUG_ICCC_MEM
    Iccc_DumpParams_TA();
#endif

    return ret;
}

uint32_t Iccc_SaveATN_TA(uint8_t *blob, uint32_t *blob_len)
{
    uint32_t sectimer_header_size = sizeof(uint8_t) * 3; // Type(1 byte) + Length(2 Byte)
    uint32_t sectimer_type[2][2] = {
        {SECTIMER_BASE,     ICCC_ATN_RESULT_TYPE_SECTIMER_BASE},
        {SECTIMER_STATUS,   ICCC_ATN_RESULT_TYPE_SECTIMER_STATUS}
    };
    uint32_t sectimer_value;
    uint8_t digest[SHA256_DIGEST_LENGTH] = {0, };
    uint32_t digest_len = sizeof(digest);
    uint32_t ret = ICCC_SUCCESS;

    uint32_t secure_param_type;
    uint32_t secure_param_addr;
    uint32_t secure_mem_addr;
    uint16_t magic_str = 0;

    ICCC_LOG("ICCC: Iccc_SaveATN_TA: given blob from N/W, blob_len = %d", *blob_len);

    // Add securetimer value to blob before generate hash
    for (uint32_t i = 0; i < sizeof(sectimer_type) / sizeof(sectimer_type[0]); i++) {
        sectimer_value = -1;
        if (*blob_len + sectimer_header_size + sizeof(sectimer_value) > ICCC_ATN_BLOB_MAX_SIZE) {
            ICCC_LOG("ICCC: invalid blob length: (*blob_len + sectimer_header_size + sizeof(sectimer_value)) = 0x%x, ret = 0x%x",
                                                  *blob_len + sectimer_header_size + sizeof(sectimer_value), ret);
            return ICCC_ERROR_ATTESTATION_FAILED;
        }

        ret = Iccc_ReadData_TA(sectimer_type[i][0], &sectimer_value);
        if (ret) {
            ICCC_LOG("ICCC: Error reading sectimer type = 0x%x, value = %d, ret = 0x%x\n", sectimer_type[i][0], sectimer_value, ret);
            ret = ICCC_ERROR_ATTESTATION_FAILED;
            goto error;
        }
        sectimer_value = switch_endianness(sectimer_value);

        blob[(*blob_len)++] = sectimer_type[i][1];
        blob[(*blob_len)++] = 0;
        blob[(*blob_len)++] = sizeof(sectimer_value);
        TEE_MemMove(blob + *blob_len, (uint8_t *)&sectimer_value, sizeof(sectimer_value)); 
        *blob_len += sizeof(sectimer_value);

        ICCC_LOG("ICCC: ATN blob after adding sectimer type 0x%x", sectimer_type[i][0]);
    }

    // Generate digest
    ret = Iccc_digest_SHA256(blob, *blob_len, digest, &digest_len);
    if (ret) {
        ICCC_LOG("ICCC: Iccc_digest_SHA256 failed with ret = 0x%x\n", ret);
        ret = ICCC_ERROR_ATTESTATION_FAILED;
        goto error;
    }
    if (digest_len != SHA256_DIGEST_LENGTH) {
        ICCC_LOG("ICCC: invalid SHA256 digest length with ret = 0x%x, length = %d", ret, digest_len);
        ret = ICCC_ERROR_ATTESTATION_FAILED;
        goto error;
    }
    //ICCC_LOG("ICCC: sha256 result = %s", digest);

    // Save hash to secure memory
    secure_mem_addr = get_sec_ICCC_address(PARAM_FOR_ICCC_SEC_MEM);
    secure_param_type = (ATN_BLOB_HASH >> 20) & (0xF);
    secure_param_addr = (uint32_t)((ATN_BLOB_HASH & (0x1F)) * ICCC_SECURE_PARAMETERS_READING_LENGTH);

    ret = Iccc_check_magic(secure_param_type, secure_mem_addr, &magic_str);
    if (ret) {
        ICCC_LOG("ICCC: check magic failed");
        ICCC_LOG_DEBUG("ICCC: Iccc_check_magic failed with ret = %x ", ret);
        return ICCC_ERROR_ATTESTATION_FAILED;
    }
    if (secure_param_type == 0x0 && magic_str == TA_MAGIC_STR) {
        if (secure_param_addr > sizeof(ta_secure_info_t)) {
            ICCC_LOG("ICCC: secure_param_addr error");
            ICCC_LOG_DEBUG("ICCC: secure_param_addr > sizeof(ta_secure_info_t)");
            return ICCC_ERROR_ATTESTATION_FAILED;
        }
        if (0 != (ret = Iccc_phys_write((void *)(secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)),
                                                 SHA256_DIGEST_LENGTH, (void *)(digest)))) {
            ICCC_LOG("ICCC: Iccc_phys_write failed");
            ICCC_LOG_DEBUG("ICCC: Iccc_phys_write failed: (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)) = 0x%x, ret = 0x%x",
                                                          (secure_mem_addr + ICCC_TA_SECURE_PARAMETERS_OFFSET + secure_param_addr + sizeof(secure_param_header_t)), ret);
            ret = ICCC_ERROR_ATTESTATION_FAILED;
        }
    }

error:
    return ret;
}

static int is_sec_boot_secure(uint32_t value) {
    const uint32_t SEC_BOOT_SECURE_VALUE = 1;
    return value == SEC_BOOT_SECURE_VALUE ? true : false;
}

static int is_react_lock_secure(uint32_t value) {
    const uint32_t REACT_LOCK_SECURE_VALUE = 1;
    return value == REACT_LOCK_SECURE_VALUE ? true : false;
}

static int is_kiwi_lock_secure(uint32_t value) {
    const uint32_t KIWI_LOCK_SECURE_VALUE = 1;
    return value == KIWI_LOCK_SECURE_VALUE ? true : false;
}

static int is_frp_lock_secure(uint32_t value) {
    const uint32_t FRP_LOCK_SECURE_VALUE = 1;
    return value == FRP_LOCK_SECURE_VALUE ? true : false;
}

static int is_cc_mode_secure(uint32_t value) {
    const uint32_t CC_MODE_SECURE_VALUE = 1;
    return value == CC_MODE_SECURE_VALUE ? true : false;
}

static int is_curr_bin_status_secure(uint32_t value) {
    const uint32_t CURR_BIN_STATUS_SECURE_VALUE = 0;
    return value == CURR_BIN_STATUS_SECURE_VALUE ? true : false;
}

static int is_warranty_bit_secure(uint32_t value) {
    const uint32_t WARRANTY_BIT_SECURE_VALUE = 0;
    return value == WARRANTY_BIT_SECURE_VALUE ? true : false;
}

static int is_kap_secure(uint32_t value) {
    const uint32_t KAP_SECURE_VALUE = 1;
    return value == KAP_SECURE_VALUE ? true : false;
}

/**
  * 0:Market   User(01)      Official
  * 1:Factory  Eng(10)/Knox(11)  Custom
  *
  * Secure values:
  * No Download History  = 0 0 0 0
  * Market+User+Official = 0 0 1 0
  * Market+Knox+Official = 0 1 1 0
  * we are not using knox bit until now.
**/
static int is_image_status1_secure(uint32_t value) {
    const uint32_t IMAGE_STATUS1_SECURE_VALUE_NO_HISTORY = 0;
    const uint32_t IMAGE_STATUS1_SECURE_VALUE_USER = 2;
    return (value == IMAGE_STATUS1_SECURE_VALUE_NO_HISTORY) || (value == IMAGE_STATUS1_SECURE_VALUE_USER) ? true : false;
}

static int is_pkm_text_secure(uint32_t value) {
    const uint32_t PKM_TEXT_SECURE_VALUE = 0;
    const uint32_t PKM_TEXT_UNINITIALIZED_VALUE = -1;
    return (value == PKM_TEXT_SECURE_VALUE) || (value == PKM_TEXT_UNINITIALIZED_VALUE) ? true : false;
}

static int is_pkm_ro_secure(uint32_t value) {
    const uint32_t PKM_RO_SECURE_VALUE = 0;
    const uint32_t PKM_RO_UNINITIALIZED_VALUE = -1;
    return (value == PKM_RO_SECURE_VALUE) || (value == PKM_RO_UNINITIALIZED_VALUE) ? true : false;
}

static int is_selinux_secure(uint32_t value) {
    const uint32_t SELINUX_SECURE_VALUE = 0;
    const uint32_t SELINUX_UNINITIALIZED_VALUE = -1;
    return (value == SELINUX_SECURE_VALUE) || (value == SELINUX_UNINITIALIZED_VALUE) ? true : false;
}

static int is_dmv_secure(uint32_t value) {
    const uint32_t DMV_SECURE_VALUE = 0;
    return value == DMV_SECURE_VALUE ? true : false;
}

static int is_sysscope_secure(uint32_t value) {
    const uint32_t SYSSCOPE_INSECURE_VALUE = 1;
    return value != SYSSCOPE_INSECURE_VALUE ? true : false;
}

static int is_trust_boot_secure(uint32_t value) {
    const uint32_t TRUSTBOOT_SECURE_VALUE = 0;
    return value == TRUSTBOOT_SECURE_VALUE ? true : false;
}

#define ICCC_NUMBER_OF_COMPONENT_TYPES 2

typedef int (*iccc_status_check_func_t)(uint32_t);
typedef uint8_t comp_type_array_t[ICCC_NUMBER_OF_COMPONENT_TYPES];

#define INSECURE_MSG_TYPE 0
#define FLAG_NOT_READ 1

typedef struct {
    const char *name;
    const uint8_t name_size;
    const uint32_t type;
    const uint32_t type_bitwise;
    iccc_status_check_func_t is_secure;
    const uint8_t * comp_type_array;
} iccc_status_flags_t;

//                                                                HARD_INTEGRITY  SOFT_INTEGRITY
static comp_type_array_t const comp_types_for_sec_boot        = { false,          false  };
static comp_type_array_t const comp_types_for_react_lock      = { false,          false  };
static comp_type_array_t const comp_types_for_kiwi_lock       = { false,          false  };
static comp_type_array_t const comp_types_for_frp_lock        = { false,          false  };
static comp_type_array_t const comp_types_for_cc_mode         = { false,          false  };
static comp_type_array_t const comp_types_for_curr_bin_status = { false,          false  };
static comp_type_array_t const comp_types_for_warrant_bit     = { false,          true   };
static comp_type_array_t const comp_types_for_kap_status      = { false,          false  };
static comp_type_array_t const comp_types_for_image_status1   = { false,          false  };
static comp_type_array_t const comp_types_for_pkm_text        = { false,          false  };
static comp_type_array_t const comp_types_for_pkm_ro          = { false,          false  };
static comp_type_array_t const comp_types_for_selinux_status  = { false,          false  };
static comp_type_array_t const comp_types_for_dmv_status      = { false,          false  };
static comp_type_array_t const comp_types_for_sysscope_flag   = { false,          false  };
static comp_type_array_t const comp_types_for_trustboot_flag  = { true,           true   };

static iccc_status_flags_t const iccc_status_flags[] =
{
//   Name                          Size    Value             Bit value                         Function                   Component Types
    {"Secure Boot",                11,     SEC_BOOT,         ICCC_STATUS_FLAG_SEC_BOOT,        is_sec_boot_secure,        comp_types_for_sec_boot },
    {"Reactivation Lock",          17,     REACT_LOCK,       ICCC_STATUS_FLAG_REACT_LOCK,      is_react_lock_secure,      comp_types_for_react_lock },
    {"KIWI Lock",                   9,     KIWI_LOCK,        ICCC_STATUS_FLAG_KIWI_LOCK,       is_kiwi_lock_secure,       comp_types_for_kiwi_lock },
    {"Factory Reset Protection",   24,     FRP_LOCK,         ICCC_STATUS_FLAG_FRP_LOCK,        is_frp_lock_secure,        comp_types_for_frp_lock },
    {"CC Mode",                     7,     CC_MODE,          ICCC_STATUS_FLAG_CC_MODE,         is_cc_mode_secure,         comp_types_for_cc_mode },
    {"Current Binary Status",      21,     CURR_BIN_STATUS,  ICCC_STATUS_FLAG_CURR_BIN_STATUS, is_curr_bin_status_secure, comp_types_for_curr_bin_status },
    {"Warranty Bit",               12,     WARRANTY_BIT,     ICCC_STATUS_FLAG_WARRANT_BIT,     is_warranty_bit_secure,    comp_types_for_warrant_bit },
    {"Knox Active Protection",     22,     KAP_STATUS,       ICCC_STATUS_FLAG_KAP_STATUS,      is_kap_secure,             comp_types_for_kap_status },
    {"Status of Boot Image",       20,     IMAGE_STATUS1,    ICCC_STATUS_FLAG_IMAGE_STATUS1,   is_image_status1_secure,   comp_types_for_image_status1 },
    {"PKM Text",                    8,     PKM_TEXT,         ICCC_STATUS_FLAG_PKM_TEXT,        is_pkm_text_secure,        comp_types_for_pkm_text },
    {"PKM Read Only",              13,     PKM_RO,           ICCC_STATUS_FLAG_PKM_RO,          is_pkm_ro_secure,          comp_types_for_pkm_ro },
    {"SELINUX",                     7,     SELINUX_STATUS,   ICCC_STATUS_FLAG_SELINUX_STATUS,  is_selinux_secure,         comp_types_for_selinux_status },
    {"dm-verity",                   9,     DMV_STATUS,       ICCC_STATUS_FLAG_DMV_STATUS,      is_dmv_secure,             comp_types_for_dmv_status },
    {"Sysscope",                    8,     SYSSCOPE_FLAG,    ICCC_STATUS_FLAG_SYSSCOPE_FLAG,   is_sysscope_secure,        comp_types_for_sysscope_flag },
    {"Trusted Boot",               12,     TRUSTBOOT_FLAG,   ICCC_STATUS_FLAG_TRUSTBOOT_FLAG,  is_trust_boot_secure,      comp_types_for_trustboot_flag }
};

uint32_t append_to_result_msg(char *result_message, uint32_t *offset, uint32_t result_message_len, uint8_t type, const char *flag_name, const uint8_t flag_size)
{
    const char insecure_msg_preffix[] = "The value of ";
    const char read_error_msg_preffix[] = "The value of ";
    const char insecure_msg_suffix[] = " is insecure. ";
    const char read_error_msg_suffix[] = " could not be read. ";
    uint8_t insecure_msg_size = 0;
    uint8_t read_error_msg_size = 0;
    uint32_t init_offset = *offset;

    switch(type) {
        case INSECURE_MSG_TYPE:
            if ((sizeof(insecure_msg_preffix)) <= UINT8_MAX) {
                insecure_msg_size = sizeof(insecure_msg_preffix);
                if ((sizeof(insecure_msg_suffix)) > 0 && (insecure_msg_size <= (UINT8_MAX-(sizeof(insecure_msg_suffix))))) {
                    insecure_msg_size += (sizeof(insecure_msg_suffix));
                    if (flag_size > 0 && (insecure_msg_size <= UINT8_MAX - flag_size)) {
                        insecure_msg_size = insecure_msg_size + flag_size - 2;
                        if ((*offset + insecure_msg_size) < result_message_len) {
                            memcpy(result_message + *offset, insecure_msg_preffix, sizeof(insecure_msg_preffix) - 1);
                            *offset += sizeof(insecure_msg_preffix) - 1;
                            memcpy(result_message + *offset, flag_name, flag_size);
                            *offset += flag_size;
                            memcpy(result_message + *offset, insecure_msg_suffix, sizeof(insecure_msg_suffix) - 1);
                            *offset += sizeof(insecure_msg_suffix) - 1;
                            *offset -= init_offset;
                        }
                    }
                }
            }
            break;
        case FLAG_NOT_READ:
            if ((sizeof(read_error_msg_preffix)) <= UINT8_MAX) {
                read_error_msg_size = sizeof(read_error_msg_preffix);
                if ((sizeof(read_error_msg_suffix)) > 0 && (read_error_msg_size <= (UINT8_MAX-(sizeof(read_error_msg_suffix))))) {
                    read_error_msg_size += (sizeof(read_error_msg_suffix));
                    if (flag_size > 0 && (read_error_msg_size <= UINT8_MAX - flag_size)) {
                        read_error_msg_size = read_error_msg_size + flag_size - 2;
                        if ((*offset + read_error_msg_size) < result_message_len) {
                            memcpy(result_message + *offset, read_error_msg_preffix, sizeof(read_error_msg_preffix) - 1);
                            *offset += sizeof(read_error_msg_preffix) - 1;
                            memcpy(result_message + *offset, flag_name, flag_size);
                            *offset += flag_size;
                            memcpy(result_message + *offset, read_error_msg_suffix, sizeof(read_error_msg_suffix) - 1);
                            *offset += sizeof(read_error_msg_suffix) - 1;
                            *offset -= init_offset;
                        }
                    }
                }
            }
            break;
    }

    return *offset;
}

uint32_t check_flag(char *result_message, uint32_t *offset, const iccc_status_flags_t *flag)
{
    uint32_t value;
    uint32_t read_result;
    uint32_t ret = ICCC_STATUS_RETURN_SECURE;

    read_result = Iccc_ReadData_TA(flag->type, &value);
    if (read_result == ICCC_SUCCESS) {
        if (flag->is_secure(value)) {
        // The Secure message is printed later.
        ret = ICCC_STATUS_RETURN_SECURE;
        } else {
        append_to_result_msg(result_message, offset, ICCC_STATUS_MAX_RESULT_MESSAGE, INSECURE_MSG_TYPE, flag->name, flag->name_size);
        ret = ICCC_STATUS_RETURN_NOT_SECURE;
        }
    } else {
        append_to_result_msg(result_message, offset, ICCC_STATUS_MAX_RESULT_MESSAGE, FLAG_NOT_READ, flag->name, flag->name_size);
        ret = ICCC_STATUS_RETURN_FAILURE_TO_READ;
    }
    return ret;
}

uint32_t ICCC_device_status_check_flags(uint32_t comp_type, uint32_t *result_code, char *result_message)
{
    uint32_t result_check;
    uint32_t offset = 0;
    const char device_secure_msg[] = "Device Secure.";
    uint32_t i = 0;

    *result_code = ICCC_STATUS_RETURN_SECURE;
    for (i = 0; i < (sizeof(iccc_status_flags) / sizeof(iccc_status_flags_t)); i++) {
        if (iccc_status_flags[i].comp_type_array[comp_type - 1]) { // tz_iccc_device_status_comp_type_t starts on 1
            ICCC_LOG("ICCC: Checking flag %d for component %d", i, comp_type);
            result_check = check_flag(result_message, &offset, &iccc_status_flags[i]);
            if(result_check != ICCC_STATUS_RETURN_SECURE) {
                *result_code |= iccc_status_flags[i].type_bitwise;
            }
        }
    }

    if (*result_code == ICCC_STATUS_RETURN_SECURE) {
        memcpy(result_message, device_secure_msg, strlen(device_secure_msg));
    } else {
        // Remove the trailing space
        result_message[offset - 1] = '\0';
    }

    return ICCC_SUCCESS;
}

uint32_t Iccc_DeviceStatus_TA(uint32_t comp_type, uint8_t *resp_msg_buf, uint32_t resp_msg_buf_size, uint32_t *resp_msg_len, uint32_t *result_code)
{
    uint32_t ret = ICCC_ERROR_DEVICE_STATUS_FAILED;

    if (resp_msg_buf == NULL) {
        ICCC_LOG("ICCC: Iccc_DeviceStatus_TA: resp_msg_buf NULL");
        return ret;
    }

    if (resp_msg_buf_size < ICCC_STATUS_MAX_RESULT_MESSAGE) {
        ICCC_LOG("ICCC: Iccc_DeviceStatus_TA: resp_msg_buf_size < ICCC_STATUS_MAX_RESULT_MESSAGE");
        return ret;
    }
    if (comp_type < ICCC_STATUS_COMP_TYPE_HARD_INTEGRITY || comp_type > ICCC_STATUS_COMP_TYPE_SOFT_INTEGRITY) {
        ICCC_LOG("ICCC: Iccc_DeviceStatus_TA: comp_type %d", comp_type);
        return ret;
    }

    memset(resp_msg_buf, 0, resp_msg_buf_size); // invalid resp_msg_buf log

    ret = ICCC_device_status_check_flags(comp_type, result_code, (char *)resp_msg_buf);
    if (ret != ICCC_SUCCESS) {
        ICCC_LOG("ICCC: error checking flags");
        return ret;
    }

    (*resp_msg_len) = strlen((char *)resp_msg_buf);

    ICCC_LOG("ICCC: Device Status comp_type = %d ret = %d", comp_type, ret);
    ICCC_LOG("ICCC: Device Status resp_msg_buf = %s resp_msg_len = %d", (char *)resp_msg_buf, *resp_msg_len);
    return ret;
}

#if defined (CONFIG_SUPPORT_ICCC_INIT)
uint32_t Iccc_ReadData_TAForTB(uint8_t *p_msr_buf, uint32_t p_msr_size)
{
    uint32_t value;
    uint32_t ret = ICCC_INIT_ERROR;

    ICCC_LOG_DEBUG("ICCC: ICCC_ReadData_TAForTB, p_msr_size: %d", p_msr_size);

    ret = ICCC_init_TB(p_msr_buf, 0);
    if (ret == ICCC_INIT_UNINITIALIZED_SECURE_MEM) {
        ret = ICCC_init_TB(p_msr_buf, p_msr_size);
    }

    if (ret) {
        ICCC_LOG("ICCC: ICCC Read Data TA For TB error!");
        ICCC_LOG_DEBUG("ICCC: End of ICCC_ReadData_TAForTB, error= %x", ret);
        return ret;
    } else {
        Iccc_ReadData_TA(TRUSTBOOT_FLAG, &value);
        ICCC_LOG("ICCC: End of ICCC Read Data TA For TB");
        ICCC_LOG_DEBUG("ICCC: End of ICCC_ReadData_TAForTB, TB = %x", value);
        return value;
    }
}
#endif

#ifdef DEBUG_ICCC_MEM
#define DUMP_SIZE ((uint32_t)sizeof(bl_secure_info_t))
uint32_t print_param_value(char *param_offset_type, uint32_t param_offset_value, uint32_t read_size) {
    uint32_t ret;
    uint32_t secure_param_addr;
    uint32_t secure_mem_addr;
    uint32_t secure_addr;
    uint32_t secure_value;
    uint32_t *value = &secure_value;
    char dump_buf[DUMP_SIZE] = {0, };

    secure_mem_addr = get_sec_ICCC_address(PARAM_FOR_ICCC_SEC_MEM);
    secure_addr = secure_mem_addr + param_offset_value;

    memset(dump_buf, 0, DUMP_SIZE);
    if (0 != (ret = Iccc_phys_read((void *)secure_addr, read_size, (void *)dump_buf))) {
        ICCC_LOG("ICCC: Iccc_phys_read failed: (secure_mem_addr + %s) = 0x%x, ret = 0x%x", 
                                               param_offset_type, secure_addr, ret);
        //ret = ICCC_ERROR_READ_FAILED;
    }

    //ICCC_LOG("ICCC: DUMP_SIZE : %d, read_size : %d", DUMP_SIZE, read_size);
    ICCC_LOG("ICCC: ADDRESS[0x%x]: ", secure_addr);
    for (int i = 0; i < read_size;) {
        int j = 0;
        for (j = 0; j < 16 && i + j < read_size; j++) {
            if (j > 0 && j % 4 == 0) printf(" ");
            printf("%02x", dump_buf[i + j]);
        }

        printf("\t\t");
        for (j = 0; j < 16 && i + j < read_size; j++) {
            if (j > 0 && j % 4 == 0) printf(" ");
            if (dump_buf[i + j] <= 0x1F)
                printf(".");
            else
                printf("%c", dump_buf[i + j]);
        }
        printf("\n");

        i += j;
    }
    
    return ICCC_SUCCESS;
}

uint32_t Iccc_DumpParams_TA() {
    uint32_t start_param_idx;
    uint32_t end_param_idx;
    
    ICCC_LOG("ICCC: ICCC_DUMP_PARAMS");

    ICCC_LOG("ICCC: ---------- BL PARAMS ----------");
    print_param_value("ICCC_BL_SECURE_PARAMETERS_OFFSET", ICCC_BL_SECURE_PARAMETERS_OFFSET,
                        sizeof(bl_secure_info_t));


    ICCC_LOG("ICCC: ---------- TA PARAMS ----------");
    print_param_value("ICCC_TA_SECURE_PARAMETERS_OFFSET", ICCC_TA_SECURE_PARAMETERS_OFFSET, 
                        sizeof(ta_secure_info_t));


    ICCC_LOG("ICCC: ---------- KERNEL PARAMS ----------");
    print_param_value("ICCC_KERN_SECURE_PARAMETERS_OFFSET", ICCC_KERN_SECURE_PARAMETERS_OFFSET, 
                        sizeof(kern_secure_info_t));


    ICCC_LOG("ICCC: ---------- SYSTEM PARAMS ----------");
    print_param_value("ICCC_SYS_SECURE_PARAMETERS_OFFSET", ICCC_SYS_SECURE_PARAMETERS_OFFSET, 
                        sizeof(sys_secure_info_t));


#ifdef CONFIG_ROT_IN_ICCC
    ICCC_LOG("ICCC: ---------- ROT PARAMS ----------");
    print_param_value("ICCC_ROT_SECURE_PARAMETERS_OFFSET", ICCC_ROT_SECURE_PARAMETERS_OFFSET, 
                        sizeof(rot_secure_info_t));
#endif

    return ICCC_SUCCESS;
}
#endif

#endif // ICCC_v4
