/*******************************************************************************
 * 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   : Image load function
 ******************************************************************************/
/******************************************************************************
 * @file          image_load.c
 * - Version      : 0.14
 * @brief         Loading image driver.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 28.07.2021 0.01     First Release
 *         : 03.09.2021 0.02     Modify macro definition name.
 *         : 30.09.2021 0.03     Support of eMMC boot.
 *         : 15.10.2021 0.04     Fix a problem with overwriting the load area
 *                               information in RTOS.
 *                               modify Error log of check_load_area.
 *                               Modify the process of outputting load
 *                               information of Optionbyte to function.
 *         : 03.12.2021 0.05     Modify function "check_load_area" to check the
 *                               boundary value of RT-VRAM(for virtual buffer).
 *                               Fixed judgment of the top/end of the
 *                               forwarding destination.
 *         : 06.01.2022 0.06     Support for two-stage boot of G4MH.
 *         : 23.05.2022 0.07     Support for updating the memory map.
 *         : 21.06.2022 0.08     Modify some function's arguments and add
 *                               macros.
 *         : 05.08.2022 0.09     Add TFMV/NTFMV minimum version table
 *                               information to load_init function.
 *         : 22.09.2022 0.10     Fix address range check for V4H.
 *         : 21.08.2023 0.11     Add support for V4M.
 *         : 15.01.2024 0.12     Add image_id initialization to load_init
 *                               function.
 *         : 19.12.2024 0.13     Add RTOS#1, RTOS#2 image.
 *         : 26.05.2025 0.14     Change key cert address of [CA_OPTIONAL_ID+2].
 *****************************************************************************/

/* indelude */
#include <stdint.h>
#include <image_load.h>
#include <remap.h>
#include <mem_io.h>
#include <log.h>
#include <rom_api.h>
#include <ram_def.h>

#if (RCAR_SA9_TYPE == FLASH_BOOT)
#include <image_load_flash.h>
#include <dma.h>
#elif (RCAR_SA9_TYPE == EMMC_BOOT)
#include <image_load_emmc.h>
#include <emmc_multiboot.h>
#include <emmc_def.h>
#endif

#define KEY_SIZE_FLG_MSK            (0x00000003U)
#define KEY_SIZE_4096               (0x00000002U)
#define KEY_SIZE_3072               (0x00000001U)
#define KEY_SIZE_2048               (0x00000000U)
#define WORD_TO_BYTE                (4U)
#define ERROR_PARAM                 (0U)
#define NOT_OVERLAP_FLAG            (0U)
#define OVERLAP_FLAG                (1U)
#define RAM_RANGE_OK                (0U)
#define RAM_RANGE_NG                (1U)
#if (BOOT_MCU != 0U)
#define RAM_MAX                     (5U)
#else
#define RAM_MAX                     (4U)
#endif /* (BOOT_MCU != 0U) */

/* Load Parameter of Secure data */
#define SRC_ADDR_OF_SECURE_DATA_FOR_ICUMXB  (SRC_TOP + 0x00340000U)
#define DST_ADDR_OF_SECURE_DATA_FOR_ICUMXB  (0xEB2E0000U)
#if (BOOT_MCU != 0U)
#define SRC_ADDR_OF_SECURE_DATA_FOR_ICUMH   (SRC_TOP + 0x00440000U)
/* The destination address of Flash to RAM in the ICUMH Secure data is the top address of RT-VRAM. */
#endif

static void get_info_from_cert(uint32_t cert_addr, uint32_t *size,
    uint32_t *dest_addr);
static void check_src_addr_range(uint32_t src, uint32_t len, uint32_t src_end);
static void check_dst_addr_range(uint32_t dst, uint32_t len, uint32_t dst_end);
static void check_overlap_images(uint32_t dst, uint32_t len, uint32_t dst_end);

uint32_t load_content_cert(void)
{
    uint32_t load_num;
#if (RCAR_SA9_TYPE == FLASH_BOOT)
    load_num = load_content_cert_for_flash();
#elif (RCAR_SA9_TYPE == EMMC_BOOT)
    load_num = load_content_cert_for_emmc();
#else
    /* NoProcess */
#endif
    return load_num;
}
/* End of function load_content_cert(void) */

void load_image(LOAD_INFO* li)
{
    /* log output of load image for information */
#if (RCAR_SA9_TYPE == FLASH_BOOT)
    load_image_info_print_for_flash(li);
#elif (RCAR_SA9_TYPE == EMMC_BOOT)
    load_image_info_print_for_emmc(li);
#endif
    /* Check transfer range of image. */
    check_load_area(li);

    /* Image load start. */
    load_start(li);
}
/* End of function load_image(LOAD_INFO* li) */

void load_init(LOAD_INFO* li)
{
    uint32_t loop;
    uint32_t buf;

    const char *image_name[MAX_PLACED]  = {
        [SECURE_FW_ID]             = "Secure FW",
        [RTOS_ID]                  = "RTOS",
        [CA_PROGRAM_ID]            = "Cx IPL",
        [ICUMH_PROGRAM_ID]         = "ICUMH",
        [G4MH_PROGRAM_ID]          = "G4MH(1st)",
        [G4MH_PROGRAM_ID + 1]      = "G4MH(2nd)",
        [CA_OPTIONAL_ID]           = "CA Program #1",
        [CA_OPTIONAL_ID + 1]       = "CA Program #2",
        [CA_OPTIONAL_ID + 2]       = "CA Program #3",
        [CA_OPTIONAL_ID + 3]       = "CA Program #4",
        [CA_OPTIONAL_ID + 4]       = "CA Program #5",
        [CA_OPTIONAL_ID + 5]       = "CA Program #6",
        [CA_OPTIONAL_ID + 6]       = "CA Program #7",
        [CA_OPTIONAL_ID + 7]       = "CA Program #8",
        [TFMV_MIN_VER_TBL_ID]      = "TFMV minimum version table",
        [NTFMV_MIN_VER_TBL_ID]     = "NTFMV minimum version table",
#if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3)
        [RTOS1_ID]                 = "RTOS#1",
        [RTOS2_ID]                 = "RTOS#2"
#endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */
    };

    const uint32_t key_cert[MAX_PLACED]  = {
        [SECURE_FW_ID]             = TFMV_KEY_CERT_ADDR,
        [RTOS_ID]                  = TFMV_KEY_CERT_ADDR,
        [CA_PROGRAM_ID]            = TFMV_KEY_CERT_ADDR,
        [ICUMH_PROGRAM_ID]         = TFMV_KEY_CERT_ADDR,
        [G4MH_PROGRAM_ID]          = TFMV_KEY_CERT_ADDR,
        [G4MH_PROGRAM_ID + 1]      = TFMV_KEY_CERT_ADDR,
        [CA_OPTIONAL_ID]           = TFMV_KEY_CERT_ADDR,
#if (RCAR_LSI == RCAR_S4)
        [CA_OPTIONAL_ID + 1]       = TFMV_KEY_CERT_ADDR,
#elif ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
        [CA_OPTIONAL_ID + 1]       = NTFMV_KEY_CERT_ADDR,
#endif
#if (OPTEE_LOAD_ENABLE == OPTEE_DISABLE)
        [CA_OPTIONAL_ID + 2]       = NTFMV_KEY_CERT_ADDR,
#else
        [CA_OPTIONAL_ID + 2]       = TFMV_KEY_CERT_ADDR,
#endif
        [CA_OPTIONAL_ID + 3]       = NTFMV_KEY_CERT_ADDR,
        [CA_OPTIONAL_ID + 4]       = NTFMV_KEY_CERT_ADDR,
        [CA_OPTIONAL_ID + 5]       = NTFMV_KEY_CERT_ADDR,
        [CA_OPTIONAL_ID + 6]       = NTFMV_KEY_CERT_ADDR,
        [CA_OPTIONAL_ID + 7]       = NTFMV_KEY_CERT_ADDR,
        [TFMV_MIN_VER_TBL_ID]      = TFMV_KEY_CERT_ADDR,
        [NTFMV_MIN_VER_TBL_ID]     = NTFMV_KEY_CERT_ADDR,
#if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3)
        [RTOS1_ID]                 = TFMV_KEY_CERT_ADDR,
        [RTOS2_ID]                 = TFMV_KEY_CERT_ADDR
#endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */
    };

    /* Set Load info parameter */
    for (loop = 0; loop < MAX_PLACED; loop++)
    {
        li[loop].name          = image_name[loop];
        li[loop].key_cert_addr = key_cert[loop];
        li[loop].cnt_cert_addr = get_logic_cont_cert_addr(loop);
        get_info_from_cert(li[loop].cnt_cert_addr, &li[loop].image_size, &li[loop].boot_addr);
        buf                    = get_src_addr_offset_in_cert(loop);
        li[loop].src_addr      = (SRC_TOP + mem_read32(buf));
        li[loop].image_id      = loop;
#if (RCAR_SA9_TYPE == EMMC_BOOT)
        buf                    = get_part_num_in_cert(loop);
        li[loop].part_num      = mem_read32(buf);
#endif
    }
}/* End of function load_init(LOAD_INFO* li) */


void check_load_area(const LOAD_INFO* li)
{
    uint32_t src;
    uint32_t dst;
    uint32_t len;
    uint32_t src_end;
    uint32_t dst_end;

    src = li->src_addr;
    dst = li->boot_addr;
    len = li->image_size;

    /* Check whether source is overflow. */
    check_overflow(src, len, &src_end, __func__);

    /* Check whether destination is overflow. */
    check_overflow(dst, len, &dst_end, __func__);

    /* Check source address range. */
    check_src_addr_range(src, len, src_end);

    /* Check destination address range. */
    check_dst_addr_range(dst, len, dst_end);

    /* Check whether overlap destination address and images that have been loaded. */
    check_overlap_images(dst, len, dst_end);
}
/* End of function check_load_area(const LOAD_INFO* li) */

static void get_info_from_cert(uint32_t cert_addr, uint32_t *size,
    uint32_t *dest_addr)
{
    uint32_t    val;
    uint32_t    certInfo1;
    uint32_t   pSize;
    uint32_t   pDestL;

    /* Get key length of content certificate. */
    val = mem_read32(cert_addr + CERT_INFO_FLG_OFFSET);
    certInfo1 = (val >> KEY_SIZE_BIT_SHIFT) & KEY_SIZE_FLG_MSK;

    /* Get the transfer address and transfer size from
       the certificate in accordance with the key length.   */
    if (KEY_SIZE_4096 == certInfo1)  /* key size = 4096 */
    {
        pSize = cert_addr + CERT_INFO_SIZE_OFFSET2;
        *size = mem_read32(pSize) * WORD_TO_BYTE;
        pDestL = cert_addr + CERT_INFO_DST_OFFSET2;
        *dest_addr = mem_read32(pDestL);
    }
    else if (KEY_SIZE_3072 == certInfo1)    /* key size = 3072 */
    {
        pSize = cert_addr + CERT_INFO_SIZE_OFFSET1;
        *size = mem_read32(pSize) * WORD_TO_BYTE;
        pDestL = cert_addr + CERT_INFO_DST_OFFSET1;
        *dest_addr = mem_read32(pDestL);
    }
    else if (KEY_SIZE_2048 == certInfo1)    /* key size = 2048 */
    {
        pSize = cert_addr + CERT_INFO_SIZE_OFFSET;
        *size = mem_read32(pSize) * WORD_TO_BYTE;
        pDestL = cert_addr + CERT_INFO_DST_OFFSET;
        *dest_addr = mem_read32(pDestL);
    }
    else
    {
        *size = ERROR_PARAM;
        *dest_addr = ERROR_PARAM;
    }
}
/* End of function get_info_from_cert(uint32_t cert_addr, uint32_t *size, uint32_t *dest_addr) */

void load_start(const LOAD_INFO* li)
{
#if (RCAR_SA9_TYPE == FLASH_BOOT)
    dma_trans_start(li->boot_addr, li->src_addr, li->image_size);
#elif (RCAR_SA9_TYPE == EMMC_BOOT)
    uint32_t rtn_val;
    uint32_t sector_count;
    uint32_t fraction;

    /* Converted to number of sectors transferred. */
    sector_count = li->image_size >> EMMC_SECTOR_SIZE_SHIFT;
    fraction = li->image_size % EMMC_SECTOR_SIZE;
    /* Add 1 if there is a fraction */
    if(0U != fraction)
    {
        sector_count += 1U;
    }

    rtn_val = emmc_trans_data(li->part_num, (li->src_addr >> EMMC_SECTOR_SIZE_SHIFT),
                    li->boot_addr,  sector_count);

    if(EMMC_DEV_OK != rtn_val)
    {
        ERROR("load_start(emmc_trans_data error).\r\n");
        panic;
    }
#else
    /* NoProcess */
#endif
}/* End of function load_start(LOAD_INFO* li) */

void load_end(void)
{
#if (RCAR_SA9_TYPE == FLASH_BOOT)
    dma_trans_end_check();
#else
    /* NoProcess */
#endif
}/* End of function load_end(void) */

void load_securedata(uint32_t target_id)
{
    LOAD_INFO tmp_li;

    if(target_id == SECURE_FW_ID)   /* When secure data transfer for ICUMXB FW. */
    {
        tmp_li.image_size = SECUREDATA_SIZE;
        tmp_li.src_addr   = SRC_ADDR_OF_SECURE_DATA_FOR_ICUMXB;
        tmp_li.boot_addr  =DST_ADDR_OF_SECURE_DATA_FOR_ICUMXB;
#if (RCAR_SA9_TYPE == EMMC_BOOT)
        tmp_li.part_num  = EMMC_PARTITION_1;
#endif
    }
#if (BOOT_MCU != 0U)
    else if(target_id == ICUMH_PROGRAM_ID)  /* When secure data transfer for ICUMH FW. */
    {
        tmp_li.image_size = SECUREDATA_SIZE;
        tmp_li.src_addr   = SRC_ADDR_OF_SECURE_DATA_FOR_ICUMH;
        tmp_li.boot_addr  = RTVRAM_BASE;
#if (RCAR_SA9_TYPE == EMMC_BOOT)
        tmp_li.part_num  = EMMC_PARTITION_1;
#endif
    }
#endif
    else
    {
        ERROR("Failed input parameter.\n");
        panic;
    }

    load_start(&tmp_li);
}/* End of function load_securedata(uint32_t target_id) */

void check_overflow(uint32_t addr, uint32_t len, uint32_t *end_addr, const char *func_name)
{
    /* Pre confirmation */
    if (addr > (UINT32_MAX - len))
    {
        ERROR("1:overflow is occurred in %s.\n", func_name);
        ERROR("1:address = 0x%x size = 0x%x\n", addr, len);
        panic;
    }
    else
    {
        *end_addr = addr + len - 1U;
    }
    /* Post confirmation */
    if (*end_addr < addr)
    {
        ERROR("2:overflow is occurred in %s.\n", func_name);
        ERROR("2:address = 0x%x size = 0x%x\n", addr, len);
        panic;
    }
}
/* End of function check_overflow(uint32_t addr, uint32_t len, uint32_t *end_addr, char *func_name) */

static void check_src_addr_range(uint32_t src, uint32_t len, uint32_t src_end)
{

    /* Check image size */
    if (len == 0U)
    {
        ERROR("image size error\n");
        panic;
    }

#if (RCAR_SA9_TYPE == FLASH_BOOT)
    if ((src < SRC_TOP) || (SRC_END < src_end))
#elif (RCAR_SA9_TYPE == EMMC_BOOT)
    if (SRC_END < src_end)
#endif
    {
        ERROR("check load area (source address)\n");
        ERROR("source address = 0x%x image size = 0x%x\n", src, len);
        panic;
    }
}
/* End of function check_src_addr_range(uint32_t src, uint32_t len, uint32_t src_end) */

static void check_dst_addr_range(uint32_t dst, uint32_t len, uint32_t dst_end)
{
    uint32_t rge_chk_flg;
    uint32_t loop;

    /* The memory range of destination. */
    const ADDRESS_RANGE add_list[RAM_MAX] = {
        [TARGET_MEM_DRAM] = {DRAM_BASE, DRAM_END},
        [TARGET_MEM_RTSRAM] = {RTSRAM_BASE, RTSRAM_END},
        [TARGET_MEM_RTVRAM] = {RTVRAM_VBUF_TOP, RTVRAM_VBUF_END},
        [TARGET_MEM_SYSRAM] = {SYSRAM_BASE, SYSRAM_END},
#if (BOOT_MCU != 0U)
        [TARGET_MEM_CODESRAM] = {CODESRAM_BASE, CODESRAM_END}
#endif /* (BOOT_MCU != 0U) */
    };

    /* Check image size */
    if (len == 0U)
    {
        ERROR("image size error\n");
        panic;
    }

    rge_chk_flg = RAM_RANGE_NG;

    for(loop = 0; loop < RAM_MAX; loop++)
    {
        if (add_list[loop].topadd <= dst)
        {
            if(dst_end <= add_list[loop].endadd)
            {
                rge_chk_flg = RAM_RANGE_OK;
                break;
            }
        }
    }

    if(rge_chk_flg != RAM_RANGE_OK)
    {
        ERROR("check load area (destination address)\n");
        ERROR("destination address = 0x%x image size = 0x%x\n", dst, len);
        panic;
    }
}
/* End of function check_dst_addr_range(uint32_t dst, uint32_t len, uint32_t dst_end) */

static void check_overlap_images(uint32_t dst, uint32_t len, uint32_t dst_end)
{
    uint32_t overlap;
    uint32_t loop;

    static uint32_t s_num = 1U;

    static ADDRESS_RANGE s_placed_image[MAX_PLACED + 1] = {
        [0]  = {IPL_TOP, IPL_END},
        [1]  = {0U,0U},
        [2]  = {0U,0U},
        [3]  = {0U,0U},
        [4]  = {0U,0U},
        [5]  = {0U,0U},
        [6]  = {0U,0U},
        [7]  = {0U,0U},
        [8]  = {0U,0U},
        [9]  = {0U,0U},
        [10] = {0U,0U},
        [11] = {0U,0U},
        [12] = {0U,0U},
        [13] = {0U,0U},
        [14] = {0U,0U},
        [15] = {0U,0U},
        [16] = {0U,0U}
    };

    overlap = NOT_OVERLAP_FLAG;
    loop    = 0U;
    do
    {
        /* check overlap */
        if ((dst >= s_placed_image[loop].topadd) && (dst <= s_placed_image[loop].endadd))
        {
            overlap = OVERLAP_FLAG;
        }
        else if ((dst_end >= s_placed_image[loop].topadd) && (dst_end <= s_placed_image[loop].endadd))
        {
            overlap = OVERLAP_FLAG;
        }
        else if ((dst < s_placed_image[loop].topadd) && (s_placed_image[loop].endadd < dst_end))
        {
            overlap = OVERLAP_FLAG;
        }
        else
        {
            loop++;
        }
    } while ((loop < s_num) && (overlap == NOT_OVERLAP_FLAG));

    /* Check the overlap flag.                                                *
     * Parameters are error if overwrite occurred.                            *
     * Otherwise, add parameters of the image to be loaded into Placed_image. */
    if (overlap == NOT_OVERLAP_FLAG)
    {
        s_placed_image[s_num].topadd = dst;
        s_placed_image[s_num].endadd = dst_end;
        INFO("[0x%x] topadd = 0x%x endadd = 0x%x\n", s_num,
            s_placed_image[s_num].topadd, s_placed_image[s_num].endadd);
        s_num++;
    }
    else
    {
        ERROR("check load area (overlap)\n");
        ERROR("destination address = 0x%x image size = 0x%x\n", dst, len);
        ERROR("overlapped image is [%x]\n", loop);
        ERROR("top address = 0x%x end address = 0x%x\n",
            s_placed_image[loop].topadd, s_placed_image[loop].endadd);
        panic;
    }
}
/* End of function check_overlap_images(uint32_t dst, uint32_t len, uint32_t dst_end) */

