/******************************************************************************* * 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 : Loader main function ******************************************************************************/ /****************************************************************************** * @file loader_main.c * - Version : 0.17 * @brief 1. IP initialization. * 2. Transfer image. * 3. Release of used resources. * . *****************************************************************************/ /****************************************************************************** * History : DD.MM.YYYY Version Description * : 30.11.2021 0.01 First Release * : 14.02.2022 0.02 Changed log output * Added device version log output * Removed Include in micro_wait.h * Removed the parameter setting process to BL31 * Removed LCS judgement * Memory map change * : 17.02.2022 0.03 Support AArch32 * : 22.03.2022 0.04 Support for GSCE[5.4a, 5.4b],[10.3b] * Support for coverity * cid:3430806, 3307617, 3430797 * Changed comment * : 10.05.2022 0.05 Integrated processing * Changed to processing for each device * Change log output * Add argument of load_init() * : 16.06.2022 0.06 Change log output * Support secure boot for S4 * : 31.10.2022 0.07 License notation change. * : 07.11.2022 0.08 Added the parameter setting process to BL31 * Added DDR initialization/QOS initialization * : 07.12.2022 0.09 Warning support when log output is disabled * : 15.12.2022 0.10 Support RegionID check * : 04.04.2023 0.11 Removed stdio.h. * : 21.08.2023 0.12 Add support for V4M. * : 23.01.2024 0.13 Add calling of ram_protection_check function. * Move calling of final_hash_cmp function. * : 10.09.2024 0.14 Updated Region ID and RAM protection setting * for QNX. * : 11.10.2024 0.15 Updated Region ID and RAM protection setting * for QNX for V4M. * : 19.12.2024 0.16 Add loading RTOS#1 and RTOS#2 process. * Add calling ecm_error_enable() function. * : 26.05.2025 0.17 Add argument of OP-TEE boot address to * smoni_set_param function. *****************************************************************************/ #include #include #include #include #include #include #include #include #include #if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) #include "cpu_on.h" #include "qos.h" #include "rtvram.h" #include "loader_main_common.h" #include "../ip/ddr/boot_init_dram.h" #include "access_protection.h" #if (ECC_ENABLE == 1) #if (RCAR_LSI == RCAR_V4H) #include "../ip/ddr/v4h/lpddr5/ecc_enable_v4h.h" #elif (RCAR_LSI == RCAR_V4M) #include "../ip/ddr/v4m/lpddr5/ecc_enable_v4m.h" #endif /* RCAR_LSI == RCAR_V4H */ #endif /* ECC_ENABLE == 1 */ #endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */ #if (BOOT_MODE == SECURE) #include "secure_boot.h" #endif /* BOOT_MODE == SECURE */ /* Time analysis */ #if (1 == (MEASURE_TIME)) #include #include #else #define scmt_wait_ticks(x) #define store_time_checkpoint(x,y) #define print_time_checkpoints(x) #endif #if (ACC_PROT_ENABLE == PROTECTION_ENABLE) #include "axmm_register.h" #include "ram_protection.h" #endif #if (ECM_ERROR_ENABLE == 1) #if (RCAR_LSI == RCAR_V4H) #include "../ip/ddr/v4h/lpddr5/ecm_enable_v4h.h" #elif (RCAR_LSI == RCAR_V4M) #include "../ip/ddr/v4m/lpddr5/ecm_enable_v4m.h" #endif /* RCAR_LSI == RCAR_V4H */ #endif /* ECM_ERROR_ENABLE == 1 */ #include #include #include #if (ACC_PROT_ENABLE == PROTECTION_ENABLE) #define AXMM_DPTSECCR_NUM (SDRAM_PROTECT_AREA) /* set 0 to 15 */ #if (OPTEE_LOAD_ENABLE == OPTEE_ENABLE) #define AXMM_DPTSECCR_NUM2 (SDRAM_PROTECT_AREA2) /* set 0 to 15 */ #endif /* OPTEE_LOAD_ENABLE == OPTEE_ENABLE */ #define AXMM_DPTSECCR_SECGRP_MASK (0x00000F00U) #define AXMM_DPTSECCR_SECGRP_SEC (0x00000400U) #define AXMM_DPTSECCR_SECGWP_MASK (0x0000000FU) #define AXMM_DPTSECCR_SECGWP_SEC (0x00000004U) #if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) #if (OPTEE_LOAD_ENABLE == OPTEE_DISABLE) #define DPTRGNCR_PROTECT_AREA (3U) #define DPTRGNCR_LINUX_AREA (6U) #else #define DPTRGNCR_PROTECT_AREA (4U) #define DPTRGNCR_LINUX_AREA (9U) #endif /* OPTEE_LOAD_ENABLE == OPTEE_DISABLE */ #define SECCTRWD_AREA0 (0U) #define SECCTRWD_AREA2 (2U) #define AXMM_DPTRGNCR_RGN0RP_MASK (0x00010000U) #define AXMM_DPTRGNCR_RGN0RP (0x00010000U) #define AXMM_DPTRGNCR_RGN0WP_MASK (0x00000001U) #define AXMM_DPTRGNCR_RGN0WP (0x00000001U) #define SECCTRWD_SAFG15WP_MASK (0x00000005U) #define SECCTRWD_SAFG15WP (0x00000005U) static void remove_rgid0_previlege(void); #endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */ static void sdram_protection(uint32_t num); #endif /* ACC_PROT_ENABLE == PROTECTION_ENABLE */ uint32_t loader_main(void) { uint32_t ca_load_num; /* number of load for CA program */ uint32_t loop; uint32_t reg; /* store register value */ #ifdef MOBIS_PRK3 int slot = 0; #endif #if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) int32_t result; /* store result of ddr_init() */ #endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */ __attribute__((unused))const char *str; #if (RCAR_LSI == RCAR_S4) const char *product_s4 = "S4"; #elif (RCAR_LSI == RCAR_V4H) const char *product_v4h = "V4H"; #elif (RCAR_LSI == RCAR_V4M) const char *product_v4m = "V4M"; #endif /* RCAR_LSI == RCAR_S4 */ const char *unknown = "unknown"; #if (BOOT_MODE == SECURE) uint32_t bootmode; /* store boot mode */ #endif /* BOOT_MODE == SECURE */ LOAD_INFO li[MAX_PLACED]; #if (1 == (MEASURE_TIME)) scmt_module_start(); store_time_checkpoint("loader_main", 0); #endif /***************************************************************************** * Initialize Hardware *****************************************************************************/ /* IP initialize */ ip_init(); /***************************************************************************** * Output boot message *****************************************************************************/ #if (RCAR_LSI == RCAR_S4) NOTICE("CA55 Loader Program Rev.%s\n", IPL_VERSION); #elif ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) NOTICE("CR52 Loader Program Rev.%s\n", IPL_VERSION); #endif /* RCAR_LSI == RCAR_S4 */ NOTICE("%s\n", build_message); /* Get PRR */ reg = mem_read32(PRR); switch (reg & PRR_PRODUCT_MASK) { #if (RCAR_LSI == RCAR_S4) case PRR_PRODUCT_S4: { str = product_s4; break; } #elif (RCAR_LSI == RCAR_V4H) case PRR_PRODUCT_V4H: { str = product_v4h; break; } #elif (RCAR_LSI == RCAR_V4M) case PRR_PRODUCT_V4M: { str = product_v4m; break; } #endif /* RCAR_LSI == RCAR_S4 */ default: { str = unknown; break; } } NOTICE("PRR is R-Car %s Ver.%d.%d\n", str, ((int)(reg & PRR_MAJOR_MASK) >> PRR_MAJOR_SHIFT) + PRR_MAJOR_OFFSET, (int)(reg & PRR_MINOR_MASK)); #if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) #if (ACC_PROT_ENABLE == PROTECTION_ENABLE) /* Notice the ecc enable */ NOTICE("Access Protection Enable\n"); #endif /* ACC_PROT_ENABLE == PROTECTION_ENABLE */ #endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */ store_time_checkpoint("init_done", 0); /***************************************************************************** * DDR Initialization *****************************************************************************/ #if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) /* DDR initialize */ result = R_DRAM_Init(); if (INITDRAM_OK != result) { ERROR("Failed to DRAM initialize (%d).\n", (int)result); panic; } #if (ECM_ERROR_ENABLE == 1) ecm_error_enable(); #endif /* ECM_ERROR_ENABLE == 1 */ #if (ECC_ENABLE == 1) /* ECC Protection */ ecc_sdram_enable(); #endif /* ECC_ENABLE == 1 */ /* QoS configuration */ qos_init(); /* RT-VRAM Extend mode */ rtvram_extendmode(); /* memory copy */ memcpy((void *)DISK_BUFFER_ADDR, (void *)DISK_BUFFER__IPL, 4096); memset((void *)DISK_BUFFER__IPL, 0xFF, 4096); memcpy((void *)AB_INFO_FLAG_ADDR, (void *)AB_INFO_FLAG__IPL, 4); memset((void *)AB_INFO_FLAG__IPL, 0xFF, 4); #endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */ store_time_checkpoint("DDR_and_Bus_init_done", 0); /***************************************************************************** * Load Certficate *****************************************************************************/ /* Load content certificate */ ca_load_num = mem_read32(CONTENT_CERT_DEST_ADDR); /* Get load information */ load_init(li, ca_load_num); #if (BOOT_MODE == SECURE) /***************************************************************************** * Check SecureBoot *****************************************************************************/ secureboot_init(); /* LCS judgement for secure boot */ bootmode = judge_bootmode(); if (NORMAL_BOOT != bootmode) { /* Content cert certification */ #if (BL2_LOAD_ENABLE == BL2_DISABLE) secureboot_verify(li, CA_OPTIONAL_ID, CA_OPTIONAL_ID + ca_load_num); #else secureboot_verify(li, CA_BL2_ID, CA_BL2_ID + 1); #endif store_time_checkpoint("verify_cert_done", 0); } #endif /* BOOT_MODE == SECURE */ #if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3) /***************************************************************************** * Load RTOS#2 *****************************************************************************/ /* Start loading RTOS#2 image */ load_image(&li[RTOS2_ID]); store_time_checkpoint("load_RTOS#2_done", li[RTOS2_ID].image_size); #if (BOOT_MODE == SECURE) /* Decryption image and Image cerfification */ if (NORMAL_BOOT != bootmode) { secureboot_image(&li[RTOS2_ID], 1); store_time_checkpoint("verify_RTOS#2_done", 0); } #endif /* BOOT_MODE == SECURE */ /* boot CR core2 */ arm_cpu_on(RCAR_PWR_TARGET_CR, li[RTOS2_ID].boot_addr, 2); store_time_checkpoint("started_RTOS#2", 0); #endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */ #if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) /***************************************************************************** * Load RTOS#0 *****************************************************************************/ #define _IPL_END (0xEB22FFF4) #ifdef MOBIS_PRK3 emmc_initialize(); store_time_checkpoint("emmc_initialize", 0); #if (BL2_LOAD_ENABLE == BL2_ENABLE) /* do not clear eMMC */ export_mmc_drv_obj(); #endif reg = mem_read32(AB_INFO_FLAG_ADDR); if (reg & AB_INFO_SELECT_2nd) slot = 1; // slot = ab_select_slot(); load_update_part_num(li, ca_load_num, slot); NOTICE("slot: %d\n", slot); mem_write32(_IPL_END, 0x0); #endif /* Start loading RTOS#0 image */ load_image(&li[RTOS_ID]); store_time_checkpoint("load_RTOS#0_done", li[RTOS_ID].image_size); #if (BOOT_MODE == SECURE) /* Decryption image and Image cerfification */ if (NORMAL_BOOT != bootmode) { /* WARNING! WARNING! WARNING! WARNING! */ /* TODO: set 1 to panic! later */ secureboot_image(&li[RTOS_ID], 0); store_time_checkpoint("verify_RTOS#0_done", 0); } #endif /* BOOT_MODE == SECURE */ /* boot CR core0 */ arm_cpu_on(RCAR_PWR_TARGET_CR, li[RTOS_ID].boot_addr, -1); #ifdef MOBIS_PRK3 /* enable CR-52 Core 2 */ arm_cpu_on(RCAR_PWR_TARGET_CR, li[RTOS_ID].boot_addr, 2); store_time_checkpoint("started_RTOS#0", 0); #endif #if (BOOT_TIME_CHECK != 0) gpio_N1305(2); #endif #endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */ /***************************************************************************** * Load CA Program#2--#8 *****************************************************************************/ #if (BL2_LOAD_ENABLE == BL2_DISABLE) /* Start loading CA Program#n image */ for (loop = 0U; loop < ca_load_num; loop++) #else /* load bl2 */ loop = (CA_BL2_ID - CA_OPTIONAL_ID); #endif { /* Loading start */ NOTICE("Loading %s...\n", li[CA_OPTIONAL_ID + loop].name); load_image(&li[CA_OPTIONAL_ID + loop]); store_time_checkpoint("load_CA_#_done", li[CA_OPTIONAL_ID + loop].image_size); #if (BOOT_MODE == SECURE) /* Decryption image and Image certification */ if (NORMAL_BOOT != bootmode) { secureboot_image(&li[CA_OPTIONAL_ID + loop], 1); store_time_checkpoint("verify_CA_#_done", 0); } #endif /* BOOT_MODE == SECURE */ } #if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) /* Set Secure Monitor parameter */ #if (OPTEE_LOAD_ENABLE == OPTEE_DISABLE) smoni_set_param(li[CA_OPTIONAL_ID].boot_addr, /* BL31 */ li[CA_OPTIONAL_ID + 1U].boot_addr); /* U-Boot */ #else #if (BL2_LOAD_ENABLE == BL2_DISABLE) /* BL2 will load these */ smoni_set_param(li[CA_OPTIONAL_ID].boot_addr, /* BL31 */ li[CA_OPTIONAL_ID + 1U].boot_addr, /* U-Boot */ li[CA_OPTIONAL_ID + 2U].boot_addr); /* OP-TEE */ #endif #endif /* OPTEE_LOAD_ENABLE == OPTEE_DISABLE */ /* Before Boot CPU, Set the division ratio for CPU operating frequency */ adj_ca_variant_freq(); /* boot CA */ #if (BL2_LOAD_ENABLE == BL2_DISABLE) arm_cpu_on(RCAR_PWR_TARGET_CA, li[CA_OPTIONAL_ID].boot_addr, -1); #else /* run BL2, not BL31 */ arm_cpu_on(RCAR_PWR_TARGET_CA, li[CA_BL2_ID].boot_addr, -1); #endif store_time_checkpoint("started_CA_core", 0); #if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3) /***************************************************************************** * Load RTOS#1 *****************************************************************************/ /* Start loading RTOS#1 image */ load_image(&li[RTOS1_ID]); store_time_checkpoint("load_RTOS#1_done", li[RTOS1_ID].image_size); #if (BOOT_MODE == SECURE) /* Decryption image and Image cerfification */ if (NORMAL_BOOT != bootmode) { secureboot_image(&li[RTOS1_ID], 1); store_time_checkpoint("verify_RTOS#1_done", 0); } #endif /* BOOT_MODE == SECURE */ #endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */ #if (ACC_PROT_ENABLE == PROTECTION_ENABLE) sdram_protection(AXMM_DPTSECCR_NUM); #if (OPTEE_LOAD_ENABLE == OPTEE_ENABLE) sdram_protection(AXMM_DPTSECCR_NUM2); #endif /* OPTEE_LOAD_ENABLE == OPTEE_ENABLE */ remove_rgid0_previlege(); /* * SAN(Safety Application Note) 6.23.5 Operation * Checker processor : * Check RegionID/LifeC & memory area protection settings (including order & content of intermediate updates) * done by ICUMX. */ rgid_protection_check(); ram_protection_check(); #endif /* ACC_PROT_ENABLE == PROTECTION_ENABLE */ #if (BOOT_MODE == SECURE) if (NORMAL_BOOT != bootmode) { /* Compare Hash verified at ICUMX IPL (V4H only). (Target images are Secure FW and Cx 2nd IPL.) */ /* * SAN(Safety Application Note) 6.23.5 Operation * Checker processor : * Re-do comparison of hash in Flash vs hash generated by ICUMX to confirm proper comparison. */ final_hash_cmp(); store_time_checkpoint("final_verify_done", 0); } #endif /* BOOT_MODE == SECURE */ NOTICE("Load finish.(CR52 Loader)\n"); #elif (RCAR_LSI == RCAR_S4) #if (ACC_PROT_ENABLE == PROTECTION_ENABLE) sdram_protection(AXMM_DPTSECCR_NUM); #endif /* ACC_PROT_ENABLE == PROTECTION_ENABLE */ NOTICE("Load finish.(CA55 Loader)\n"); #endif /* RCAR_LSI == RCAR_V4H || RCAR_LSI == RCAR_V4M */ // ip_release(); store_time_checkpoint("Cx_done_starting_RTOS#1", 0); // scmt_wait_ticks(SCMT_MS2TICKS(1000)); print_time_checkpoints(); #if (BOOT_TIME_CHECK != 0) gpio_N1305(2); #endif #if (RTOS_LOAD_NUM == RTOS_LOAD_NUM_1) #ifdef MOBIS_PRK3 return li[RTOS_ID].boot_addr; #else return li[CA_OPTIONAL_ID].boot_addr; #endif #elif (RTOS_LOAD_NUM == RTOS_LOAD_NUM_3) return li[RTOS1_ID].boot_addr; #endif /* RTOS_LOAD_NUM == RTOS_LOAD_NUM_3 */ } /* End of function loader_main(void) */ #if (ACC_PROT_ENABLE == PROTECTION_ENABLE) static void sdram_protection(uint32_t num) { uint32_t val; uint32_t addr; /* Calculation of the address of the DPTSECCR register. */ addr = (AXMM_DPTSECCR + (num * 4U)); val = mem_read32(addr); val &= ~(AXMM_DPTSECCR_SECGRP_MASK | AXMM_DPTSECCR_SECGWP_MASK); val |= (AXMM_DPTSECCR_SECGRP_SEC | AXMM_DPTSECCR_SECGWP_SEC); mem_write32(addr, val); }/* End of function void sdram_protection(void) */ #if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) static void remove_rgid0_previlege(void) { uint32_t val; uint32_t addr; /* Calculation of the address of the DPTRGNCR register. */ addr = get_dptrgncr_addr(DPTRGNCR_PROTECT_AREA); val = mem_read32(addr); val &= ~(AXMM_DPTRGNCR_RGN0RP_MASK | AXMM_DPTRGNCR_RGN0WP_MASK); val |= (AXMM_DPTRGNCR_RGN0RP| AXMM_DPTRGNCR_RGN0WP); /* Remove RGID0 read/write previlege on SDRAM Area. */ mem_write32(addr, val); /* Calculation of the address of the DPTRGNCR register. */ addr = get_dptrgncr_addr(DPTRGNCR_LINUX_AREA); val = mem_read32(addr); val &= ~(AXMM_DPTRGNCR_RGN0RP_MASK | AXMM_DPTRGNCR_RGN0WP_MASK); val |= (AXMM_DPTRGNCR_RGN0RP| AXMM_DPTRGNCR_RGN0WP); /* Remove RGID0 read/write previlege on SDRAM Area. */ mem_write32(addr, val); /* Calculation of the address of the SECCTRW0D_1 register. */ addr = get_rtvram1_secctrwd_addr(SECCTRWD_AREA0); val = mem_read32(addr); val &= ~(SECCTRWD_SAFG15WP_MASK); val |= SECCTRWD_SAFG15WP; /* Remove RGID0/2 write previlege on RT-VRAM1 Area0. */ mem_write32(addr, val); /* Calculation of the address of the SECCTRW2D_1 register. */ addr = get_rtvram1_secctrwd_addr(SECCTRWD_AREA2); val = mem_read32(addr); val &= ~(SECCTRWD_SAFG15WP_MASK); val |= SECCTRWD_SAFG15WP; /* Remove RGID0/2 write previlege on RT-VRAM1 Area2. */ mem_write32(addr, val); } /* End of function void remove_rgid0_previlege(void) */ #endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */ #endif /* ACC_PROT_ENABLE == PROTECTION_ENABLE */