
/*
 * =====================================================================================
 *
 *       Filename:  hdm_hypervisor.c
 *
 *    Description:  HDM hypervisor manipulation
 *
 *        Version:  1.0
 *        Created:  09/16/2019 15:26:11 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2015 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "hdm_hypervisor.h"

/**
 * @brief
 * hdm_deregister_shared_buffer
 * Clear and deregister Shared Buffer Area.
 * Returns current policy
 * 
 * @param[in] policy - current applied policy
 * @return TEE_Result
*/
TEE_Result hdm_deregister_shared_buffer(uint32_t *policy) {
        uint32_t *hdm_address = (uint32_t*) HDM_SHARED_MEM_BASE_ADDR;
        hdm_shared_mem_data_t hdm_hyp_shared_mem_data;
        TEE_Result ret = TEE_SUCCESS;

        HDM_LOG_DEBUG("start of %s", __func__);
//        HDM_LOG_DEBUG("hdm_address is 0x%x", (unsigned int) hdm_address);
        
        /* Initialize local values with 0xFFFFF */
        TEE_MemFill(&hdm_hyp_shared_mem_data, HDM_HYPERVISOR_INVALID, sizeof(hdm_shared_mem_data_t));

        ret = qsee_prepare_shared_buf_for_secure_read(hdm_address, HDM_SHARED_MEM_LEN);
        if (ret != TEE_SUCCESS) {
                HDM_LOG("Failed to Prepare Shared Buffer for Secure Read, ret = 0x%x", ret);
                goto deregister;
        }
        HDM_LOG_DEBUG("%s: qsee_prepare_shared_buf_for_secure_read is success", __func__);

        TEE_MemMove(&hdm_hyp_shared_mem_data, hdm_address, sizeof(hdm_shared_mem_data_t));
#ifdef DEBUG_HDM
        HDM_LOG_DEBUG("hdm_address[magic]   = 0x%02x", hdm_hyp_shared_mem_data.magic);
        HDM_LOG_DEBUG("hdm_address[command] = 0x%02x", hdm_hyp_shared_mem_data.command);
        HDM_LOG_DEBUG("hdm_address[policy]  = 0x%02x", hdm_hyp_shared_mem_data.policy);
        HDM_LOG_DEBUG("hdm_address[ret]     = 0x%02x", hdm_hyp_shared_mem_data.ret);
#endif

        /* Clear the Area */
        TEE_MemFill(hdm_address, 0x0, sizeof(hdm_shared_mem_data_t));

        ret = qsee_prepare_shared_buf_for_nosecure_read(hdm_address, HDM_SHARED_MEM_LEN);
        if (ret != TEE_SUCCESS) {
                HDM_LOG("Failed to Prepare Shared Buffer for Non-Secure Read, ret = 0x%x", ret);
                goto deregister;
        }
        HDM_LOG_DEBUG("%s: qsee_prepare_shared_buf_for_nosecure_read is success", __func__);
        HDM_LOG("Shared Buffer Cleared with success!");

deregister:
        ret = qsee_deregister_shared_buffer(hdm_address);
        if(ret != TEE_SUCCESS) {
                HDM_LOG("Failed to Deregister Shared Buffer");
                ret = HDM_DEREGISTER_SHARED_BUF_FAIL;
                goto exit;
        }
        HDM_LOG_DEBUG("%s: qsee_deregister_shared_buffer is success", __func__);
        HDM_LOG("Shared Buffer Deregistered with success!");

exit:
        if (hdm_hyp_shared_mem_data.magic != HDM_MAGIC) {
                HDM_LOG("Hypervisor MAGIC is wrong, hdm_hyp_shared_mem_data.magic = 0x%x", hdm_hyp_shared_mem_data.magic);
                ret = HDM_APPLY_POLICY_FAIL;
        }

        if (hdm_hyp_shared_mem_data.command != HDM_HYPERVISOR_CMD_RET) {
                HDM_LOG("Hypervisor command is wrong, hdm_hyp_shared_mem_data.command = 0x%x", hdm_hyp_shared_mem_data.command);
                ret = HDM_APPLY_POLICY_FAIL;
        }

        if (hdm_hyp_shared_mem_data.ret != HDM_HYPERVISOR_RETURN_OK) {
                HDM_LOG("Hypervisor returned an error, hdm_hyp_shared_mem_data.ret = 0x%x", hdm_hyp_shared_mem_data.ret);
                ret = HDM_APPLY_POLICY_FAIL;
        }

        *policy = hdm_hyp_shared_mem_data.policy;
        TEE_MemFill(&hdm_hyp_shared_mem_data, HDM_HYPERVISOR_INVALID, sizeof(hdm_shared_mem_data_t));

        return ret;
}

/**
 * @brief
 * hypervisor_communication
 * If command is write: Apply command bitmap (device block) on hypervisor.
 * If command is read: policy is useless
 *
 * @param[in] policy - policy device block
 * @param[in] command - read/write operation
 * @return TEE_Result
*/
TEE_Result hypervisor_communication(uint32_t policy, uint32_t command) {
        uint32_t *hdm_address = (uint32_t*) HDM_SHARED_MEM_BASE_ADDR;
        hdm_shared_mem_data_t *hdm_shared_mem_data;
        TEE_Result ret = TEE_SUCCESS;

        HDM_LOG_DEBUG("start of %s", __func__);
//        HDM_LOG_DEBUG("hdm_address is 0x%x", (unsigned int) hdm_address);

        ret = qsee_register_shared_buffer(hdm_address, HDM_SHARED_MEM_LEN);
        if (ret != TEE_SUCCESS) {
                HDM_LOG("Failed to Register Shared Buffer, ret = 0x%x", ret);
                return HDM_REGISTER_SHARED_BUF_FAIL;
        }
        HDM_LOG_DEBUG("%s: qsee_register_shared_buffer is success", __func__);

        ret = qsee_prepare_shared_buf_for_secure_read(hdm_address, HDM_SHARED_MEM_LEN);
        if (ret != TEE_SUCCESS) {
                HDM_LOG("Failed to Prepare Shared Buffer for Secure Read, ret = 0x%x", ret);
                goto deregister;
        }
        HDM_LOG_DEBUG("%s: qsee_prepare_shared_buf_for_secure_read is success", __func__);

        hdm_shared_mem_data = TEE_Malloc(sizeof(hdm_shared_mem_data_t), 0);
        if(hdm_shared_mem_data == NULL){
                HDM_LOG("Error to alloc memory");
                goto deregister;
        }

        hdm_shared_mem_data->magic = HDM_MAGIC;
        hdm_shared_mem_data->command = command;
        hdm_shared_mem_data->policy = policy;
        hdm_shared_mem_data->ret = HDM_STATUS_SUCCESS;

        TEE_MemMove(hdm_address, hdm_shared_mem_data, sizeof(hdm_shared_mem_data_t));
        TEE_Free(hdm_shared_mem_data);

#ifdef DEBUG_HDM
        hdm_shared_mem_data = (hdm_shared_mem_data_t *) hdm_address;
        HDM_LOG_DEBUG("hdm_address[magic]   = 0x%02x", hdm_shared_mem_data->magic);
        HDM_LOG_DEBUG("hdm_address[command] = 0x%02x", hdm_shared_mem_data->command);
        HDM_LOG_DEBUG("hdm_address[policy]  = 0x%02x", hdm_shared_mem_data->policy);
        HDM_LOG_DEBUG("hdm_address[ret]     = 0x%02x", hdm_shared_mem_data->ret);
#endif

        ret = qsee_prepare_shared_buf_for_nosecure_read(hdm_address, HDM_SHARED_MEM_LEN);
        if (ret != TEE_SUCCESS) {
                HDM_LOG("Failed to Prepare Shared Buffer for Non-Secure Read, ret = 0x%x", ret);
                goto clean;
        }
        HDM_LOG_DEBUG("%s: qsee_prepare_shared_buf_for_nosecure_read is success", __func__);
        HDM_LOG("Shared Buffer registered with success!");
        return ret;

clean:
        TEE_MemFill(hdm_address, 0x0, sizeof(hdm_shared_mem_data_t));

deregister:
        ret = qsee_deregister_shared_buffer(hdm_address);
        if(ret != TEE_SUCCESS) {
                HDM_LOG("Failed to Deregister Shared Buffer");
                ret = HDM_REGISTER_SHARED_BUF_FAIL;
        }
        HDM_LOG_DEBUG("%s: qsee_deregister_shared_buffer is success", __func__);

        return ret;
}
