/*******************************************************************************
 * 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 2021-2025 Renesas Electronics Corporation All rights reserved.
 *******************************************************************************/

/*******************************************************************************
 * DESCRIPTION   : boot ROM API
 ******************************************************************************/
/******************************************************************************
 * @file          rom_api.c
 * - Version      : 0.13
 * @brief         1.Call ROM_SecureBootAPI.
 *                2.Call ROM_GetLcsAPI.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 28.07.2021 0.01     First Release
 *         : (30.11.2021 0.02)   Modify argument of ROM_GetLcs.
 *         : 23.05.2022 0.03     Supported Secure boot for ROM API.
 *         : 05.08.2022 0.04     Add sw_version_check function and macros.
 *                               Add sw_version_check function call to
 *                               rom_secureboot function.
 *         : 30.09.2022 0.05     Add auth_min_ver_tbl function.
 *         : 09.12.2022 0.06     Remove argument 'is_verify' used in
 *                               auth_min_ver_tbl function.
 *         : 14.02.2023 0.07     Add Hash save process to rom_secureboot.
 *         : 14.04.2023 0.08     Add certificate authentication functions.
 *         : 21.08.2023 0.09     Add support for V4M.
 *         : 11.01.2024 0.10     Add process that change writing privilege
 *                               to System RAM by ICUMX.
 *         : 08.02.2024 0.11     Update icu_remove_write_access calling
 *                               condition to always calling.
 *         : 05.12.2024 0.12     Remove icu_remove_write_access function.
 *         : 26.05.2025 0.13     Add verification support for the OP-TEE
 *                               content cert.
 *****************************************************************************/

#include <stdint.h>
#include <rom_api.h>
#include <log.h>
#include <image_load.h>
#include <mem_io.h>
#include <remap.h>
#include <ram_def.h>
#include <access_protection.h>

/* For software version check */
#define TBL_VERSION_CHECK_DISABLE   (0U)
#define TFMV_MIN_VER_TBL_TOP        (0xFDE35000U)   /* remapped address */
#define NTFMV_MIN_VER_TBL_TOP       (0xFDE35800U)   /* remapped address */
#define NTFMV_LD_ID_OFST            (7U)
#define SW_MIN_VER_TBL_UNIT         (0x10U)
#define TBL_VER_OFST                (4U)
#define TBL_IMG_OFST                (8U)

/* Hash size definition */
#define SECURE_BOOT_COMPARE_HASH_SIZE_BYTE  (64U)   /* SHA-256 * 2 */
/* Definitions for get_hash_save_addr() */
#if (SW_VERSION_CHECK == OPT_VERSION_CHECK_ENABLE)
/* cnt=0: TFMV Software minimum version table  */
/* cnt=1: NTFMV Software minimum version table */
/* cnt=2: CR52 2nd IPL */
#define CR52_IPL_HASH_SAVE_CNT      (0x2U)
/* cnt=3: Secure FW */
#define SECURE_FW_HASH_SAVE_CNT     (0x3U)
#else
#define CR52_IPL_HASH_SAVE_CNT      (0x0U)
#define SECURE_FW_HASH_SAVE_CNT     (0x1U)
#endif
#define CR52_IPL_HASH_SAVE_ADDR     (0xE635FF40U)   /* Physical address */
#define SECURE_FW_HASH_SAVE_ADDR    (0xE635FFC0U)   /* Physical address */
/* For TFMV/NTFMV Software minimum version table */
#define OTHERS_HASH_SAVE_ADDR       (0xE635FC00U)   /* Physical address */

static uint32_t call_ROM_SecureBootVerify(uint32_t *pKeyCert, uint32_t *pContentCert);
static uint32_t call_ROM_SecureBootCompare(uint32_t *pContentCert, uint32_t *hash, uint32_t hash_size);
static uint32_t call_ROM_SecureBootDecrypt(uint32_t *pContentCert);
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
static uint32_t get_hash_save_addr(void);
#endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */

extern uint32_t is_verify;

void rom_secureboot(LOAD_INFO* li)
{
    uint32_t *keycert = (uint32_t*)li->key_cert_addr;
    uint32_t *contentcert = (uint32_t*)li->cnt_cert_addr;
#if (RCAR_LSI == RCAR_S4)
    uint32_t hash[16];      /* hash space is 64byte */
#elif ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
    uint32_t *hash;     /* SystemRAM logical address */
#endif /* (RCAR_LSI == RCAR_S4) */
    uint32_t ret;

    /* If boot mode is Secure BOOT, the ROM API is used to authenticate the image. */
    if (NORMAL_BOOT != is_verify)
    {
        /* Content cert certification */
        ret = call_ROM_SecureBootVerify(keycert, contentcert);
        if (ROMAPI_OK != ret)
        {
            ERROR("%s Certificate Verification Failed!!!(0x%x)\n", li->name, ret);
            panic;
        }

        /* Decryption image */
        ret = call_ROM_SecureBootDecrypt(contentcert);
        if ((ROMAPI_OK != ret) && (ROM_ERR_IMG_VERIFIER_NO_ENCRYPT_IMG != ret))
        {
            ERROR("%s Decryption Failed!!!(0x%x)\n", li->name, ret);
            panic;
        }
    } /* if (NORMAL_BOOT != is_verify) */

    /*
     * System RAM is divided two regions that Cx 2nd IPL and others by RAM protection.
     * After loading and decrypting Cx 2nd IPL, writing privilege to Cx 2nd IPL region
     * from RGID0(ICUMX) to be disabled and then comparing Hash.
     * This implementation is according to operation in SAN (Application Domain Safety Application Note)
     * chapter 6.23.5.
     */
/* Remove the following comment out if user want to enable protection of System Ram. */
/*    if(CA_PROGRAM_ID == (li->image_id))                                            */
/*    {                                                                              */
/*        icu_remove_write_access();                                                 */
/*    }                                                                              */

    if (NORMAL_BOOT != is_verify)
    {
        /* Hash save SystemRAM logical address calculation (V4H only) */
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
        hash = (uint32_t *)get_hash_save_addr();
#endif
        /* Image certification */
        ret = call_ROM_SecureBootCompare(contentcert, hash, SECURE_BOOT_COMPARE_HASH_SIZE_BYTE);
        if (ROMAPI_OK != ret)
        {
            ERROR("%s Image Verification Failed!!!(0x%x)\n", li->name, ret);
            panic;
        }

        /* Software version check */
        sw_version_check(li);
    } /* if (NORMAL_BOOT != is_verify) */
}
/* End of function rom_secureboot(LOAD_INFO* li) */

static uint32_t call_ROM_SecureBootVerify(uint32_t *pKeyCert, uint32_t *pContentCert)
{
    /* Secure Boot API address */
    static const uintptr_t s_rom_secureboot_verify_addr = ROM_SECUREBOOT_VERIFY;
    ROM_SECUREBOOT_VERIFY_API func;
    uint32_t ret;

    func = (ROM_SECUREBOOT_VERIFY_API)s_rom_secureboot_verify_addr;

    ret = func(pKeyCert, pContentCert);
    return ret;
}
/* End of function call_ROM_SecureBootVerify(uint32_t *pKeyCert, uint32_t *pContentCert) */

static uint32_t call_ROM_SecureBootCompare(uint32_t *pContentCert, uint32_t *hash, uint32_t hash_size)
{
    /* Secure Boot API address */
    static const uintptr_t s_rom_secureboot_compare_addr = ROM_SECUREBOOT_COMPARE;
    ROM_SECUREBOOT_COMPARE_API func;
    uint32_t ret;

    func = (ROM_SECUREBOOT_COMPARE_API)s_rom_secureboot_compare_addr;

    ret = func(pContentCert, hash, hash_size);
    return ret;
}
/* End of function call_ROM_SecureBootCompare(uint32_t *pContentCert, uint32_t *hash, uint32_t hash_size) */

static uint32_t call_ROM_SecureBootDecrypt(uint32_t *pContentCert)
{
    /* Secure Boot API address */
    static const uintptr_t s_rom_secureboot_decrypt_addr = ROM_SECUREBOOT_DECRYPT;
    ROM_SECUREBOOT_DECRYPT_API func;
    uint32_t ret;

    func = (ROM_SECUREBOOT_DECRYPT_API)s_rom_secureboot_decrypt_addr;

    ret = func(pContentCert);
    return ret;
}
/* End of function call_ROM_SecureBootDecrypt(uint32_t *pContentCert) */

uint32_t call_ROM_GetLcs(uint32_t *pLcs, uint32_t lcs_size)
{
    /* Get LCS stete API address */
    static const uintptr_t s_rom_getlcs_addr = ROM_GETLCS;
    ROM_GETLCS_API func;
    uint32_t ret;

    func = (ROM_GETLCS_API)s_rom_getlcs_addr;

    ret = func(pLcs, lcs_size);
    return ret;
}
/* End of function call_ROM_GetLcs(uint32_t *pLcs, uint32_t lcs_size) */

void sw_version_check(const LOAD_INFO* li)
{
#if (SW_VERSION_CHECK == OPT_VERSION_CHECK_ENABLE)
    uint32_t ver_tbl_base;
    uint32_t ver_tbl_addr;
    uint32_t ver_tbl_version;
    uint32_t ver_tbl_ofst;
    uint32_t img_version;
    uint32_t id_adj = 0U;
    uint32_t val;
    uint32_t rmp_addr;
    uint32_t load_id;

    load_id = get_load_info_id(li);

    if (load_id < TFMV_MIN_VER_TBL_ID)
    {
        /* If image is other than Software minimum version table */
        if(li->key_cert_addr == TFMV_KEY_CERT_ADDR)
        {
            /* Refer to TFMV Software minimum version table */
            ver_tbl_base = TFMV_MIN_VER_TBL_TOP;        /* 0xFDE35000 */
        }
        else
        {
            /* Refer to NTFMV Software minimum version table */
            ver_tbl_base = NTFMV_MIN_VER_TBL_TOP;       /* 0xFDE35800 */
            id_adj       = NTFMV_LD_ID_OFST;
        }

        /* Calculate Software minimum version address for Load ID */
        ver_tbl_addr = ver_tbl_base + (SW_MIN_VER_TBL_UNIT * (load_id - id_adj));

        val = mem_read32(ver_tbl_addr);
        if(val != TBL_VERSION_CHECK_DISABLE)
        {
            /* If a flag in Software minimum version is enable */
            ver_tbl_version = mem_read32(ver_tbl_addr + TBL_VER_OFST);
            ver_tbl_ofst    = mem_read32(ver_tbl_addr + TBL_IMG_OFST);

            /* Read image version in Load ID's image */
            remap_register(li->boot_addr + ver_tbl_ofst, &rmp_addr);
            img_version = mem_read32(rmp_addr);
            remap_unregister(rmp_addr);

            if(img_version < ver_tbl_version)
            {
                ERROR("%s Software version check result is failed.\n", li->name);
                panic;
            }
        }
    }
#endif /* (SW_VERSION_CHECK == OPT_VERSION_CHECK_ENABLE) */
}
/* End of function sw_version_check(const LOAD_INFO* li) */

void auth_min_ver_tbl(LOAD_INFO* li)
{
#if (SW_VERSION_CHECK == OPT_VERSION_CHECK_ENABLE)
    rom_secureboot(&li[TFMV_MIN_VER_TBL_ID]);
    rom_secureboot(&li[NTFMV_MIN_VER_TBL_ID]);
#endif /* (SW_VERSION_CHECK == OPT_VERSION_CHECK_ENABLE) */
}
/* End of function auth_min_ver_tbl(LOAD_INFO* li) */

#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
static uint32_t get_hash_save_addr(void)
{
    uint32_t hash_addr;
    static uint32_t cnt = 0U;

    if(cnt == CR52_IPL_HASH_SAVE_CNT)
    {
        /* When loading image is Cx 2nd IPL. */
        hash_addr = remap_get_remap_addr(CR52_IPL_HASH_SAVE_ADDR);
    }
    else if(cnt == SECURE_FW_HASH_SAVE_CNT)
    {
        /* When loading image is Secure FW. */
        hash_addr = remap_get_remap_addr(SECURE_FW_HASH_SAVE_ADDR);
    }
    else
    {
        /* When loading image is TFMV/NTFMV Software minimum version table. */
        hash_addr = remap_get_remap_addr(OTHERS_HASH_SAVE_ADDR);
    }
    /* Count how many times this function called. */
    cnt++;

    if(cnt > SECURE_FW_HASH_SAVE_CNT + 1U)
    {
        NOTICE("get_hash_save_addr: Unexpected cnt value.\n");
    }

    return hash_addr;
}
/* End of function get_hash_save_addr(void) */

void preload_verify_cntcert(const LOAD_INFO* li)
{
    if (NORMAL_BOOT != is_verify)
    {
        /* Set error code value as initial value */
        int32_t ret = -1;

        /* verify the content cert of RTOS */
        ret = call_ROM_SecureBootVerify((uint32_t *)li[RTOS_ID].key_cert_addr, (uint32_t *)li[RTOS_ID].cnt_cert_addr);
        if (ROMAPI_OK != ret)
        {
            ERROR("%s Certificate Verification Failed!!!(0x%x)\n", li[RTOS_ID].name, ret);
            panic;
        }

        /* verify the content cert of Secure FW */
        ret = call_ROM_SecureBootVerify((uint32_t *)li[SECURE_FW_ID].key_cert_addr, (uint32_t *)li[SECURE_FW_ID].cnt_cert_addr);
        if (ROMAPI_OK != ret)
        {
            ERROR("%s Certificate Verification Failed!!!(0x%x)\n", li[SECURE_FW_ID].name, ret);
            panic;
        }

        /* verify the content cert of CxIPL */
        ret = call_ROM_SecureBootVerify((uint32_t *)li[CA_PROGRAM_ID].key_cert_addr, (uint32_t *)li[CA_PROGRAM_ID].cnt_cert_addr);
        if (ROMAPI_OK != ret)
        {
            ERROR("%s Certificate Verification Failed!!!(0x%x)\n", li[CA_PROGRAM_ID].name, ret);
            panic;
        }

        /* verify the content cert of Secure Monitor */
        ret = call_ROM_SecureBootVerify((uint32_t *)li[CA_OPTIONAL_ID].key_cert_addr, (uint32_t *)li[CA_OPTIONAL_ID].cnt_cert_addr);
        if (ROMAPI_OK != ret)
        {
            ERROR("%s Certificate Verification Failed!!!(0x%x)\n", li[CA_OPTIONAL_ID].name, ret);
            panic;
        }

        /* verity the content cert of U-boot */
        ret = call_ROM_SecureBootVerify((uint32_t *)li[CA_OPTIONAL_ID + 1U].key_cert_addr, (uint32_t *)li[CA_OPTIONAL_ID + 1U].cnt_cert_addr);
        if (ROMAPI_OK != ret)
        {
            ERROR("%s Certificate Verification Failed!!!(0x%x)\n", li[CA_OPTIONAL_ID + 1U].name, ret);
            panic;
        }

#if (OPTEE_LOAD_ENABLE == OPTEE_ENABLE)
        /* verity the content cert of OP-TEE */
        ret = call_ROM_SecureBootVerify((uint32_t *)li[CA_OPTIONAL_ID + 2U].key_cert_addr, (uint32_t *)li[CA_OPTIONAL_ID + 2U].cnt_cert_addr);
        if (ROMAPI_OK != ret)
        {
            ERROR("%s Certificate Verification Failed!!!(0x%x)\n", li[CA_OPTIONAL_ID + 2U].name, ret);
            panic;
        }
#endif /* OPTEE_LOAD_ENABLE == OPTEE_ENABLE */
    }
}

#endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */

