/******************************************************************************* * 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) */