14f6ad66aSAchin Gupta /* 2758ccb80SChris Kay * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved. 3*854b4dd9SToshiyuki Ogasahara * Copyright (c) 2021-2025, Renesas Electronics Corporation. All rights reserved. 44f6ad66aSAchin Gupta * 582cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 64f6ad66aSAchin Gupta */ 74f6ad66aSAchin Gupta 809d40e0eSAntonio Nino Diaz #include <assert.h> 909d40e0eSAntonio Nino Diaz #include <errno.h> 1009d40e0eSAntonio Nino Diaz #include <string.h> 1109d40e0eSAntonio Nino Diaz 1297043ac9SDan Handley #include <arch.h> 13b86048c4SAntonio Nino Diaz #include <arch_features.h> 144f6ad66aSAchin Gupta #include <arch_helpers.h> 1509d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 16758ccb80SChris Kay #include <common/build_message.h> 1709d40e0eSAntonio Nino Diaz #include <common/debug.h> 1809d40e0eSAntonio Nino Diaz #include <drivers/auth/auth_mod.h> 1909d40e0eSAntonio Nino Diaz #include <drivers/io/io_storage.h> 2009d40e0eSAntonio Nino Diaz #include <lib/utils.h> 2109d40e0eSAntonio Nino Diaz #include <lib/xlat_tables/xlat_tables_defs.h> 2209d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 234f6ad66aSAchin Gupta 24209a60ccSSoby Mathew #if TRUSTED_BOARD_BOOT 25209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 26209a60ccSSoby Mathew static int disable_auth; 27209a60ccSSoby Mathew 28209a60ccSSoby Mathew /****************************************************************************** 29209a60ccSSoby Mathew * API to dynamically disable authentication. Only meant for development 30ed51b51fSRoberto Vargas * systems. This is only invoked if DYN_DISABLE_AUTH is defined. 31209a60ccSSoby Mathew *****************************************************************************/ 32209a60ccSSoby Mathew void dyn_disable_auth(void) 33209a60ccSSoby Mathew { 34209a60ccSSoby Mathew INFO("Disabling authentication of images dynamically\n"); 35209a60ccSSoby Mathew disable_auth = 1; 36209a60ccSSoby Mathew } 37209a60ccSSoby Mathew # endif /* DYN_DISABLE_AUTH */ 38209a60ccSSoby Mathew 39209a60ccSSoby Mathew /****************************************************************************** 40209a60ccSSoby Mathew * Function to determine whether the authentication is disabled dynamically. 41209a60ccSSoby Mathew *****************************************************************************/ 42209a60ccSSoby Mathew static int dyn_is_auth_disabled(void) 43209a60ccSSoby Mathew { 44209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 45209a60ccSSoby Mathew return disable_auth; 46209a60ccSSoby Mathew # else 47209a60ccSSoby Mathew return 0; 48209a60ccSSoby Mathew # endif 49209a60ccSSoby Mathew } 50209a60ccSSoby Mathew #endif /* TRUSTED_BOARD_BOOT */ 51209a60ccSSoby Mathew 524c0d0390SSoby Mathew uintptr_t page_align(uintptr_t value, unsigned dir) 534f6ad66aSAchin Gupta { 544f6ad66aSAchin Gupta /* Round up the limit to the next page boundary */ 55d7b5f408SJimmy Brisson if ((value & PAGE_SIZE_MASK) != 0U) { 56d7b5f408SJimmy Brisson value &= ~PAGE_SIZE_MASK; 57618e37c3SSaivardhan Thatikonda if (dir == UP) { 584c0d0390SSoby Mathew value += PAGE_SIZE; 594f6ad66aSAchin Gupta } 60618e37c3SSaivardhan Thatikonda } 614f6ad66aSAchin Gupta 624f6ad66aSAchin Gupta return value; 634f6ad66aSAchin Gupta } 644f6ad66aSAchin Gupta 6572600226SYatharth Kochar /******************************************************************************* 6676163b3aSSoby Mathew * Internal function to load an image at a specific address given 6772600226SYatharth Kochar * an image ID and extents of free memory. 6872600226SYatharth Kochar * 6972600226SYatharth Kochar * If the load is successful then the image information is updated. 7072600226SYatharth Kochar * 7172600226SYatharth Kochar * Returns 0 on success, a negative error code otherwise. 7272600226SYatharth Kochar ******************************************************************************/ 7376163b3aSSoby Mathew static int load_image(unsigned int image_id, image_info_t *image_data) 7472600226SYatharth Kochar { 75929a290eSSaivardhan Thatikonda uintptr_t dev_handle = 0ULL; 76929a290eSSaivardhan Thatikonda uintptr_t image_handle = 0ULL; 77929a290eSSaivardhan Thatikonda uintptr_t image_spec = 0ULL; 7872600226SYatharth Kochar uintptr_t image_base; 79929a290eSSaivardhan Thatikonda size_t image_size = 0ULL; 80929a290eSSaivardhan Thatikonda size_t bytes_read = 0ULL; 8172600226SYatharth Kochar int io_result; 8272600226SYatharth Kochar 8372600226SYatharth Kochar assert(image_data != NULL); 8472600226SYatharth Kochar assert(image_data->h.version >= VERSION_2); 8572600226SYatharth Kochar 8672600226SYatharth Kochar image_base = image_data->image_base; 8772600226SYatharth Kochar 8872600226SYatharth Kochar /* Obtain a reference to the image by querying the platform layer */ 8972600226SYatharth Kochar io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 9072600226SYatharth Kochar if (io_result != 0) { 9172600226SYatharth Kochar WARN("Failed to obtain reference to image id=%u (%i)\n", 9272600226SYatharth Kochar image_id, io_result); 9372600226SYatharth Kochar return io_result; 9472600226SYatharth Kochar } 9572600226SYatharth Kochar 9672600226SYatharth Kochar /* Attempt to access the image */ 9772600226SYatharth Kochar io_result = io_open(dev_handle, image_spec, &image_handle); 9872600226SYatharth Kochar if (io_result != 0) { 9972600226SYatharth Kochar WARN("Failed to access image id=%u (%i)\n", 10072600226SYatharth Kochar image_id, io_result); 10172600226SYatharth Kochar return io_result; 10272600226SYatharth Kochar } 10372600226SYatharth Kochar 10481542c00SAntonio Nino Diaz INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base); 10572600226SYatharth Kochar 10672600226SYatharth Kochar /* Find the size of the image */ 10772600226SYatharth Kochar io_result = io_size(image_handle, &image_size); 108*854b4dd9SToshiyuki Ogasahara if (io_result != 0) { 10972600226SYatharth Kochar WARN("Failed to determine the size of the image id=%u (%i)\n", 11072600226SYatharth Kochar image_id, io_result); 1111db51f0aSSaivardhan Thatikonda goto exit_load_image; 11272600226SYatharth Kochar } 11372600226SYatharth Kochar 114*854b4dd9SToshiyuki Ogasahara if (image_size == 0U) { 115*854b4dd9SToshiyuki Ogasahara WARN("image id=%u size is zero\n", image_id); 116*854b4dd9SToshiyuki Ogasahara io_result = -EIO; 117*854b4dd9SToshiyuki Ogasahara goto exit_load_image; 118*854b4dd9SToshiyuki Ogasahara } 119*854b4dd9SToshiyuki Ogasahara 12072600226SYatharth Kochar /* Check that the image size to load is within limit */ 12172600226SYatharth Kochar if (image_size > image_data->image_max_size) { 12272600226SYatharth Kochar WARN("Image id=%u size out of bounds\n", image_id); 12372600226SYatharth Kochar io_result = -EFBIG; 1241db51f0aSSaivardhan Thatikonda goto exit_load_image; 12572600226SYatharth Kochar } 12672600226SYatharth Kochar 12781542c00SAntonio Nino Diaz /* 12881542c00SAntonio Nino Diaz * image_data->image_max_size is a uint32_t so image_size will always 12981542c00SAntonio Nino Diaz * fit in image_data->image_size. 13081542c00SAntonio Nino Diaz */ 13181542c00SAntonio Nino Diaz image_data->image_size = (uint32_t)image_size; 13272600226SYatharth Kochar 13372600226SYatharth Kochar /* We have enough space so load the image now */ 13472600226SYatharth Kochar /* TODO: Consider whether to try to recover/retry a partially successful read */ 13572600226SYatharth Kochar io_result = io_read(image_handle, image_base, image_size, &bytes_read); 13672600226SYatharth Kochar if ((io_result != 0) || (bytes_read < image_size)) { 13772600226SYatharth Kochar WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 1381db51f0aSSaivardhan Thatikonda goto exit_load_image; 13972600226SYatharth Kochar } 14072600226SYatharth Kochar 14181542c00SAntonio Nino Diaz INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base, 14281542c00SAntonio Nino Diaz (uintptr_t)(image_base + image_size)); 14372600226SYatharth Kochar 1441db51f0aSSaivardhan Thatikonda exit_load_image: 14581542c00SAntonio Nino Diaz (void)io_close(image_handle); 14672600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'close' */ 14772600226SYatharth Kochar 14872600226SYatharth Kochar /* TODO: Consider maintaining open device connection from this bootloader stage */ 14981542c00SAntonio Nino Diaz (void)io_dev_close(dev_handle); 15072600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'dev_close' */ 15172600226SYatharth Kochar 15272600226SYatharth Kochar return io_result; 15372600226SYatharth Kochar } 15472600226SYatharth Kochar 1559e7d6631SSandrine Bailleux #if TRUSTED_BOARD_BOOT 1569e7d6631SSandrine Bailleux /* 1579e7d6631SSandrine Bailleux * This function uses recursion to authenticate the parent images up to the root 1589e7d6631SSandrine Bailleux * of trust. 1599e7d6631SSandrine Bailleux */ 1609e7d6631SSandrine Bailleux static int load_auth_image_recursive(unsigned int image_id, 161800ba70bSManish V Badarkhe image_info_t *image_data) 16272600226SYatharth Kochar { 16372600226SYatharth Kochar int rc; 16472600226SYatharth Kochar unsigned int parent_id; 16572600226SYatharth Kochar 16672600226SYatharth Kochar /* Use recursion to authenticate parent images */ 16772600226SYatharth Kochar rc = auth_mod_get_parent_id(image_id, &parent_id); 16872600226SYatharth Kochar if (rc == 0) { 169800ba70bSManish V Badarkhe rc = load_auth_image_recursive(parent_id, image_data); 17072600226SYatharth Kochar if (rc != 0) { 17172600226SYatharth Kochar return rc; 17272600226SYatharth Kochar } 17372600226SYatharth Kochar } 17472600226SYatharth Kochar 17572600226SYatharth Kochar /* Load the image */ 17672600226SYatharth Kochar rc = load_image(image_id, image_data); 17772600226SYatharth Kochar if (rc != 0) { 17872600226SYatharth Kochar return rc; 17972600226SYatharth Kochar } 18072600226SYatharth Kochar 18172600226SYatharth Kochar /* Authenticate it */ 18272600226SYatharth Kochar rc = auth_mod_verify_img(image_id, 18372600226SYatharth Kochar (void *)image_data->image_base, 18472600226SYatharth Kochar image_data->image_size); 18572600226SYatharth Kochar if (rc != 0) { 1860f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 187308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 18872600226SYatharth Kochar image_data->image_size); 18972600226SYatharth Kochar flush_dcache_range(image_data->image_base, 19072600226SYatharth Kochar image_data->image_size); 19172600226SYatharth Kochar return -EAUTH; 19272600226SYatharth Kochar } 19372600226SYatharth Kochar 19472600226SYatharth Kochar return 0; 19572600226SYatharth Kochar } 1969e7d6631SSandrine Bailleux #endif /* TRUSTED_BOARD_BOOT */ 1979e7d6631SSandrine Bailleux 1989e7d6631SSandrine Bailleux static int load_auth_image_internal(unsigned int image_id, 1999e7d6631SSandrine Bailleux image_info_t *image_data) 2009e7d6631SSandrine Bailleux { 2019e7d6631SSandrine Bailleux #if TRUSTED_BOARD_BOOT 2029e7d6631SSandrine Bailleux if (dyn_is_auth_disabled() == 0) { 203800ba70bSManish V Badarkhe return load_auth_image_recursive(image_id, image_data); 2049e7d6631SSandrine Bailleux } 2059e7d6631SSandrine Bailleux #endif 2069e7d6631SSandrine Bailleux 2070aa0b3afSManish V Badarkhe return load_image(image_id, image_data); 2089e7d6631SSandrine Bailleux } 20972600226SYatharth Kochar 2100f325c67SAntonio Nino Diaz /******************************************************************************* 2110f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 2120f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 2130f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 2140f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 2159e7d6631SSandrine Bailleux * authenticate the parent images up to the root of trust (if TBB is enabled). 2160f325c67SAntonio Nino Diaz ******************************************************************************/ 2170f325c67SAntonio Nino Diaz int load_auth_image(unsigned int image_id, image_info_t *image_data) 2180f325c67SAntonio Nino Diaz { 21901f62b6dSRoberto Vargas int err; 22001f62b6dSRoberto Vargas 221a03dafe5SYann Gautier if ((plat_try_img_ops == NULL) || (plat_try_img_ops->next_instance == NULL)) { 2224b48f7b5SManish V Badarkhe err = load_auth_image_internal(image_id, image_data); 223a03dafe5SYann Gautier } else { 224a03dafe5SYann Gautier do { 225a03dafe5SYann Gautier err = load_auth_image_internal(image_id, image_data); 226a03dafe5SYann Gautier if (err != 0) { 227a03dafe5SYann Gautier if (plat_try_img_ops->next_instance(image_id) != 0) { 228a03dafe5SYann Gautier return err; 229a03dafe5SYann Gautier } 230a03dafe5SYann Gautier } 231a03dafe5SYann Gautier } while (err != 0); 232a03dafe5SYann Gautier } 23301f62b6dSRoberto Vargas 2340aa0b3afSManish V Badarkhe if (err == 0) { 2350aa0b3afSManish V Badarkhe /* 2360aa0b3afSManish V Badarkhe * If loading of the image gets passed (along with its 2370aa0b3afSManish V Badarkhe * authentication in case of Trusted-Boot flow) then measure 2380aa0b3afSManish V Badarkhe * it (if MEASURED_BOOT flag is enabled). 2390aa0b3afSManish V Badarkhe */ 2400aa0b3afSManish V Badarkhe err = plat_mboot_measure_image(image_id, image_data); 2410aa0b3afSManish V Badarkhe if (err != 0) { 2420aa0b3afSManish V Badarkhe return err; 2430aa0b3afSManish V Badarkhe } 2440aa0b3afSManish V Badarkhe 2450aa0b3afSManish V Badarkhe /* 2460aa0b3afSManish V Badarkhe * Flush the image to main memory so that it can be executed 2470aa0b3afSManish V Badarkhe * later by any CPU, regardless of cache and MMU state. 2480aa0b3afSManish V Badarkhe */ 2490aa0b3afSManish V Badarkhe flush_dcache_range(image_data->image_base, 2500aa0b3afSManish V Badarkhe image_data->image_size); 2510aa0b3afSManish V Badarkhe } 2520aa0b3afSManish V Badarkhe 25301f62b6dSRoberto Vargas return err; 2540f325c67SAntonio Nino Diaz } 2550f325c67SAntonio Nino Diaz 25668a68c92SSandrine Bailleux /******************************************************************************* 25768a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 25868a68c92SSandrine Bailleux ******************************************************************************/ 25968a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 26068a68c92SSandrine Bailleux { 26181542c00SAntonio Nino Diaz INFO("Entry point address = 0x%lx\n", ep_info->pc); 2624c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 26368a68c92SSandrine Bailleux 26468a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 26568a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 26668a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 26768a68c92SSandrine Bailleux 26868a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 26968a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 27068a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 27168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 272402b3cf8SJulius Werner #ifdef __aarch64__ 27368a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 27468a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 27568a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 27668a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 27751c79b73SSoby Mathew #endif 27868a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 27968a68c92SSandrine Bailleux } 280dddf4283Slaurenw-arm 281dddf4283Slaurenw-arm /* 282dddf4283Slaurenw-arm * This function is for returning the TF-A version 283dddf4283Slaurenw-arm */ 284dddf4283Slaurenw-arm const char *get_version(void) 285dddf4283Slaurenw-arm { 286758ccb80SChris Kay return build_version; 287dddf4283Slaurenw-arm } 288