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 797043ac9SDan Handley #include <arch.h> 84f6ad66aSAchin Gupta #include <arch_helpers.h> 997043ac9SDan Handley #include <assert.h> 101779ba6bSJuan Castillo #include <auth_mod.h> 114f6ad66aSAchin Gupta #include <bl_common.h> 1235e98e55SDan Handley #include <debug.h> 138f55dfb4SSandrine Bailleux #include <errno.h> 1497043ac9SDan Handley #include <io_storage.h> 1597043ac9SDan Handley #include <platform.h> 16fedbc049SJuan Castillo #include <string.h> 177b6d330cSSandrine Bailleux #include <utils.h> 18d50ece03SAntonio Nino Diaz #include <xlat_tables_defs.h> 194f6ad66aSAchin Gupta 20209a60ccSSoby Mathew #if TRUSTED_BOARD_BOOT 21209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 22209a60ccSSoby Mathew static int disable_auth; 23209a60ccSSoby Mathew 24209a60ccSSoby Mathew /****************************************************************************** 25209a60ccSSoby Mathew * API to dynamically disable authentication. Only meant for development 26209a60ccSSoby Mathew * systems. This is only invoked if DYN_DISABLE_AUTH is defined. This 27209a60ccSSoby Mathew * capability is restricted to LOAD_IMAGE_V2. 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 */ 524c0d0390SSoby Mathew if (value & (PAGE_SIZE - 1)) { 534c0d0390SSoby Mathew value &= ~(PAGE_SIZE - 1); 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 10499c5ebafSSandrine Bailleux #if !LOAD_IMAGE_V2 1058f55dfb4SSandrine Bailleux /****************************************************************************** 1068f55dfb4SSandrine Bailleux * Inside a given memory region, determine whether a sub-region of memory is 1078f55dfb4SSandrine Bailleux * closer from the top or the bottom of the encompassing region. Return the 1088f55dfb4SSandrine Bailleux * size of the smallest chunk of free memory surrounding the sub-region in 1098f55dfb4SSandrine Bailleux * 'small_chunk_size'. 1108f55dfb4SSandrine Bailleux *****************************************************************************/ 1114c0d0390SSoby Mathew static unsigned int choose_mem_pos(uintptr_t mem_start, uintptr_t mem_end, 1124c0d0390SSoby Mathew uintptr_t submem_start, uintptr_t submem_end, 1138f55dfb4SSandrine Bailleux size_t *small_chunk_size) 1148f55dfb4SSandrine Bailleux { 1158f55dfb4SSandrine Bailleux size_t top_chunk_size, bottom_chunk_size; 1164f6ad66aSAchin Gupta 1178f55dfb4SSandrine Bailleux assert(mem_start <= submem_start); 1188f55dfb4SSandrine Bailleux assert(submem_start <= submem_end); 1198f55dfb4SSandrine Bailleux assert(submem_end <= mem_end); 1208f55dfb4SSandrine Bailleux assert(small_chunk_size != NULL); 1218f55dfb4SSandrine Bailleux 1228f55dfb4SSandrine Bailleux top_chunk_size = mem_end - submem_end; 1238f55dfb4SSandrine Bailleux bottom_chunk_size = submem_start - mem_start; 1248f55dfb4SSandrine Bailleux 1258f55dfb4SSandrine Bailleux if (top_chunk_size < bottom_chunk_size) { 1268f55dfb4SSandrine Bailleux *small_chunk_size = top_chunk_size; 1278f55dfb4SSandrine Bailleux return TOP; 1288f55dfb4SSandrine Bailleux } else { 1298f55dfb4SSandrine Bailleux *small_chunk_size = bottom_chunk_size; 1308f55dfb4SSandrine Bailleux return BOTTOM; 1318f55dfb4SSandrine Bailleux } 1328f55dfb4SSandrine Bailleux } 1338f55dfb4SSandrine Bailleux 1348f55dfb4SSandrine Bailleux /****************************************************************************** 1358f55dfb4SSandrine Bailleux * Reserve the memory region delimited by 'addr' and 'size'. The extents of free 1368f55dfb4SSandrine Bailleux * memory are passed in 'free_base' and 'free_size' and they will be updated to 1378f55dfb4SSandrine Bailleux * reflect the memory usage. 1387b6d330cSSandrine Bailleux * The caller must ensure the memory to reserve is free and that the addresses 1397b6d330cSSandrine Bailleux * and sizes passed in arguments are sane. 1408f55dfb4SSandrine Bailleux *****************************************************************************/ 1414c0d0390SSoby Mathew void reserve_mem(uintptr_t *free_base, size_t *free_size, 1424c0d0390SSoby Mathew uintptr_t addr, size_t size) 1438f55dfb4SSandrine Bailleux { 1448f55dfb4SSandrine Bailleux size_t discard_size; 1458f55dfb4SSandrine Bailleux size_t reserved_size; 1468f55dfb4SSandrine Bailleux unsigned int pos; 1478f55dfb4SSandrine Bailleux 1488f55dfb4SSandrine Bailleux assert(free_base != NULL); 1498f55dfb4SSandrine Bailleux assert(free_size != NULL); 1508f55dfb4SSandrine Bailleux assert(is_mem_free(*free_base, *free_size, addr, size)); 1518f55dfb4SSandrine Bailleux 1527b6d330cSSandrine Bailleux if (size == 0) { 1537b6d330cSSandrine Bailleux WARN("Nothing to allocate, requested size is zero\n"); 1547b6d330cSSandrine Bailleux return; 1557b6d330cSSandrine Bailleux } 1567b6d330cSSandrine Bailleux 1577b6d330cSSandrine Bailleux pos = choose_mem_pos(*free_base, *free_base + (*free_size - 1), 1587b6d330cSSandrine Bailleux addr, addr + (size - 1), 1598f55dfb4SSandrine Bailleux &discard_size); 1608f55dfb4SSandrine Bailleux 1618f55dfb4SSandrine Bailleux reserved_size = size + discard_size; 1628f55dfb4SSandrine Bailleux *free_size -= reserved_size; 1638f55dfb4SSandrine Bailleux 1648f55dfb4SSandrine Bailleux if (pos == BOTTOM) 1658f55dfb4SSandrine Bailleux *free_base = addr + size; 1668f55dfb4SSandrine Bailleux 1674c0d0390SSoby Mathew VERBOSE("Reserved 0x%zx bytes (discarded 0x%zx bytes %s)\n", 1688f55dfb4SSandrine Bailleux reserved_size, discard_size, 1698f55dfb4SSandrine Bailleux pos == TOP ? "above" : "below"); 1704f6ad66aSAchin Gupta } 1714f6ad66aSAchin Gupta 1724c0d0390SSoby Mathew static void dump_load_info(uintptr_t image_load_addr, 1734c0d0390SSoby Mathew size_t image_size, 174fb037bfbSDan Handley const meminfo_t *mem_layout) 1754f6ad66aSAchin Gupta { 1764c0d0390SSoby Mathew INFO("Trying to load image at address %p, size = 0x%zx\n", 1774c0d0390SSoby Mathew (void *)image_load_addr, image_size); 1786ad2e461SDan Handley INFO("Current memory layout:\n"); 1797b6d330cSSandrine Bailleux INFO(" total region = [base = %p, size = 0x%zx]\n", 1807b6d330cSSandrine Bailleux (void *) mem_layout->total_base, mem_layout->total_size); 1817b6d330cSSandrine Bailleux INFO(" free region = [base = %p, size = 0x%zx]\n", 1827b6d330cSSandrine Bailleux (void *) mem_layout->free_base, mem_layout->free_size); 1834f6ad66aSAchin Gupta } 18472600226SYatharth Kochar #endif /* LOAD_IMAGE_V2 */ 1854f6ad66aSAchin Gupta 186ee9ad785SRyan Harkin /* Generic function to return the size of an image */ 187*d3775d46SDaniel Boulby size_t get_image_size(unsigned int image_id) 188ee9ad785SRyan Harkin { 189625de1d4SDan Handley uintptr_t dev_handle; 190625de1d4SDan Handley uintptr_t image_handle; 191625de1d4SDan Handley uintptr_t image_spec; 192ee9ad785SRyan Harkin size_t image_size = 0; 193e098e244SJuan Castillo int io_result; 194ee9ad785SRyan Harkin 195ee9ad785SRyan Harkin /* Obtain a reference to the image by querying the platform layer */ 19616948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 197e098e244SJuan Castillo if (io_result != 0) { 19816948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 19916948ae1SJuan Castillo image_id, io_result); 200ee9ad785SRyan Harkin return 0; 201ee9ad785SRyan Harkin } 202ee9ad785SRyan Harkin 203ee9ad785SRyan Harkin /* Attempt to access the image */ 204ee9ad785SRyan Harkin io_result = io_open(dev_handle, image_spec, &image_handle); 205e098e244SJuan Castillo if (io_result != 0) { 20616948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 20716948ae1SJuan Castillo image_id, io_result); 208ee9ad785SRyan Harkin return 0; 209ee9ad785SRyan Harkin } 210ee9ad785SRyan Harkin 211ee9ad785SRyan Harkin /* Find the size of the image */ 212ee9ad785SRyan Harkin io_result = io_size(image_handle, &image_size); 213e098e244SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 21416948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 21516948ae1SJuan Castillo image_id, io_result); 216ee9ad785SRyan Harkin } 217ee9ad785SRyan Harkin io_result = io_close(image_handle); 218ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'close' */ 219ee9ad785SRyan Harkin 220ee9ad785SRyan Harkin /* TODO: Consider maintaining open device connection from this 221ee9ad785SRyan Harkin * bootloader stage 222ee9ad785SRyan Harkin */ 223ee9ad785SRyan Harkin io_result = io_dev_close(dev_handle); 224ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'dev_close' */ 225ee9ad785SRyan Harkin 226ee9ad785SRyan Harkin return image_size; 227ee9ad785SRyan Harkin } 2288f55dfb4SSandrine Bailleux 22972600226SYatharth Kochar #if LOAD_IMAGE_V2 23072600226SYatharth Kochar 23172600226SYatharth Kochar /******************************************************************************* 23276163b3aSSoby Mathew * Internal function to load an image at a specific address given 23372600226SYatharth Kochar * an image ID and extents of free memory. 23472600226SYatharth Kochar * 23572600226SYatharth Kochar * If the load is successful then the image information is updated. 23672600226SYatharth Kochar * 23772600226SYatharth Kochar * Returns 0 on success, a negative error code otherwise. 23872600226SYatharth Kochar ******************************************************************************/ 23976163b3aSSoby Mathew static int load_image(unsigned int image_id, image_info_t *image_data) 24072600226SYatharth Kochar { 24172600226SYatharth Kochar uintptr_t dev_handle; 24272600226SYatharth Kochar uintptr_t image_handle; 24372600226SYatharth Kochar uintptr_t image_spec; 24472600226SYatharth Kochar uintptr_t image_base; 24572600226SYatharth Kochar size_t image_size; 24672600226SYatharth Kochar size_t bytes_read; 24772600226SYatharth Kochar int io_result; 24872600226SYatharth Kochar 24972600226SYatharth Kochar assert(image_data != NULL); 25072600226SYatharth Kochar assert(image_data->h.version >= VERSION_2); 25172600226SYatharth Kochar 25272600226SYatharth Kochar image_base = image_data->image_base; 25372600226SYatharth Kochar 25472600226SYatharth Kochar /* Obtain a reference to the image by querying the platform layer */ 25572600226SYatharth Kochar io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 25672600226SYatharth Kochar if (io_result != 0) { 25772600226SYatharth Kochar WARN("Failed to obtain reference to image id=%u (%i)\n", 25872600226SYatharth Kochar image_id, io_result); 25972600226SYatharth Kochar return io_result; 26072600226SYatharth Kochar } 26172600226SYatharth Kochar 26272600226SYatharth Kochar /* Attempt to access the image */ 26372600226SYatharth Kochar io_result = io_open(dev_handle, image_spec, &image_handle); 26472600226SYatharth Kochar if (io_result != 0) { 26572600226SYatharth Kochar WARN("Failed to access image id=%u (%i)\n", 26672600226SYatharth Kochar image_id, io_result); 26772600226SYatharth Kochar return io_result; 26872600226SYatharth Kochar } 26972600226SYatharth Kochar 27072600226SYatharth Kochar INFO("Loading image id=%u at address %p\n", image_id, 27172600226SYatharth Kochar (void *) image_base); 27272600226SYatharth Kochar 27372600226SYatharth Kochar /* Find the size of the image */ 27472600226SYatharth Kochar io_result = io_size(image_handle, &image_size); 27572600226SYatharth Kochar if ((io_result != 0) || (image_size == 0)) { 27672600226SYatharth Kochar WARN("Failed to determine the size of the image id=%u (%i)\n", 27772600226SYatharth Kochar image_id, io_result); 27872600226SYatharth Kochar goto exit; 27972600226SYatharth Kochar } 28072600226SYatharth Kochar 28172600226SYatharth Kochar /* Check that the image size to load is within limit */ 28272600226SYatharth Kochar if (image_size > image_data->image_max_size) { 28372600226SYatharth Kochar WARN("Image id=%u size out of bounds\n", image_id); 28472600226SYatharth Kochar io_result = -EFBIG; 28572600226SYatharth Kochar goto exit; 28672600226SYatharth Kochar } 28772600226SYatharth Kochar 28872600226SYatharth Kochar image_data->image_size = image_size; 28972600226SYatharth Kochar 29072600226SYatharth Kochar /* We have enough space so load the image now */ 29172600226SYatharth Kochar /* TODO: Consider whether to try to recover/retry a partially successful read */ 29272600226SYatharth Kochar io_result = io_read(image_handle, image_base, image_size, &bytes_read); 29372600226SYatharth Kochar if ((io_result != 0) || (bytes_read < image_size)) { 29472600226SYatharth Kochar WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 29572600226SYatharth Kochar goto exit; 29672600226SYatharth Kochar } 29772600226SYatharth Kochar 29872600226SYatharth Kochar INFO("Image id=%u loaded: %p - %p\n", image_id, (void *) image_base, 29972600226SYatharth Kochar (void *) (image_base + image_size)); 30072600226SYatharth Kochar 30172600226SYatharth Kochar exit: 30272600226SYatharth Kochar io_close(image_handle); 30372600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'close' */ 30472600226SYatharth Kochar 30572600226SYatharth Kochar /* TODO: Consider maintaining open device connection from this bootloader stage */ 30672600226SYatharth Kochar io_dev_close(dev_handle); 30772600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'dev_close' */ 30872600226SYatharth Kochar 30972600226SYatharth Kochar return io_result; 31072600226SYatharth Kochar } 31172600226SYatharth Kochar 3120f325c67SAntonio Nino Diaz static int load_auth_image_internal(unsigned int image_id, 3130f325c67SAntonio Nino Diaz image_info_t *image_data, 3140f325c67SAntonio Nino Diaz int is_parent_image) 31572600226SYatharth Kochar { 31672600226SYatharth Kochar int rc; 31772600226SYatharth Kochar 31872600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 319209a60ccSSoby Mathew if (dyn_is_auth_disabled() == 0) { 32072600226SYatharth Kochar unsigned int parent_id; 32172600226SYatharth Kochar 32272600226SYatharth Kochar /* Use recursion to authenticate parent images */ 32372600226SYatharth Kochar rc = auth_mod_get_parent_id(image_id, &parent_id); 32472600226SYatharth Kochar if (rc == 0) { 3250f325c67SAntonio Nino Diaz rc = load_auth_image_internal(parent_id, image_data, 1); 32672600226SYatharth Kochar if (rc != 0) { 32772600226SYatharth Kochar return rc; 32872600226SYatharth Kochar } 32972600226SYatharth Kochar } 330209a60ccSSoby Mathew } 33172600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 33272600226SYatharth Kochar 33372600226SYatharth Kochar /* Load the image */ 33472600226SYatharth Kochar rc = load_image(image_id, image_data); 33572600226SYatharth Kochar if (rc != 0) { 33672600226SYatharth Kochar return rc; 33772600226SYatharth Kochar } 33872600226SYatharth Kochar 33972600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 340209a60ccSSoby Mathew if (dyn_is_auth_disabled() == 0) { 34172600226SYatharth Kochar /* Authenticate it */ 34272600226SYatharth Kochar rc = auth_mod_verify_img(image_id, 34372600226SYatharth Kochar (void *)image_data->image_base, 34472600226SYatharth Kochar image_data->image_size); 34572600226SYatharth Kochar if (rc != 0) { 3460f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 347308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 34872600226SYatharth Kochar image_data->image_size); 34972600226SYatharth Kochar flush_dcache_range(image_data->image_base, 35072600226SYatharth Kochar image_data->image_size); 35172600226SYatharth Kochar return -EAUTH; 35272600226SYatharth Kochar } 353209a60ccSSoby Mathew } 35476163b3aSSoby Mathew #endif /* TRUSTED_BOARD_BOOT */ 35572600226SYatharth Kochar 35672600226SYatharth Kochar /* 35772600226SYatharth Kochar * Flush the image to main memory so that it can be executed later by 35876163b3aSSoby Mathew * any CPU, regardless of cache and MMU state. If TBB is enabled, then 35976163b3aSSoby Mathew * the file has been successfully loaded and authenticated and flush 36076163b3aSSoby Mathew * only for child images, not for the parents (certificates). 36172600226SYatharth Kochar */ 3620f325c67SAntonio Nino Diaz if (!is_parent_image) { 3630f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 3640f325c67SAntonio Nino Diaz image_data->image_size); 3650f325c67SAntonio Nino Diaz } 36676163b3aSSoby Mathew 36772600226SYatharth Kochar 36872600226SYatharth Kochar return 0; 36972600226SYatharth Kochar } 37072600226SYatharth Kochar 3710f325c67SAntonio Nino Diaz /******************************************************************************* 3720f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 3730f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 3740f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 3750f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 3760f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 3770f325c67SAntonio Nino Diaz ******************************************************************************/ 3780f325c67SAntonio Nino Diaz int load_auth_image(unsigned int image_id, image_info_t *image_data) 3790f325c67SAntonio Nino Diaz { 38001f62b6dSRoberto Vargas int err; 38101f62b6dSRoberto Vargas 38201f62b6dSRoberto Vargas do { 38301f62b6dSRoberto Vargas err = load_auth_image_internal(image_id, image_data, 0); 38401f62b6dSRoberto Vargas } while (err != 0 && plat_try_next_boot_source()); 38501f62b6dSRoberto Vargas 38601f62b6dSRoberto Vargas return err; 3870f325c67SAntonio Nino Diaz } 3880f325c67SAntonio Nino Diaz 38972600226SYatharth Kochar #else /* LOAD_IMAGE_V2 */ 39072600226SYatharth Kochar 3914f6ad66aSAchin Gupta /******************************************************************************* 392a6b995fbSSandrine Bailleux * Generic function to load an image at a specific address given an image ID and 393a6b995fbSSandrine Bailleux * extents of free memory. 394a6b995fbSSandrine Bailleux * 395a6b995fbSSandrine Bailleux * If the load is successful then the image information is updated. 396a6b995fbSSandrine Bailleux * 397a6b995fbSSandrine Bailleux * If the entry_point_info argument is not NULL then this function also updates: 398a6b995fbSSandrine Bailleux * - the memory layout to mark the memory as reserved; 399a6b995fbSSandrine Bailleux * - the entry point information. 400a6b995fbSSandrine Bailleux * 401a6b995fbSSandrine Bailleux * The caller might pass a NULL pointer for the entry point if they are not 402a6b995fbSSandrine Bailleux * interested in this information. This is typically the case for non-executable 403a6b995fbSSandrine Bailleux * images (e.g. certificates) and executable images that won't ever be executed 404a6b995fbSSandrine Bailleux * on the application processor (e.g. additional microcontroller firmware). 405a6b995fbSSandrine Bailleux * 4068f55dfb4SSandrine Bailleux * Returns 0 on success, a negative error code otherwise. 4074f6ad66aSAchin Gupta ******************************************************************************/ 4084112bfa0SVikram Kanigiri int load_image(meminfo_t *mem_layout, 40916948ae1SJuan Castillo unsigned int image_id, 4101779ba6bSJuan Castillo uintptr_t image_base, 4114112bfa0SVikram Kanigiri image_info_t *image_data, 4124112bfa0SVikram Kanigiri entry_point_info_t *entry_point_info) 4134f6ad66aSAchin Gupta { 414625de1d4SDan Handley uintptr_t dev_handle; 415625de1d4SDan Handley uintptr_t image_handle; 416625de1d4SDan Handley uintptr_t image_spec; 4178f55dfb4SSandrine Bailleux size_t image_size; 4188f55dfb4SSandrine Bailleux size_t bytes_read; 41978460a05SJuan Castillo int io_result; 4204f6ad66aSAchin Gupta 4219d72b4eaSJames Morrissey assert(mem_layout != NULL); 4228f55dfb4SSandrine Bailleux assert(image_data != NULL); 42372600226SYatharth Kochar assert(image_data->h.version == VERSION_1); 4249d72b4eaSJames Morrissey 4259d72b4eaSJames Morrissey /* Obtain a reference to the image by querying the platform layer */ 42616948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 42778460a05SJuan Castillo if (io_result != 0) { 42816948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 42916948ae1SJuan Castillo image_id, io_result); 4304112bfa0SVikram Kanigiri return io_result; 4314f6ad66aSAchin Gupta } 4324f6ad66aSAchin Gupta 4339d72b4eaSJames Morrissey /* Attempt to access the image */ 4349d72b4eaSJames Morrissey io_result = io_open(dev_handle, image_spec, &image_handle); 43578460a05SJuan Castillo if (io_result != 0) { 43616948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 43716948ae1SJuan Castillo image_id, io_result); 4384112bfa0SVikram Kanigiri return io_result; 4394f6ad66aSAchin Gupta } 4404f6ad66aSAchin Gupta 441f0dd061aSAntonio Nino Diaz INFO("Loading image id=%u at address %p\n", image_id, 442f0dd061aSAntonio Nino Diaz (void *) image_base); 4438f55dfb4SSandrine Bailleux 4449d72b4eaSJames Morrissey /* Find the size of the image */ 4459d72b4eaSJames Morrissey io_result = io_size(image_handle, &image_size); 44678460a05SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 44716948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 44816948ae1SJuan Castillo image_id, io_result); 4494112bfa0SVikram Kanigiri goto exit; 4509d72b4eaSJames Morrissey } 4519d72b4eaSJames Morrissey 4528f55dfb4SSandrine Bailleux /* Check that the memory where the image will be loaded is free */ 4538f55dfb4SSandrine Bailleux if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, 4548f55dfb4SSandrine Bailleux image_base, image_size)) { 4557b6d330cSSandrine Bailleux WARN("Failed to reserve region [base = %p, size = 0x%zx]\n", 4567b6d330cSSandrine Bailleux (void *) image_base, image_size); 4579d72b4eaSJames Morrissey dump_load_info(image_base, image_size, mem_layout); 4584112bfa0SVikram Kanigiri io_result = -ENOMEM; 4594112bfa0SVikram Kanigiri goto exit; 4604f6ad66aSAchin Gupta } 4614f6ad66aSAchin Gupta 4624f6ad66aSAchin Gupta /* We have enough space so load the image now */ 4639d72b4eaSJames Morrissey /* TODO: Consider whether to try to recover/retry a partially successful read */ 464625de1d4SDan Handley io_result = io_read(image_handle, image_base, image_size, &bytes_read); 46578460a05SJuan Castillo if ((io_result != 0) || (bytes_read < image_size)) { 46616948ae1SJuan Castillo WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 4674112bfa0SVikram Kanigiri goto exit; 4684f6ad66aSAchin Gupta } 4694f6ad66aSAchin Gupta 470a6b995fbSSandrine Bailleux image_data->image_base = image_base; 471a6b995fbSSandrine Bailleux image_data->image_size = image_size; 472a6b995fbSSandrine Bailleux 4738f55dfb4SSandrine Bailleux /* 4748f55dfb4SSandrine Bailleux * Update the memory usage info. 4758f55dfb4SSandrine Bailleux * This is done after the actual loading so that it is not updated when 4768f55dfb4SSandrine Bailleux * the load is unsuccessful. 477c5fb47c3SJuan Castillo * If the caller does not provide an entry point, bypass the memory 478c5fb47c3SJuan Castillo * reservation. 4798f55dfb4SSandrine Bailleux */ 480c5fb47c3SJuan Castillo if (entry_point_info != NULL) { 4818f55dfb4SSandrine Bailleux reserve_mem(&mem_layout->free_base, &mem_layout->free_size, 4828f55dfb4SSandrine Bailleux image_base, image_size); 483a6b995fbSSandrine Bailleux entry_point_info->pc = image_base; 484c5fb47c3SJuan Castillo } else { 4857b6d330cSSandrine Bailleux INFO("Skip reserving region [base = %p, size = 0x%zx]\n", 4867b6d330cSSandrine Bailleux (void *) image_base, image_size); 487c5fb47c3SJuan Castillo } 4888f55dfb4SSandrine Bailleux 489ad4494dcSDan Handley #if !TRUSTED_BOARD_BOOT 4904f6ad66aSAchin Gupta /* 4918f55dfb4SSandrine Bailleux * File has been successfully loaded. 492ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 493ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 494ad4494dcSDan Handley * When TBB is enabled the image is flushed later, after image 495ad4494dcSDan Handley * authentication. 4964f6ad66aSAchin Gupta */ 4979d72b4eaSJames Morrissey flush_dcache_range(image_base, image_size); 498ad4494dcSDan Handley #endif /* TRUSTED_BOARD_BOOT */ 4994f6ad66aSAchin Gupta 5007b6d330cSSandrine Bailleux INFO("Image id=%u loaded at address %p, size = 0x%zx\n", image_id, 5017b6d330cSSandrine Bailleux (void *) image_base, image_size); 5029d72b4eaSJames Morrissey 5039d72b4eaSJames Morrissey exit: 5044112bfa0SVikram Kanigiri io_close(image_handle); 5059d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'close' */ 5069d72b4eaSJames Morrissey 5079d72b4eaSJames Morrissey /* TODO: Consider maintaining open device connection from this bootloader stage */ 5084112bfa0SVikram Kanigiri io_dev_close(dev_handle); 5099d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'dev_close' */ 5104f6ad66aSAchin Gupta 5114112bfa0SVikram Kanigiri return io_result; 5124f6ad66aSAchin Gupta } 5131779ba6bSJuan Castillo 5140f325c67SAntonio Nino Diaz static int load_auth_image_internal(meminfo_t *mem_layout, 5151779ba6bSJuan Castillo unsigned int image_id, 5161779ba6bSJuan Castillo uintptr_t image_base, 5171779ba6bSJuan Castillo image_info_t *image_data, 5180f325c67SAntonio Nino Diaz entry_point_info_t *entry_point_info, 5190f325c67SAntonio Nino Diaz int is_parent_image) 5201779ba6bSJuan Castillo { 5211779ba6bSJuan Castillo int rc; 5221779ba6bSJuan Castillo 5231779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 5241779ba6bSJuan Castillo unsigned int parent_id; 5251779ba6bSJuan Castillo 5261779ba6bSJuan Castillo /* Use recursion to authenticate parent images */ 5271779ba6bSJuan Castillo rc = auth_mod_get_parent_id(image_id, &parent_id); 5281779ba6bSJuan Castillo if (rc == 0) { 5290f325c67SAntonio Nino Diaz rc = load_auth_image_internal(mem_layout, parent_id, image_base, 5300f325c67SAntonio Nino Diaz image_data, NULL, 1); 53178460a05SJuan Castillo if (rc != 0) { 5321779ba6bSJuan Castillo return rc; 5331779ba6bSJuan Castillo } 5341779ba6bSJuan Castillo } 5351779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 5361779ba6bSJuan Castillo 5371779ba6bSJuan Castillo /* Load the image */ 5381779ba6bSJuan Castillo rc = load_image(mem_layout, image_id, image_base, image_data, 5391779ba6bSJuan Castillo entry_point_info); 54078460a05SJuan Castillo if (rc != 0) { 54178460a05SJuan Castillo return rc; 5421779ba6bSJuan Castillo } 5431779ba6bSJuan Castillo 5441779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 5451779ba6bSJuan Castillo /* Authenticate it */ 5461779ba6bSJuan Castillo rc = auth_mod_verify_img(image_id, 5471779ba6bSJuan Castillo (void *)image_data->image_base, 5481779ba6bSJuan Castillo image_data->image_size); 5491779ba6bSJuan Castillo if (rc != 0) { 5500f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 551308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 552fedbc049SJuan Castillo image_data->image_size); 553fedbc049SJuan Castillo flush_dcache_range(image_data->image_base, 554fedbc049SJuan Castillo image_data->image_size); 55578460a05SJuan Castillo return -EAUTH; 5561779ba6bSJuan Castillo } 557ad4494dcSDan Handley /* 558ad4494dcSDan Handley * File has been successfully loaded and authenticated. 559ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 560ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 5610f325c67SAntonio Nino Diaz * Do it only for child images, not for the parents (certificates). 562ad4494dcSDan Handley */ 5630f325c67SAntonio Nino Diaz if (!is_parent_image) { 5640f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 5650f325c67SAntonio Nino Diaz image_data->image_size); 5660f325c67SAntonio Nino Diaz } 5671779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 5681779ba6bSJuan Castillo 56978460a05SJuan Castillo return 0; 5701779ba6bSJuan Castillo } 57168a68c92SSandrine Bailleux 5720f325c67SAntonio Nino Diaz /******************************************************************************* 5730f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 5740f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 5750f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 5760f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 5770f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 5780f325c67SAntonio Nino Diaz ******************************************************************************/ 5790f325c67SAntonio Nino Diaz int load_auth_image(meminfo_t *mem_layout, 5800f325c67SAntonio Nino Diaz unsigned int image_id, 5810f325c67SAntonio Nino Diaz uintptr_t image_base, 5820f325c67SAntonio Nino Diaz image_info_t *image_data, 5830f325c67SAntonio Nino Diaz entry_point_info_t *entry_point_info) 5840f325c67SAntonio Nino Diaz { 58501f62b6dSRoberto Vargas int err; 58601f62b6dSRoberto Vargas 58701f62b6dSRoberto Vargas do { 58801f62b6dSRoberto Vargas err = load_auth_image_internal(mem_layout, image_id, image_base, 5890f325c67SAntonio Nino Diaz image_data, entry_point_info, 0); 59001f62b6dSRoberto Vargas } while (err != 0 && plat_try_next_boot_source()); 59101f62b6dSRoberto Vargas 59201f62b6dSRoberto Vargas return err; 5930f325c67SAntonio Nino Diaz } 5940f325c67SAntonio Nino Diaz 59572600226SYatharth Kochar #endif /* LOAD_IMAGE_V2 */ 59672600226SYatharth Kochar 59768a68c92SSandrine Bailleux /******************************************************************************* 59868a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 59968a68c92SSandrine Bailleux ******************************************************************************/ 60068a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 60168a68c92SSandrine Bailleux { 6024c0d0390SSoby Mathew INFO("Entry point address = %p\n", (void *)ep_info->pc); 6034c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 60468a68c92SSandrine Bailleux 60568a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 60668a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 60768a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 60868a68c92SSandrine Bailleux 60968a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 61068a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 61168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 61268a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 61351c79b73SSoby Mathew #ifndef AARCH32 61468a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 61568a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 61668a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 61768a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 61851c79b73SSoby Mathew #endif 61968a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 62068a68c92SSandrine Bailleux } 621