14f6ad66aSAchin Gupta /* 2209a60ccSSoby Mathew * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. 34f6ad66aSAchin Gupta * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 54f6ad66aSAchin Gupta */ 64f6ad66aSAchin Gupta 7*09d40e0eSAntonio Nino Diaz #include <assert.h> 8*09d40e0eSAntonio Nino Diaz #include <errno.h> 9*09d40e0eSAntonio Nino Diaz #include <string.h> 10*09d40e0eSAntonio Nino Diaz 1197043ac9SDan Handley #include <arch.h> 124f6ad66aSAchin Gupta #include <arch_helpers.h> 13*09d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 14*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 15*09d40e0eSAntonio Nino Diaz #include <drivers/auth/auth_mod.h> 16*09d40e0eSAntonio Nino Diaz #include <drivers/io/io_storage.h> 17*09d40e0eSAntonio Nino Diaz #include <lib/utils.h> 18*09d40e0eSAntonio Nino Diaz #include <lib/xlat_tables/xlat_tables_defs.h> 19*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 204f6ad66aSAchin Gupta 21209a60ccSSoby Mathew #if TRUSTED_BOARD_BOOT 22209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 23209a60ccSSoby Mathew static int disable_auth; 24209a60ccSSoby Mathew 25209a60ccSSoby Mathew /****************************************************************************** 26209a60ccSSoby Mathew * API to dynamically disable authentication. Only meant for development 27ed51b51fSRoberto Vargas * systems. This is only invoked if DYN_DISABLE_AUTH is defined. 28209a60ccSSoby Mathew *****************************************************************************/ 29209a60ccSSoby Mathew void dyn_disable_auth(void) 30209a60ccSSoby Mathew { 31209a60ccSSoby Mathew INFO("Disabling authentication of images dynamically\n"); 32209a60ccSSoby Mathew disable_auth = 1; 33209a60ccSSoby Mathew } 34209a60ccSSoby Mathew # endif /* DYN_DISABLE_AUTH */ 35209a60ccSSoby Mathew 36209a60ccSSoby Mathew /****************************************************************************** 37209a60ccSSoby Mathew * Function to determine whether the authentication is disabled dynamically. 38209a60ccSSoby Mathew *****************************************************************************/ 39209a60ccSSoby Mathew static int dyn_is_auth_disabled(void) 40209a60ccSSoby Mathew { 41209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 42209a60ccSSoby Mathew return disable_auth; 43209a60ccSSoby Mathew # else 44209a60ccSSoby Mathew return 0; 45209a60ccSSoby Mathew # endif 46209a60ccSSoby Mathew } 47209a60ccSSoby Mathew #endif /* TRUSTED_BOARD_BOOT */ 48209a60ccSSoby Mathew 494c0d0390SSoby Mathew uintptr_t page_align(uintptr_t value, unsigned dir) 504f6ad66aSAchin Gupta { 514f6ad66aSAchin Gupta /* Round up the limit to the next page boundary */ 5281542c00SAntonio Nino Diaz if ((value & (PAGE_SIZE - 1U)) != 0U) { 5381542c00SAntonio Nino Diaz value &= ~(PAGE_SIZE - 1U); 544f6ad66aSAchin Gupta if (dir == UP) 554c0d0390SSoby Mathew value += PAGE_SIZE; 564f6ad66aSAchin Gupta } 574f6ad66aSAchin Gupta 584f6ad66aSAchin Gupta return value; 594f6ad66aSAchin Gupta } 604f6ad66aSAchin Gupta 618f55dfb4SSandrine Bailleux /****************************************************************************** 628f55dfb4SSandrine Bailleux * Determine whether the memory region delimited by 'addr' and 'size' is free, 638f55dfb4SSandrine Bailleux * given the extents of free memory. 647b6d330cSSandrine Bailleux * Return 1 if it is free, 0 if it is not free or if the input values are 657b6d330cSSandrine Bailleux * invalid. 668f55dfb4SSandrine Bailleux *****************************************************************************/ 6799c5ebafSSandrine Bailleux int is_mem_free(uintptr_t free_base, size_t free_size, 684c0d0390SSoby Mathew uintptr_t addr, size_t size) 694f6ad66aSAchin Gupta { 707b6d330cSSandrine Bailleux uintptr_t free_end, requested_end; 717b6d330cSSandrine Bailleux 727b6d330cSSandrine Bailleux /* 737b6d330cSSandrine Bailleux * Handle corner cases first. 747b6d330cSSandrine Bailleux * 757b6d330cSSandrine Bailleux * The order of the 2 tests is important, because if there's no space 767b6d330cSSandrine Bailleux * left (i.e. free_size == 0) but we don't ask for any memory 777b6d330cSSandrine Bailleux * (i.e. size == 0) then we should report that the memory is free. 787b6d330cSSandrine Bailleux */ 797b6d330cSSandrine Bailleux if (size == 0) 807b6d330cSSandrine Bailleux return 1; /* A zero-byte region is always free */ 817b6d330cSSandrine Bailleux if (free_size == 0) 827b6d330cSSandrine Bailleux return 0; 837b6d330cSSandrine Bailleux 847b6d330cSSandrine Bailleux /* 857b6d330cSSandrine Bailleux * Check that the end addresses don't overflow. 867b6d330cSSandrine Bailleux * If they do, consider that this memory region is not free, as this 877b6d330cSSandrine Bailleux * is an invalid scenario. 887b6d330cSSandrine Bailleux */ 897b6d330cSSandrine Bailleux if (check_uptr_overflow(free_base, free_size - 1)) 907b6d330cSSandrine Bailleux return 0; 917b6d330cSSandrine Bailleux free_end = free_base + (free_size - 1); 927b6d330cSSandrine Bailleux 937b6d330cSSandrine Bailleux if (check_uptr_overflow(addr, size - 1)) 947b6d330cSSandrine Bailleux return 0; 957b6d330cSSandrine Bailleux requested_end = addr + (size - 1); 967b6d330cSSandrine Bailleux 977b6d330cSSandrine Bailleux /* 987b6d330cSSandrine Bailleux * Finally, check that the requested memory region lies within the free 997b6d330cSSandrine Bailleux * region. 1007b6d330cSSandrine Bailleux */ 1017b6d330cSSandrine Bailleux return (addr >= free_base) && (requested_end <= free_end); 1024f6ad66aSAchin Gupta } 1034f6ad66aSAchin Gupta 104ee9ad785SRyan Harkin /* Generic function to return the size of an image */ 105d3775d46SDaniel Boulby size_t get_image_size(unsigned int image_id) 106ee9ad785SRyan Harkin { 107625de1d4SDan Handley uintptr_t dev_handle; 108625de1d4SDan Handley uintptr_t image_handle; 109625de1d4SDan Handley uintptr_t image_spec; 11081542c00SAntonio Nino Diaz size_t image_size = 0U; 111e098e244SJuan Castillo int io_result; 112ee9ad785SRyan Harkin 113ee9ad785SRyan Harkin /* Obtain a reference to the image by querying the platform layer */ 11416948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 115e098e244SJuan Castillo if (io_result != 0) { 11616948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 11716948ae1SJuan Castillo image_id, io_result); 118ee9ad785SRyan Harkin return 0; 119ee9ad785SRyan Harkin } 120ee9ad785SRyan Harkin 121ee9ad785SRyan Harkin /* Attempt to access the image */ 122ee9ad785SRyan Harkin io_result = io_open(dev_handle, image_spec, &image_handle); 123e098e244SJuan Castillo if (io_result != 0) { 12416948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 12516948ae1SJuan Castillo image_id, io_result); 126ee9ad785SRyan Harkin return 0; 127ee9ad785SRyan Harkin } 128ee9ad785SRyan Harkin 129ee9ad785SRyan Harkin /* Find the size of the image */ 130ee9ad785SRyan Harkin io_result = io_size(image_handle, &image_size); 13181542c00SAntonio Nino Diaz if ((io_result != 0) || (image_size == 0U)) { 13216948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 13316948ae1SJuan Castillo image_id, io_result); 134ee9ad785SRyan Harkin } 135ee9ad785SRyan Harkin io_result = io_close(image_handle); 136ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'close' */ 137ee9ad785SRyan Harkin 138ee9ad785SRyan Harkin /* TODO: Consider maintaining open device connection from this 139ee9ad785SRyan Harkin * bootloader stage 140ee9ad785SRyan Harkin */ 141ee9ad785SRyan Harkin io_result = io_dev_close(dev_handle); 142ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'dev_close' */ 143ee9ad785SRyan Harkin 144ee9ad785SRyan Harkin return image_size; 145ee9ad785SRyan Harkin } 1468f55dfb4SSandrine Bailleux 14772600226SYatharth Kochar /******************************************************************************* 14876163b3aSSoby Mathew * Internal function to load an image at a specific address given 14972600226SYatharth Kochar * an image ID and extents of free memory. 15072600226SYatharth Kochar * 15172600226SYatharth Kochar * If the load is successful then the image information is updated. 15272600226SYatharth Kochar * 15372600226SYatharth Kochar * Returns 0 on success, a negative error code otherwise. 15472600226SYatharth Kochar ******************************************************************************/ 15576163b3aSSoby Mathew static int load_image(unsigned int image_id, image_info_t *image_data) 15672600226SYatharth Kochar { 15772600226SYatharth Kochar uintptr_t dev_handle; 15872600226SYatharth Kochar uintptr_t image_handle; 15972600226SYatharth Kochar uintptr_t image_spec; 16072600226SYatharth Kochar uintptr_t image_base; 16172600226SYatharth Kochar size_t image_size; 16272600226SYatharth Kochar size_t bytes_read; 16372600226SYatharth Kochar int io_result; 16472600226SYatharth Kochar 16572600226SYatharth Kochar assert(image_data != NULL); 16672600226SYatharth Kochar assert(image_data->h.version >= VERSION_2); 16772600226SYatharth Kochar 16872600226SYatharth Kochar image_base = image_data->image_base; 16972600226SYatharth Kochar 17072600226SYatharth Kochar /* Obtain a reference to the image by querying the platform layer */ 17172600226SYatharth Kochar io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 17272600226SYatharth Kochar if (io_result != 0) { 17372600226SYatharth Kochar WARN("Failed to obtain reference to image id=%u (%i)\n", 17472600226SYatharth Kochar image_id, io_result); 17572600226SYatharth Kochar return io_result; 17672600226SYatharth Kochar } 17772600226SYatharth Kochar 17872600226SYatharth Kochar /* Attempt to access the image */ 17972600226SYatharth Kochar io_result = io_open(dev_handle, image_spec, &image_handle); 18072600226SYatharth Kochar if (io_result != 0) { 18172600226SYatharth Kochar WARN("Failed to access image id=%u (%i)\n", 18272600226SYatharth Kochar image_id, io_result); 18372600226SYatharth Kochar return io_result; 18472600226SYatharth Kochar } 18572600226SYatharth Kochar 18681542c00SAntonio Nino Diaz INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base); 18772600226SYatharth Kochar 18872600226SYatharth Kochar /* Find the size of the image */ 18972600226SYatharth Kochar io_result = io_size(image_handle, &image_size); 19081542c00SAntonio Nino Diaz if ((io_result != 0) || (image_size == 0U)) { 19172600226SYatharth Kochar WARN("Failed to determine the size of the image id=%u (%i)\n", 19272600226SYatharth Kochar image_id, io_result); 19372600226SYatharth Kochar goto exit; 19472600226SYatharth Kochar } 19572600226SYatharth Kochar 19672600226SYatharth Kochar /* Check that the image size to load is within limit */ 19772600226SYatharth Kochar if (image_size > image_data->image_max_size) { 19872600226SYatharth Kochar WARN("Image id=%u size out of bounds\n", image_id); 19972600226SYatharth Kochar io_result = -EFBIG; 20072600226SYatharth Kochar goto exit; 20172600226SYatharth Kochar } 20272600226SYatharth Kochar 20381542c00SAntonio Nino Diaz /* 20481542c00SAntonio Nino Diaz * image_data->image_max_size is a uint32_t so image_size will always 20581542c00SAntonio Nino Diaz * fit in image_data->image_size. 20681542c00SAntonio Nino Diaz */ 20781542c00SAntonio Nino Diaz image_data->image_size = (uint32_t)image_size; 20872600226SYatharth Kochar 20972600226SYatharth Kochar /* We have enough space so load the image now */ 21072600226SYatharth Kochar /* TODO: Consider whether to try to recover/retry a partially successful read */ 21172600226SYatharth Kochar io_result = io_read(image_handle, image_base, image_size, &bytes_read); 21272600226SYatharth Kochar if ((io_result != 0) || (bytes_read < image_size)) { 21372600226SYatharth Kochar WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 21472600226SYatharth Kochar goto exit; 21572600226SYatharth Kochar } 21672600226SYatharth Kochar 21781542c00SAntonio Nino Diaz INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base, 21881542c00SAntonio Nino Diaz (uintptr_t)(image_base + image_size)); 21972600226SYatharth Kochar 22072600226SYatharth Kochar exit: 22181542c00SAntonio Nino Diaz (void)io_close(image_handle); 22272600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'close' */ 22372600226SYatharth Kochar 22472600226SYatharth Kochar /* TODO: Consider maintaining open device connection from this bootloader stage */ 22581542c00SAntonio Nino Diaz (void)io_dev_close(dev_handle); 22672600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'dev_close' */ 22772600226SYatharth Kochar 22872600226SYatharth Kochar return io_result; 22972600226SYatharth Kochar } 23072600226SYatharth Kochar 2310f325c67SAntonio Nino Diaz static int load_auth_image_internal(unsigned int image_id, 2320f325c67SAntonio Nino Diaz image_info_t *image_data, 2330f325c67SAntonio Nino Diaz int is_parent_image) 23472600226SYatharth Kochar { 23572600226SYatharth Kochar int rc; 23672600226SYatharth Kochar 23772600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 238209a60ccSSoby Mathew if (dyn_is_auth_disabled() == 0) { 23972600226SYatharth Kochar unsigned int parent_id; 24072600226SYatharth Kochar 24172600226SYatharth Kochar /* Use recursion to authenticate parent images */ 24272600226SYatharth Kochar rc = auth_mod_get_parent_id(image_id, &parent_id); 24372600226SYatharth Kochar if (rc == 0) { 2440f325c67SAntonio Nino Diaz rc = load_auth_image_internal(parent_id, image_data, 1); 24572600226SYatharth Kochar if (rc != 0) { 24672600226SYatharth Kochar return rc; 24772600226SYatharth Kochar } 24872600226SYatharth Kochar } 249209a60ccSSoby Mathew } 25072600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 25172600226SYatharth Kochar 25272600226SYatharth Kochar /* Load the image */ 25372600226SYatharth Kochar rc = load_image(image_id, image_data); 25472600226SYatharth Kochar if (rc != 0) { 25572600226SYatharth Kochar return rc; 25672600226SYatharth Kochar } 25772600226SYatharth Kochar 25872600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 259209a60ccSSoby Mathew if (dyn_is_auth_disabled() == 0) { 26072600226SYatharth Kochar /* Authenticate it */ 26172600226SYatharth Kochar rc = auth_mod_verify_img(image_id, 26272600226SYatharth Kochar (void *)image_data->image_base, 26372600226SYatharth Kochar image_data->image_size); 26472600226SYatharth Kochar if (rc != 0) { 2650f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 266308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 26772600226SYatharth Kochar image_data->image_size); 26872600226SYatharth Kochar flush_dcache_range(image_data->image_base, 26972600226SYatharth Kochar image_data->image_size); 27072600226SYatharth Kochar return -EAUTH; 27172600226SYatharth Kochar } 272209a60ccSSoby Mathew } 27376163b3aSSoby Mathew #endif /* TRUSTED_BOARD_BOOT */ 27472600226SYatharth Kochar 27572600226SYatharth Kochar /* 27672600226SYatharth Kochar * Flush the image to main memory so that it can be executed later by 27776163b3aSSoby Mathew * any CPU, regardless of cache and MMU state. If TBB is enabled, then 27876163b3aSSoby Mathew * the file has been successfully loaded and authenticated and flush 27976163b3aSSoby Mathew * only for child images, not for the parents (certificates). 28072600226SYatharth Kochar */ 28181542c00SAntonio Nino Diaz if (is_parent_image == 0) { 2820f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 2830f325c67SAntonio Nino Diaz image_data->image_size); 2840f325c67SAntonio Nino Diaz } 28576163b3aSSoby Mathew 28672600226SYatharth Kochar 28772600226SYatharth Kochar return 0; 28872600226SYatharth Kochar } 28972600226SYatharth Kochar 2900f325c67SAntonio Nino Diaz /******************************************************************************* 2910f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 2920f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 2930f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 2940f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 2950f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 2960f325c67SAntonio Nino Diaz ******************************************************************************/ 2970f325c67SAntonio Nino Diaz int load_auth_image(unsigned int image_id, image_info_t *image_data) 2980f325c67SAntonio Nino Diaz { 29901f62b6dSRoberto Vargas int err; 30001f62b6dSRoberto Vargas 30101f62b6dSRoberto Vargas do { 30201f62b6dSRoberto Vargas err = load_auth_image_internal(image_id, image_data, 0); 30381542c00SAntonio Nino Diaz } while ((err != 0) && (plat_try_next_boot_source() != 0)); 30401f62b6dSRoberto Vargas 30501f62b6dSRoberto Vargas return err; 3060f325c67SAntonio Nino Diaz } 3070f325c67SAntonio Nino Diaz 30868a68c92SSandrine Bailleux /******************************************************************************* 30968a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 31068a68c92SSandrine Bailleux ******************************************************************************/ 31168a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 31268a68c92SSandrine Bailleux { 31381542c00SAntonio Nino Diaz INFO("Entry point address = 0x%lx\n", ep_info->pc); 3144c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 31568a68c92SSandrine Bailleux 31668a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 31768a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 31868a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 31968a68c92SSandrine Bailleux 32068a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 32168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 32268a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 32368a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 32451c79b73SSoby Mathew #ifndef AARCH32 32568a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 32668a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 32768a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 32868a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 32951c79b73SSoby Mathew #endif 33068a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 33168a68c92SSandrine Bailleux } 332