/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2018-2025 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/



/*******************************************************************************
 * DESCRIPTION   : ICUMIF control function
 ******************************************************************************/
/******************************************************************************
 * @file          secure_boot.c
 * - Version      : 0.08
 * @brief         ICUMIF controller.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 16.06.2022 0.01     First Release
 *         : 22.07.2022 0.02     Change CMAC address settings
 *                               Added include file
 *                               Changed for Warning measures
 *         : 31.10.2022 0.03     License notation change.
 *         : 07.12.2022 0.04     Warning support when log output is disabled
 *         : 15.02.2023 0.05     Added final_hash_cmp function.
 *         : 04.04.2023 0.06     Removed stdio.h.
 *         : 21.08.2023 0.07     Add support for V4M.
 *         : 14.01.2024 0.08     Add parameter setting process for RTOS#1/#2.
 *****************************************************************************/
#include "log.h"
#include "timer.h"
#include "r_icumif_api.h"
#include "r_icumif_pub.h"
#include "icum_d_comm_pe_pub.h"
#include "shared.h"
#include "image_load.h"
#include "secure_boot.h"
#include "rst_register.h"

#define LCS_CM                  (0x00000000U)   /* CM */
#define LCS_DM                  (0x00000001U)   /* DM */
#define LCS_SD                  (0x00000003U)   /* SD */
#define LCS_SE                  (0x00000005U)   /* SE */
#define LCS_FA                  (0x00000007U)   /* FA */

#define RST_MODEMR0_MD5         (0x00000020U)

#define CX_CMAC_COPY            (4U)
#define CX_ICUMIF_STATUS        (0x1000F800UL)
#define CX_SIZEOF_CNT           (4U)
#define CX_CMAC_SIZE            (16U)

/* Definitions for hash_cmp */
#define HASH_CMP_NUM                (0x2U)          /* The number of hash check images */
#define HASH_SIZE                   (32U)           /* Hash size (32-bytes) */
#define CR52_IPL_HASH_SAVE_ADDR     (0xE635FF40U)   /* Hash save address for CR52 IPL */
#define SECURE_FW_HASH_SAVE_ADDR    (0xE635FFC0U)   /* Hash save address for Secure FW */

static void secureboot_memset(void *buff, uint32_t data, uint32_t cnt);
static void secureboot_service(r_icumif_isd_t *p_ISD);

void secureboot_init(void)
{
    int32_t           r_errno;
    volatile uint32_t *status;

    status = (volatile uint32_t *)R_ICUMIF_GetStatus();

    /* Wait until the ICU-M system intialization is complete */
    while(true)
    {
        if((*status & CX_ICUMIF_STATUS) != 0UL)
        {
            break;
        }
        else
        {
            micro_wait(100U);    /* 100 micro sec */
        }
    }

    r_errno = R_ICUMIF_Init((uint32_t *)((uintptr_t)MEM_INFO_SERVICEQUE_1_ADDR));
    if(r_errno != R_ICUMIF_ER_OK)
    {
        ERROR("R_ICUMIF_Init:Error code = (0x%x).\n", (unsigned int)r_errno);
        panic;
    }

}
/* End of function secureboot_init(void) */

uint32_t judge_bootmode(void)
{
    uint32_t       *p_lcs;
    r_icumif_isd_t *p_ISD;
    uint32_t       md;
    uint32_t       is_verify = SECURE_BOOT;

    __attribute__((unused))const char *lcs_name[8U] = {
        [LCS_CM] = "CM",
        [LCS_DM] = "DM",
        [LCS_SD] = "SD",
        [LCS_SE] = "SE",
        [LCS_FA] = "FA",
    };

    secureboot_memset(ISD_BUFFER, 0U, SIZE_OF_ISD_BUFFER);
    secureboot_memset(LCS_BUFFER, 0U, SIZE_OF_LCS_BUFFER);

    /* initialize the global icum service header */
    p_ISD = (r_icumif_isd_t *)ISD_BUFFER;
    p_lcs = (uint32_t *)LCS_BUFFER;

    p_ISD->service_id         = SERVICE_00_SECURE_BOOT_API;
    p_ISD->ptr.p_callbackfunc = NULL;
    p_ISD->job_id             = 0U;
    p_ISD->res_nointerrupt    = R_ICUMIF_REQRES_NOINTERRPUT;

    p_ISD->prm.SECURE_BOOT_API.boot_api_id                   = ROM_GET_LCS;
    p_ISD->prm.SECURE_BOOT_API.api.get_lcs.ptr.p_lcs         = p_lcs;
    p_ISD->prm.SECURE_BOOT_API.api.get_lcs.lcs_size_in_bytes = SIZE_OF_LCS_BUFFER;

    /* trigger the service request */
    secureboot_service(p_ISD);

    if(ROMAPI_OK != p_ISD->prm.SECURE_BOOT_API.api_return_value)
    {
        ERROR("SECURE_BOOT_API:Error code = (0x%x).\n",
            (unsigned int)p_ISD->prm.SECURE_BOOT_API.api_return_value);
        panic;
    }
    else
    {
        /* LCM Status check */
        if(( LCS_CM != *p_lcs)
        && ( LCS_DM != *p_lcs)
        && ( LCS_SD != *p_lcs)
        && ( LCS_SE != *p_lcs)
        && ( LCS_FA != *p_lcs))
        {
            ERROR("LCM state error. LCS = 0x%x\n", (unsigned int)*p_lcs );
            panic;
        }
        else
        {
            NOTICE("LCM state is %s\n",lcs_name[*p_lcs]);
        }
    }

    md = (mem_read32(RST_MODEMR0) & RST_MODEMR0_MD5) >> 5U;

    if (LCS_SD == *p_lcs)
    {
        /* LCS=SD => Normal boot */
        is_verify = NORMAL_BOOT;
    }
    else if ((LCS_SE != *p_lcs) && ( 1U == md))
    {
        /* LCS=CM/DM/FA and MD5=1 => Normal boot */
        is_verify = NORMAL_BOOT;
    }
    else
    {
        /* LCS=SE => Secure boot */
        /* LCS=CM/DM/FA and MD5=0 => Secure boot */
        is_verify = SECURE_BOOT;
    }

    if (NORMAL_BOOT != is_verify)
    {
#if (RCAR_LSI == RCAR_S4)
       NOTICE("Secure boot(CA55 Loader)\n");
#elif ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
    #ifdef AARCH64
       NOTICE("Secure boot(CA76 Loader)\n");
    #else
       NOTICE("Secure boot(CR52 Loader)\n");
    #endif
#endif /* RCAR_LSI == RCAR_S4 */
    }
    else
    {
#if (RCAR_LSI == RCAR_S4)
        NOTICE("Normal boot(CA55 Loader)\n");
#elif ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
    #ifdef AARCH64
        NOTICE("Normal boot(CA76 Loader)\n");
    #else
        NOTICE("Normal boot(CR52 Loader)\n");
    #endif
#endif /* RCAR_LSI == RCAR_S4 */
    }

    return is_verify;

}
/* End of function judge_bootmode(void) */

void secureboot_verify(LOAD_INFO* li, uint32_t start, uint32_t end)
{
    uint32_t            *p_cmac;
    r_icumif_isd_t      *p_ISD;
    uint32_t            loop;
    uint32_t            i;
    volatile uintptr_t  p_content_cert;
    volatile uintptr_t  p_key_cert;

    secureboot_memset(ISD_BUFFER, 0U, SIZE_OF_ISD_BUFFER);

    p_ISD = (r_icumif_isd_t *)ISD_BUFFER;

    /* Set Load info parameter */
    for (loop = start; loop < end; loop++)
    {
        secureboot_memset(CMAC_BUFFER, 0U, SIZE_OF_CMAC_BUFFER);
        p_cmac = (uint32_t *)CMAC_BUFFER;
        p_ISD->service_id         = SERVICE_00_SECURE_BOOT_API;
        p_ISD->ptr.p_callbackfunc = NULL;
        p_ISD->job_id             = 0U;
        p_ISD->res_nointerrupt    = R_ICUMIF_REQRES_NOINTERRPUT;

        p_ISD->prm.SECURE_BOOT_API.boot_api_id
                                            = ROM_SECURE_BOOT_VERIFY;
        p_key_cert     = li[loop].key_cert_addr;
        p_content_cert = li[loop].cnt_cert_addr;

        p_ISD->prm.SECURE_BOOT_API.api.
            boot_verify.ptr1.p_key_cert     = (uint32_t*)p_key_cert;
        p_ISD->prm.SECURE_BOOT_API.api.
            boot_verify.ptr2.p_content_cert = (uint32_t*)p_content_cert;
        p_ISD->prm.SECURE_BOOT_API.api.
            boot_verify.ptr3.p_cmac         = p_cmac;

        /* trigger the service request */
        secureboot_service(p_ISD);
        if(ROMAPI_OK != p_ISD->prm.SECURE_BOOT_API.api_return_value)
        {
            ERROR("SECURE_BOOT_API:Error code = (0x%x).\n",
                (unsigned int)p_ISD->prm.SECURE_BOOT_API.api_return_value);
            panic;
        }
        else
        {
            for (i = 0U; i < CX_CMAC_COPY; i++)
            {
                li[loop].cmac[i] = *(p_cmac++);
            }
        }
    }

#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
    /* Set Load info parameter */
    /* For RTOS#0 */
    secureboot_memset(CMAC_BUFFER, 0U, CX_CMAC_SIZE);
    p_cmac = (uint32_t *)CMAC_BUFFER;
    p_ISD->service_id         = SERVICE_00_SECURE_BOOT_API;
    p_ISD->ptr.p_callbackfunc = NULL;
    p_ISD->job_id             = 0U;
    p_ISD->res_nointerrupt    = R_ICUMIF_REQRES_NOINTERRPUT;

    p_ISD->prm.SECURE_BOOT_API.boot_api_id
                                        = ROM_SECURE_BOOT_VERIFY;
    p_key_cert     = li[RTOS_ID].key_cert_addr;
    p_content_cert = li[RTOS_ID].cnt_cert_addr;

    p_ISD->prm.SECURE_BOOT_API.api.
        boot_verify.ptr1.p_key_cert     = (uint32_t*)p_key_cert;
    p_ISD->prm.SECURE_BOOT_API.api.
        boot_verify.ptr2.p_content_cert = (uint32_t*)p_content_cert;
    p_ISD->prm.SECURE_BOOT_API.api.
        boot_verify.ptr3.p_cmac         = p_cmac;

    /* trigger the service request */
    secureboot_service(p_ISD);
    if(ROMAPI_OK != p_ISD->prm.SECURE_BOOT_API.api_return_value)
    {
        ERROR("SECURE_BOOT_API:Error code = (0x%x).\n",
            (unsigned int)p_ISD->prm.SECURE_BOOT_API.api_return_value);
        panic;
    }
    else
    {
        for (i = 0U; i < CX_CMAC_COPY; i++)
        {
            li[RTOS_ID].cmac[i] = *(p_cmac++);
        }
    }

#if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3)
    /* For RTOS#1,RTOS#2 */
    for (loop = RTOS1_ID; loop <= RTOS2_ID; loop++)
    {
        secureboot_memset(CMAC_BUFFER, 0U, CX_CMAC_SIZE);
        p_cmac = (uint32_t *)CMAC_BUFFER;
        p_ISD->service_id         = SERVICE_00_SECURE_BOOT_API;
        p_ISD->ptr.p_callbackfunc = NULL;
        p_ISD->job_id             = 0U;
        p_ISD->res_nointerrupt    = R_ICUMIF_REQRES_NOINTERRPUT;

        p_ISD->prm.SECURE_BOOT_API.boot_api_id
                                            = ROM_SECURE_BOOT_VERIFY;
        p_key_cert     = li[loop].key_cert_addr;
        p_content_cert = li[loop].cnt_cert_addr;

        p_ISD->prm.SECURE_BOOT_API.api.
            boot_verify.ptr1.p_key_cert     = (uint32_t*)p_key_cert;
        p_ISD->prm.SECURE_BOOT_API.api.
            boot_verify.ptr2.p_content_cert = (uint32_t*)p_content_cert;
        p_ISD->prm.SECURE_BOOT_API.api.
            boot_verify.ptr3.p_cmac         = p_cmac;

        /* trigger the service request */
        secureboot_service(p_ISD);
        if(ROMAPI_OK != p_ISD->prm.SECURE_BOOT_API.api_return_value)
        {
            ERROR("SECURE_BOOT_API:Error code = (0x%x).\n",
                (unsigned int)p_ISD->prm.SECURE_BOOT_API.api_return_value);
            panic;
        }
        else
        {
            for (i = 0U; i < CX_CMAC_COPY; i++)
            {
                li[loop].cmac[i] = *(p_cmac++);
            }
        }
    }
#endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */
#endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */

}
/* End of function secureboot_verify(void) */

int secureboot_image(LOAD_INFO* li, int do_panic)
{
    uint32_t       *p_cmac;
    uint32_t       *p_hash;
    r_icumif_isd_t *p_ISD;
    uint32_t       i;
    volatile uintptr_t  p_content_cert;

    secureboot_memset(ISD_BUFFER, 0U, SIZE_OF_ISD_BUFFER);
    secureboot_memset(CMAC_BUFFER, 0U, SIZE_OF_CMAC_BUFFER);
    secureboot_memset(HASH_BUFFER, 0U, SIZE_OF_HASH_BUFFER);

    /* initialize the global icum service header */
    p_ISD = (r_icumif_isd_t *)ISD_BUFFER;
    p_cmac = (uint32_t *)CMAC_BUFFER;
    p_hash = (uint32_t *)HASH_BUFFER;

    for (i = 0U; i < CX_CMAC_COPY; i++)
    {
        *(p_cmac++) = li->cmac[i];
    }

    p_ISD->service_id         = SERVICE_00_SECURE_BOOT_API;
    p_ISD->ptr.p_callbackfunc = NULL;
    p_ISD->job_id             = 0U;
    p_ISD->res_nointerrupt    = R_ICUMIF_REQRES_NOINTERRPUT;

    p_ISD->prm.SECURE_BOOT_API.boot_api_id = ROM_SECURE_BOOT_DECRYPT;

    p_content_cert = li->cnt_cert_addr;

    p_ISD->prm.SECURE_BOOT_API.api.
        boot_decrypt.ptr1.p_content_cert   = (uint32_t*)p_content_cert;
    p_ISD->prm.SECURE_BOOT_API.api.
        boot_decrypt.ptr2.p_cmac           = (uint32_t *)CMAC_BUFFER;

    /* trigger the service request */
    secureboot_service(p_ISD);
    if(( ROMAPI_OK != p_ISD->prm.SECURE_BOOT_API.api_return_value) &&
        (ROM_ERR_IMG_VERIFIER_NO_ENCRYPT_IMG != p_ISD->prm.SECURE_BOOT_API.api_return_value))
    {
        ERROR("SECURE_BOOT_API:Error code = (0x%x).\n",
            (unsigned int)p_ISD->prm.SECURE_BOOT_API.api_return_value);
        if (do_panic)
            panic;
        else
            return -1;
    }

    p_ISD->service_id         = SERVICE_00_SECURE_BOOT_API;
    p_ISD->ptr.p_callbackfunc = NULL;
    p_ISD->job_id             = 0U;
    p_ISD->res_nointerrupt    = R_ICUMIF_REQRES_NOINTERRPUT;

    p_ISD->prm.SECURE_BOOT_API.boot_api_id = ROM_SECURE_BOOT_COMPARE;

    p_ISD->prm.SECURE_BOOT_API.api.
        boot_compare.ptr1.p_content_cert   = (uint32_t*)p_content_cert;
    p_ISD->prm.SECURE_BOOT_API.api.
        boot_compare.ptr2.p_hash           = p_hash;
    p_ISD->prm.SECURE_BOOT_API.api.
        boot_compare.hash_size_in_bytes    = SIZE_OF_HASH_BUFFER;
    p_ISD->prm.SECURE_BOOT_API.api.
        boot_compare.ptr3.p_cmac           = (uint32_t *)CMAC_BUFFER;

    /* trigger the service request */
    secureboot_service(p_ISD);
    if(ROMAPI_OK != p_ISD->prm.SECURE_BOOT_API.api_return_value)
    {
        ERROR("SECURE_BOOT_API:Error code = (0x%x).\n",
           (unsigned int)p_ISD->prm.SECURE_BOOT_API.api_return_value);
        if (do_panic)
            panic;
        else
            return -1;
    }

    return 0;
}
/* End of function secureboot_image(LOAD_INFO* li) */


static void secureboot_memset(void *buff, uint32_t data, uint32_t cnt)
{
    uint32_t *tmp = NULL;
	uint32_t loop = cnt / CX_SIZEOF_CNT;    /* Copy 4 bytes at a time */
    tmp = (uint32_t *)buff;

    if (buff == NULL)
    {
        return;
    }

    while (loop > 0U)
    {
        *tmp = data;
        tmp++;
        loop--;
    }
}/* End of function secureboot_memset(void *buff, uint32_t data, uint32_t cnt) */

static void secureboot_service(r_icumif_isd_t *p_ISD)
{
    int32_t r_errno;

    /* trigger the service request */
    r_errno = R_ICUMIF_ServiceRequest(p_ISD);
    if(R_ICUMIF_ER_OK != r_errno)
    {
        ERROR("R_ICUMIF_ServiceRequest:Error code = (0x%x).\n", (unsigned int)r_errno);
        panic;
    }

    /* wait for response */
    while(true)
    {
        r_errno = R_ICUMIF_IsServiceCompleted(p_ISD);
        if(r_errno != R_ICUMIF_RTN_SERV_RUNNING)
        {
            break;
        }
    }

    if(SERV_OK != p_ISD->service_result)
    {
        ERROR("R_ICUMIF_IsServiceCompleted:Error code = (0x%x).\n", p_ISD->service_result);
        panic;
    }

    r_errno = R_ICUMIF_ServiceResponse();
    if(R_ICUMIF_ER_OK != r_errno)
    {
        ERROR("R_ICUMIF_ServiceResponse:Error code = (0x%x).\n", (unsigned int)r_errno);
        panic;
    }

}
/* End of function secureboot_service(r_icumif_isd_t *p_ISD) */

void final_hash_cmp(void)
{
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
    uint32_t i;
    uint32_t j;
    uint8_t *hash1;
    uint8_t *hash2;
    uintptr_t hash_addr[HASH_CMP_NUM] = {SECURE_FW_HASH_SAVE_ADDR, CR52_IPL_HASH_SAVE_ADDR};

    for(i = 0U; i < HASH_CMP_NUM; i++)
    {
        /* Hash is placed SystemRAM by ICUMX IPL. */
        hash1 = (uint8_t *)(hash_addr[i]);
        hash2 = (uint8_t *)(hash_addr[i] + HASH_SIZE);

        for(j = 0U; j < HASH_SIZE; j++)
        {
            /* Compare Hash */
            if(*hash1 != *hash2)
            {
                /* Hash unmatch. */
                ERROR("Final Hash compare error!!\n");
                panic;
            }
            hash1++;
            hash2++;
        }
    }
#endif /* (RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M) */
}
/* End of function final_hash_cmp(void) */

