14f6ad66aSAchin Gupta /* 24c0d0390SSoby Mathew * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. 34f6ad66aSAchin Gupta * 44f6ad66aSAchin Gupta * Redistribution and use in source and binary forms, with or without 54f6ad66aSAchin Gupta * modification, are permitted provided that the following conditions are met: 64f6ad66aSAchin Gupta * 74f6ad66aSAchin Gupta * Redistributions of source code must retain the above copyright notice, this 84f6ad66aSAchin Gupta * list of conditions and the following disclaimer. 94f6ad66aSAchin Gupta * 104f6ad66aSAchin Gupta * Redistributions in binary form must reproduce the above copyright notice, 114f6ad66aSAchin Gupta * this list of conditions and the following disclaimer in the documentation 124f6ad66aSAchin Gupta * and/or other materials provided with the distribution. 134f6ad66aSAchin Gupta * 144f6ad66aSAchin Gupta * Neither the name of ARM nor the names of its contributors may be used 154f6ad66aSAchin Gupta * to endorse or promote products derived from this software without specific 164f6ad66aSAchin Gupta * prior written permission. 174f6ad66aSAchin Gupta * 184f6ad66aSAchin Gupta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 194f6ad66aSAchin Gupta * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 204f6ad66aSAchin Gupta * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 214f6ad66aSAchin Gupta * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 224f6ad66aSAchin Gupta * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 234f6ad66aSAchin Gupta * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 244f6ad66aSAchin Gupta * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 254f6ad66aSAchin Gupta * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 264f6ad66aSAchin Gupta * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 274f6ad66aSAchin Gupta * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 284f6ad66aSAchin Gupta * POSSIBILITY OF SUCH DAMAGE. 294f6ad66aSAchin Gupta */ 304f6ad66aSAchin Gupta 3197043ac9SDan Handley #include <arch.h> 324f6ad66aSAchin Gupta #include <arch_helpers.h> 3397043ac9SDan Handley #include <assert.h> 341779ba6bSJuan Castillo #include <auth_mod.h> 354f6ad66aSAchin Gupta #include <bl_common.h> 3635e98e55SDan Handley #include <debug.h> 378f55dfb4SSandrine Bailleux #include <errno.h> 3897043ac9SDan Handley #include <io_storage.h> 3997043ac9SDan Handley #include <platform.h> 40fedbc049SJuan Castillo #include <string.h> 417b6d330cSSandrine Bailleux #include <utils.h> 423ca9928dSSoby Mathew #include <xlat_tables.h> 434f6ad66aSAchin Gupta 444c0d0390SSoby Mathew uintptr_t page_align(uintptr_t value, unsigned dir) 454f6ad66aSAchin Gupta { 464f6ad66aSAchin Gupta /* Round up the limit to the next page boundary */ 474c0d0390SSoby Mathew if (value & (PAGE_SIZE - 1)) { 484c0d0390SSoby Mathew value &= ~(PAGE_SIZE - 1); 494f6ad66aSAchin Gupta if (dir == UP) 504c0d0390SSoby Mathew value += PAGE_SIZE; 514f6ad66aSAchin Gupta } 524f6ad66aSAchin Gupta 534f6ad66aSAchin Gupta return value; 544f6ad66aSAchin Gupta } 554f6ad66aSAchin Gupta 5672600226SYatharth Kochar #if !LOAD_IMAGE_V2 578f55dfb4SSandrine Bailleux /****************************************************************************** 588f55dfb4SSandrine Bailleux * Determine whether the memory region delimited by 'addr' and 'size' is free, 598f55dfb4SSandrine Bailleux * given the extents of free memory. 607b6d330cSSandrine Bailleux * Return 1 if it is free, 0 if it is not free or if the input values are 617b6d330cSSandrine Bailleux * invalid. 628f55dfb4SSandrine Bailleux *****************************************************************************/ 634c0d0390SSoby Mathew static int is_mem_free(uintptr_t free_base, size_t free_size, 644c0d0390SSoby Mathew uintptr_t addr, size_t size) 654f6ad66aSAchin Gupta { 667b6d330cSSandrine Bailleux uintptr_t free_end, requested_end; 677b6d330cSSandrine Bailleux 687b6d330cSSandrine Bailleux /* 697b6d330cSSandrine Bailleux * Handle corner cases first. 707b6d330cSSandrine Bailleux * 717b6d330cSSandrine Bailleux * The order of the 2 tests is important, because if there's no space 727b6d330cSSandrine Bailleux * left (i.e. free_size == 0) but we don't ask for any memory 737b6d330cSSandrine Bailleux * (i.e. size == 0) then we should report that the memory is free. 747b6d330cSSandrine Bailleux */ 757b6d330cSSandrine Bailleux if (size == 0) 767b6d330cSSandrine Bailleux return 1; /* A zero-byte region is always free */ 777b6d330cSSandrine Bailleux if (free_size == 0) 787b6d330cSSandrine Bailleux return 0; 797b6d330cSSandrine Bailleux 807b6d330cSSandrine Bailleux /* 817b6d330cSSandrine Bailleux * Check that the end addresses don't overflow. 827b6d330cSSandrine Bailleux * If they do, consider that this memory region is not free, as this 837b6d330cSSandrine Bailleux * is an invalid scenario. 847b6d330cSSandrine Bailleux */ 857b6d330cSSandrine Bailleux if (check_uptr_overflow(free_base, free_size - 1)) 867b6d330cSSandrine Bailleux return 0; 877b6d330cSSandrine Bailleux free_end = free_base + (free_size - 1); 887b6d330cSSandrine Bailleux 897b6d330cSSandrine Bailleux if (check_uptr_overflow(addr, size - 1)) 907b6d330cSSandrine Bailleux return 0; 917b6d330cSSandrine Bailleux requested_end = addr + (size - 1); 927b6d330cSSandrine Bailleux 937b6d330cSSandrine Bailleux /* 947b6d330cSSandrine Bailleux * Finally, check that the requested memory region lies within the free 957b6d330cSSandrine Bailleux * region. 967b6d330cSSandrine Bailleux */ 977b6d330cSSandrine Bailleux return (addr >= free_base) && (requested_end <= free_end); 984f6ad66aSAchin Gupta } 994f6ad66aSAchin Gupta 1008f55dfb4SSandrine Bailleux /****************************************************************************** 1018f55dfb4SSandrine Bailleux * Inside a given memory region, determine whether a sub-region of memory is 1028f55dfb4SSandrine Bailleux * closer from the top or the bottom of the encompassing region. Return the 1038f55dfb4SSandrine Bailleux * size of the smallest chunk of free memory surrounding the sub-region in 1048f55dfb4SSandrine Bailleux * 'small_chunk_size'. 1058f55dfb4SSandrine Bailleux *****************************************************************************/ 1064c0d0390SSoby Mathew static unsigned int choose_mem_pos(uintptr_t mem_start, uintptr_t mem_end, 1074c0d0390SSoby Mathew uintptr_t submem_start, uintptr_t submem_end, 1088f55dfb4SSandrine Bailleux size_t *small_chunk_size) 1098f55dfb4SSandrine Bailleux { 1108f55dfb4SSandrine Bailleux size_t top_chunk_size, bottom_chunk_size; 1114f6ad66aSAchin Gupta 1128f55dfb4SSandrine Bailleux assert(mem_start <= submem_start); 1138f55dfb4SSandrine Bailleux assert(submem_start <= submem_end); 1148f55dfb4SSandrine Bailleux assert(submem_end <= mem_end); 1158f55dfb4SSandrine Bailleux assert(small_chunk_size != NULL); 1168f55dfb4SSandrine Bailleux 1178f55dfb4SSandrine Bailleux top_chunk_size = mem_end - submem_end; 1188f55dfb4SSandrine Bailleux bottom_chunk_size = submem_start - mem_start; 1198f55dfb4SSandrine Bailleux 1208f55dfb4SSandrine Bailleux if (top_chunk_size < bottom_chunk_size) { 1218f55dfb4SSandrine Bailleux *small_chunk_size = top_chunk_size; 1228f55dfb4SSandrine Bailleux return TOP; 1238f55dfb4SSandrine Bailleux } else { 1248f55dfb4SSandrine Bailleux *small_chunk_size = bottom_chunk_size; 1258f55dfb4SSandrine Bailleux return BOTTOM; 1268f55dfb4SSandrine Bailleux } 1278f55dfb4SSandrine Bailleux } 1288f55dfb4SSandrine Bailleux 1298f55dfb4SSandrine Bailleux /****************************************************************************** 1308f55dfb4SSandrine Bailleux * Reserve the memory region delimited by 'addr' and 'size'. The extents of free 1318f55dfb4SSandrine Bailleux * memory are passed in 'free_base' and 'free_size' and they will be updated to 1328f55dfb4SSandrine Bailleux * reflect the memory usage. 1337b6d330cSSandrine Bailleux * The caller must ensure the memory to reserve is free and that the addresses 1347b6d330cSSandrine Bailleux * and sizes passed in arguments are sane. 1358f55dfb4SSandrine Bailleux *****************************************************************************/ 1364c0d0390SSoby Mathew void reserve_mem(uintptr_t *free_base, size_t *free_size, 1374c0d0390SSoby Mathew uintptr_t addr, size_t size) 1388f55dfb4SSandrine Bailleux { 1398f55dfb4SSandrine Bailleux size_t discard_size; 1408f55dfb4SSandrine Bailleux size_t reserved_size; 1418f55dfb4SSandrine Bailleux unsigned int pos; 1428f55dfb4SSandrine Bailleux 1438f55dfb4SSandrine Bailleux assert(free_base != NULL); 1448f55dfb4SSandrine Bailleux assert(free_size != NULL); 1458f55dfb4SSandrine Bailleux assert(is_mem_free(*free_base, *free_size, addr, size)); 1468f55dfb4SSandrine Bailleux 1477b6d330cSSandrine Bailleux if (size == 0) { 1487b6d330cSSandrine Bailleux WARN("Nothing to allocate, requested size is zero\n"); 1497b6d330cSSandrine Bailleux return; 1507b6d330cSSandrine Bailleux } 1517b6d330cSSandrine Bailleux 1527b6d330cSSandrine Bailleux pos = choose_mem_pos(*free_base, *free_base + (*free_size - 1), 1537b6d330cSSandrine Bailleux addr, addr + (size - 1), 1548f55dfb4SSandrine Bailleux &discard_size); 1558f55dfb4SSandrine Bailleux 1568f55dfb4SSandrine Bailleux reserved_size = size + discard_size; 1578f55dfb4SSandrine Bailleux *free_size -= reserved_size; 1588f55dfb4SSandrine Bailleux 1598f55dfb4SSandrine Bailleux if (pos == BOTTOM) 1608f55dfb4SSandrine Bailleux *free_base = addr + size; 1618f55dfb4SSandrine Bailleux 1624c0d0390SSoby Mathew VERBOSE("Reserved 0x%zx bytes (discarded 0x%zx bytes %s)\n", 1638f55dfb4SSandrine Bailleux reserved_size, discard_size, 1648f55dfb4SSandrine Bailleux pos == TOP ? "above" : "below"); 1654f6ad66aSAchin Gupta } 1664f6ad66aSAchin Gupta 1674c0d0390SSoby Mathew static void dump_load_info(uintptr_t image_load_addr, 1684c0d0390SSoby Mathew size_t image_size, 169fb037bfbSDan Handley const meminfo_t *mem_layout) 1704f6ad66aSAchin Gupta { 1714c0d0390SSoby Mathew INFO("Trying to load image at address %p, size = 0x%zx\n", 1724c0d0390SSoby Mathew (void *)image_load_addr, image_size); 1736ad2e461SDan Handley INFO("Current memory layout:\n"); 1747b6d330cSSandrine Bailleux INFO(" total region = [base = %p, size = 0x%zx]\n", 1757b6d330cSSandrine Bailleux (void *) mem_layout->total_base, mem_layout->total_size); 1767b6d330cSSandrine Bailleux INFO(" free region = [base = %p, size = 0x%zx]\n", 1777b6d330cSSandrine Bailleux (void *) mem_layout->free_base, mem_layout->free_size); 1784f6ad66aSAchin Gupta } 17972600226SYatharth Kochar #endif /* LOAD_IMAGE_V2 */ 1804f6ad66aSAchin Gupta 181ee9ad785SRyan Harkin /* Generic function to return the size of an image */ 1824c0d0390SSoby Mathew size_t image_size(unsigned int image_id) 183ee9ad785SRyan Harkin { 184625de1d4SDan Handley uintptr_t dev_handle; 185625de1d4SDan Handley uintptr_t image_handle; 186625de1d4SDan Handley uintptr_t image_spec; 187ee9ad785SRyan Harkin size_t image_size = 0; 188e098e244SJuan Castillo int io_result; 189ee9ad785SRyan Harkin 190ee9ad785SRyan Harkin /* Obtain a reference to the image by querying the platform layer */ 19116948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 192e098e244SJuan Castillo if (io_result != 0) { 19316948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 19416948ae1SJuan Castillo image_id, io_result); 195ee9ad785SRyan Harkin return 0; 196ee9ad785SRyan Harkin } 197ee9ad785SRyan Harkin 198ee9ad785SRyan Harkin /* Attempt to access the image */ 199ee9ad785SRyan Harkin io_result = io_open(dev_handle, image_spec, &image_handle); 200e098e244SJuan Castillo if (io_result != 0) { 20116948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 20216948ae1SJuan Castillo image_id, io_result); 203ee9ad785SRyan Harkin return 0; 204ee9ad785SRyan Harkin } 205ee9ad785SRyan Harkin 206ee9ad785SRyan Harkin /* Find the size of the image */ 207ee9ad785SRyan Harkin io_result = io_size(image_handle, &image_size); 208e098e244SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 20916948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 21016948ae1SJuan Castillo image_id, io_result); 211ee9ad785SRyan Harkin } 212ee9ad785SRyan Harkin io_result = io_close(image_handle); 213ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'close' */ 214ee9ad785SRyan Harkin 215ee9ad785SRyan Harkin /* TODO: Consider maintaining open device connection from this 216ee9ad785SRyan Harkin * bootloader stage 217ee9ad785SRyan Harkin */ 218ee9ad785SRyan Harkin io_result = io_dev_close(dev_handle); 219ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'dev_close' */ 220ee9ad785SRyan Harkin 221ee9ad785SRyan Harkin return image_size; 222ee9ad785SRyan Harkin } 2238f55dfb4SSandrine Bailleux 22472600226SYatharth Kochar #if LOAD_IMAGE_V2 22572600226SYatharth Kochar 22672600226SYatharth Kochar /******************************************************************************* 22772600226SYatharth Kochar * Generic function to load an image at a specific address given 22872600226SYatharth Kochar * an image ID and extents of free memory. 22972600226SYatharth Kochar * 23072600226SYatharth Kochar * If the load is successful then the image information is updated. 23172600226SYatharth Kochar * 23272600226SYatharth Kochar * Returns 0 on success, a negative error code otherwise. 23372600226SYatharth Kochar ******************************************************************************/ 23472600226SYatharth Kochar int load_image(unsigned int image_id, image_info_t *image_data) 23572600226SYatharth Kochar { 23672600226SYatharth Kochar uintptr_t dev_handle; 23772600226SYatharth Kochar uintptr_t image_handle; 23872600226SYatharth Kochar uintptr_t image_spec; 23972600226SYatharth Kochar uintptr_t image_base; 24072600226SYatharth Kochar size_t image_size; 24172600226SYatharth Kochar size_t bytes_read; 24272600226SYatharth Kochar int io_result; 24372600226SYatharth Kochar 24472600226SYatharth Kochar assert(image_data != NULL); 24572600226SYatharth Kochar assert(image_data->h.version >= VERSION_2); 24672600226SYatharth Kochar 24772600226SYatharth Kochar image_base = image_data->image_base; 24872600226SYatharth Kochar 24972600226SYatharth Kochar /* Obtain a reference to the image by querying the platform layer */ 25072600226SYatharth Kochar io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 25172600226SYatharth Kochar if (io_result != 0) { 25272600226SYatharth Kochar WARN("Failed to obtain reference to image id=%u (%i)\n", 25372600226SYatharth Kochar image_id, io_result); 25472600226SYatharth Kochar return io_result; 25572600226SYatharth Kochar } 25672600226SYatharth Kochar 25772600226SYatharth Kochar /* Attempt to access the image */ 25872600226SYatharth Kochar io_result = io_open(dev_handle, image_spec, &image_handle); 25972600226SYatharth Kochar if (io_result != 0) { 26072600226SYatharth Kochar WARN("Failed to access image id=%u (%i)\n", 26172600226SYatharth Kochar image_id, io_result); 26272600226SYatharth Kochar return io_result; 26372600226SYatharth Kochar } 26472600226SYatharth Kochar 26572600226SYatharth Kochar INFO("Loading image id=%u at address %p\n", image_id, 26672600226SYatharth Kochar (void *) image_base); 26772600226SYatharth Kochar 26872600226SYatharth Kochar /* Find the size of the image */ 26972600226SYatharth Kochar io_result = io_size(image_handle, &image_size); 27072600226SYatharth Kochar if ((io_result != 0) || (image_size == 0)) { 27172600226SYatharth Kochar WARN("Failed to determine the size of the image id=%u (%i)\n", 27272600226SYatharth Kochar image_id, io_result); 27372600226SYatharth Kochar goto exit; 27472600226SYatharth Kochar } 27572600226SYatharth Kochar 27672600226SYatharth Kochar /* Check that the image size to load is within limit */ 27772600226SYatharth Kochar if (image_size > image_data->image_max_size) { 27872600226SYatharth Kochar WARN("Image id=%u size out of bounds\n", image_id); 27972600226SYatharth Kochar io_result = -EFBIG; 28072600226SYatharth Kochar goto exit; 28172600226SYatharth Kochar } 28272600226SYatharth Kochar 28372600226SYatharth Kochar image_data->image_size = image_size; 28472600226SYatharth Kochar 28572600226SYatharth Kochar /* We have enough space so load the image now */ 28672600226SYatharth Kochar /* TODO: Consider whether to try to recover/retry a partially successful read */ 28772600226SYatharth Kochar io_result = io_read(image_handle, image_base, image_size, &bytes_read); 28872600226SYatharth Kochar if ((io_result != 0) || (bytes_read < image_size)) { 28972600226SYatharth Kochar WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 29072600226SYatharth Kochar goto exit; 29172600226SYatharth Kochar } 29272600226SYatharth Kochar 29372600226SYatharth Kochar #if !TRUSTED_BOARD_BOOT 29472600226SYatharth Kochar /* 29572600226SYatharth Kochar * File has been successfully loaded. 29672600226SYatharth Kochar * Flush the image to main memory so that it can be executed later by 29772600226SYatharth Kochar * any CPU, regardless of cache and MMU state. 29872600226SYatharth Kochar * When TBB is enabled the image is flushed later, after image 29972600226SYatharth Kochar * authentication. 30072600226SYatharth Kochar */ 30172600226SYatharth Kochar flush_dcache_range(image_base, image_size); 30272600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 30372600226SYatharth Kochar 30472600226SYatharth Kochar INFO("Image id=%u loaded: %p - %p\n", image_id, (void *) image_base, 30572600226SYatharth Kochar (void *) (image_base + image_size)); 30672600226SYatharth Kochar 30772600226SYatharth Kochar exit: 30872600226SYatharth Kochar io_close(image_handle); 30972600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'close' */ 31072600226SYatharth Kochar 31172600226SYatharth Kochar /* TODO: Consider maintaining open device connection from this bootloader stage */ 31272600226SYatharth Kochar io_dev_close(dev_handle); 31372600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'dev_close' */ 31472600226SYatharth Kochar 31572600226SYatharth Kochar return io_result; 31672600226SYatharth Kochar } 31772600226SYatharth Kochar 318*0f325c67SAntonio Nino Diaz static int load_auth_image_internal(unsigned int image_id, 319*0f325c67SAntonio Nino Diaz image_info_t *image_data, 320*0f325c67SAntonio Nino Diaz int is_parent_image) 32172600226SYatharth Kochar { 32272600226SYatharth Kochar int rc; 32372600226SYatharth Kochar 32472600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 32572600226SYatharth Kochar unsigned int parent_id; 32672600226SYatharth Kochar 32772600226SYatharth Kochar /* Use recursion to authenticate parent images */ 32872600226SYatharth Kochar rc = auth_mod_get_parent_id(image_id, &parent_id); 32972600226SYatharth Kochar if (rc == 0) { 330*0f325c67SAntonio Nino Diaz rc = load_auth_image_internal(parent_id, image_data, 1); 33172600226SYatharth Kochar if (rc != 0) { 33272600226SYatharth Kochar return rc; 33372600226SYatharth Kochar } 33472600226SYatharth Kochar } 33572600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 33672600226SYatharth Kochar 33772600226SYatharth Kochar /* Load the image */ 33872600226SYatharth Kochar rc = load_image(image_id, image_data); 33972600226SYatharth Kochar if (rc != 0) { 34072600226SYatharth Kochar return rc; 34172600226SYatharth Kochar } 34272600226SYatharth Kochar 34372600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 34472600226SYatharth Kochar /* Authenticate it */ 34572600226SYatharth Kochar rc = auth_mod_verify_img(image_id, 34672600226SYatharth Kochar (void *)image_data->image_base, 34772600226SYatharth Kochar image_data->image_size); 34872600226SYatharth Kochar if (rc != 0) { 349*0f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 35072600226SYatharth Kochar memset((void *)image_data->image_base, 0x00, 35172600226SYatharth Kochar image_data->image_size); 35272600226SYatharth Kochar flush_dcache_range(image_data->image_base, 35372600226SYatharth Kochar image_data->image_size); 35472600226SYatharth Kochar return -EAUTH; 35572600226SYatharth Kochar } 35672600226SYatharth Kochar 35772600226SYatharth Kochar /* 35872600226SYatharth Kochar * File has been successfully loaded and authenticated. 35972600226SYatharth Kochar * Flush the image to main memory so that it can be executed later by 36072600226SYatharth Kochar * any CPU, regardless of cache and MMU state. 361*0f325c67SAntonio Nino Diaz * Do it only for child images, not for the parents (certificates). 36272600226SYatharth Kochar */ 363*0f325c67SAntonio Nino Diaz if (!is_parent_image) { 364*0f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 365*0f325c67SAntonio Nino Diaz image_data->image_size); 366*0f325c67SAntonio Nino Diaz } 36772600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 36872600226SYatharth Kochar 36972600226SYatharth Kochar return 0; 37072600226SYatharth Kochar } 37172600226SYatharth Kochar 372*0f325c67SAntonio Nino Diaz /******************************************************************************* 373*0f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 374*0f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 375*0f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 376*0f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 377*0f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 378*0f325c67SAntonio Nino Diaz ******************************************************************************/ 379*0f325c67SAntonio Nino Diaz int load_auth_image(unsigned int image_id, image_info_t *image_data) 380*0f325c67SAntonio Nino Diaz { 381*0f325c67SAntonio Nino Diaz return load_auth_image_internal(image_id, image_data, 0); 382*0f325c67SAntonio Nino Diaz } 383*0f325c67SAntonio Nino Diaz 38472600226SYatharth Kochar #else /* LOAD_IMAGE_V2 */ 38572600226SYatharth Kochar 3864f6ad66aSAchin Gupta /******************************************************************************* 387a6b995fbSSandrine Bailleux * Generic function to load an image at a specific address given an image ID and 388a6b995fbSSandrine Bailleux * extents of free memory. 389a6b995fbSSandrine Bailleux * 390a6b995fbSSandrine Bailleux * If the load is successful then the image information is updated. 391a6b995fbSSandrine Bailleux * 392a6b995fbSSandrine Bailleux * If the entry_point_info argument is not NULL then this function also updates: 393a6b995fbSSandrine Bailleux * - the memory layout to mark the memory as reserved; 394a6b995fbSSandrine Bailleux * - the entry point information. 395a6b995fbSSandrine Bailleux * 396a6b995fbSSandrine Bailleux * The caller might pass a NULL pointer for the entry point if they are not 397a6b995fbSSandrine Bailleux * interested in this information. This is typically the case for non-executable 398a6b995fbSSandrine Bailleux * images (e.g. certificates) and executable images that won't ever be executed 399a6b995fbSSandrine Bailleux * on the application processor (e.g. additional microcontroller firmware). 400a6b995fbSSandrine Bailleux * 4018f55dfb4SSandrine Bailleux * Returns 0 on success, a negative error code otherwise. 4024f6ad66aSAchin Gupta ******************************************************************************/ 4034112bfa0SVikram Kanigiri int load_image(meminfo_t *mem_layout, 40416948ae1SJuan Castillo unsigned int image_id, 4051779ba6bSJuan Castillo uintptr_t image_base, 4064112bfa0SVikram Kanigiri image_info_t *image_data, 4074112bfa0SVikram Kanigiri entry_point_info_t *entry_point_info) 4084f6ad66aSAchin Gupta { 409625de1d4SDan Handley uintptr_t dev_handle; 410625de1d4SDan Handley uintptr_t image_handle; 411625de1d4SDan Handley uintptr_t image_spec; 4128f55dfb4SSandrine Bailleux size_t image_size; 4138f55dfb4SSandrine Bailleux size_t bytes_read; 41478460a05SJuan Castillo int io_result; 4154f6ad66aSAchin Gupta 4169d72b4eaSJames Morrissey assert(mem_layout != NULL); 4178f55dfb4SSandrine Bailleux assert(image_data != NULL); 41872600226SYatharth Kochar assert(image_data->h.version == VERSION_1); 4199d72b4eaSJames Morrissey 4209d72b4eaSJames Morrissey /* Obtain a reference to the image by querying the platform layer */ 42116948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 42278460a05SJuan Castillo if (io_result != 0) { 42316948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 42416948ae1SJuan Castillo image_id, io_result); 4254112bfa0SVikram Kanigiri return io_result; 4264f6ad66aSAchin Gupta } 4274f6ad66aSAchin Gupta 4289d72b4eaSJames Morrissey /* Attempt to access the image */ 4299d72b4eaSJames Morrissey io_result = io_open(dev_handle, image_spec, &image_handle); 43078460a05SJuan Castillo if (io_result != 0) { 43116948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 43216948ae1SJuan Castillo image_id, io_result); 4334112bfa0SVikram Kanigiri return io_result; 4344f6ad66aSAchin Gupta } 4354f6ad66aSAchin Gupta 436f0dd061aSAntonio Nino Diaz INFO("Loading image id=%u at address %p\n", image_id, 437f0dd061aSAntonio Nino Diaz (void *) image_base); 4388f55dfb4SSandrine Bailleux 4399d72b4eaSJames Morrissey /* Find the size of the image */ 4409d72b4eaSJames Morrissey io_result = io_size(image_handle, &image_size); 44178460a05SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 44216948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 44316948ae1SJuan Castillo image_id, io_result); 4444112bfa0SVikram Kanigiri goto exit; 4459d72b4eaSJames Morrissey } 4469d72b4eaSJames Morrissey 4478f55dfb4SSandrine Bailleux /* Check that the memory where the image will be loaded is free */ 4488f55dfb4SSandrine Bailleux if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, 4498f55dfb4SSandrine Bailleux image_base, image_size)) { 4507b6d330cSSandrine Bailleux WARN("Failed to reserve region [base = %p, size = 0x%zx]\n", 4517b6d330cSSandrine Bailleux (void *) image_base, image_size); 4529d72b4eaSJames Morrissey dump_load_info(image_base, image_size, mem_layout); 4534112bfa0SVikram Kanigiri io_result = -ENOMEM; 4544112bfa0SVikram Kanigiri goto exit; 4554f6ad66aSAchin Gupta } 4564f6ad66aSAchin Gupta 4574f6ad66aSAchin Gupta /* We have enough space so load the image now */ 4589d72b4eaSJames Morrissey /* TODO: Consider whether to try to recover/retry a partially successful read */ 459625de1d4SDan Handley io_result = io_read(image_handle, image_base, image_size, &bytes_read); 46078460a05SJuan Castillo if ((io_result != 0) || (bytes_read < image_size)) { 46116948ae1SJuan Castillo WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 4624112bfa0SVikram Kanigiri goto exit; 4634f6ad66aSAchin Gupta } 4644f6ad66aSAchin Gupta 465a6b995fbSSandrine Bailleux image_data->image_base = image_base; 466a6b995fbSSandrine Bailleux image_data->image_size = image_size; 467a6b995fbSSandrine Bailleux 4688f55dfb4SSandrine Bailleux /* 4698f55dfb4SSandrine Bailleux * Update the memory usage info. 4708f55dfb4SSandrine Bailleux * This is done after the actual loading so that it is not updated when 4718f55dfb4SSandrine Bailleux * the load is unsuccessful. 472c5fb47c3SJuan Castillo * If the caller does not provide an entry point, bypass the memory 473c5fb47c3SJuan Castillo * reservation. 4748f55dfb4SSandrine Bailleux */ 475c5fb47c3SJuan Castillo if (entry_point_info != NULL) { 4768f55dfb4SSandrine Bailleux reserve_mem(&mem_layout->free_base, &mem_layout->free_size, 4778f55dfb4SSandrine Bailleux image_base, image_size); 478a6b995fbSSandrine Bailleux entry_point_info->pc = image_base; 479c5fb47c3SJuan Castillo } else { 4807b6d330cSSandrine Bailleux INFO("Skip reserving region [base = %p, size = 0x%zx]\n", 4817b6d330cSSandrine Bailleux (void *) image_base, image_size); 482c5fb47c3SJuan Castillo } 4838f55dfb4SSandrine Bailleux 484ad4494dcSDan Handley #if !TRUSTED_BOARD_BOOT 4854f6ad66aSAchin Gupta /* 4868f55dfb4SSandrine Bailleux * File has been successfully loaded. 487ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 488ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 489ad4494dcSDan Handley * When TBB is enabled the image is flushed later, after image 490ad4494dcSDan Handley * authentication. 4914f6ad66aSAchin Gupta */ 4929d72b4eaSJames Morrissey flush_dcache_range(image_base, image_size); 493ad4494dcSDan Handley #endif /* TRUSTED_BOARD_BOOT */ 4944f6ad66aSAchin Gupta 4957b6d330cSSandrine Bailleux INFO("Image id=%u loaded at address %p, size = 0x%zx\n", image_id, 4967b6d330cSSandrine Bailleux (void *) image_base, image_size); 4979d72b4eaSJames Morrissey 4989d72b4eaSJames Morrissey exit: 4994112bfa0SVikram Kanigiri io_close(image_handle); 5009d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'close' */ 5019d72b4eaSJames Morrissey 5029d72b4eaSJames Morrissey /* TODO: Consider maintaining open device connection from this bootloader stage */ 5034112bfa0SVikram Kanigiri io_dev_close(dev_handle); 5049d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'dev_close' */ 5054f6ad66aSAchin Gupta 5064112bfa0SVikram Kanigiri return io_result; 5074f6ad66aSAchin Gupta } 5081779ba6bSJuan Castillo 509*0f325c67SAntonio Nino Diaz static int load_auth_image_internal(meminfo_t *mem_layout, 5101779ba6bSJuan Castillo unsigned int image_id, 5111779ba6bSJuan Castillo uintptr_t image_base, 5121779ba6bSJuan Castillo image_info_t *image_data, 513*0f325c67SAntonio Nino Diaz entry_point_info_t *entry_point_info, 514*0f325c67SAntonio Nino Diaz int is_parent_image) 5151779ba6bSJuan Castillo { 5161779ba6bSJuan Castillo int rc; 5171779ba6bSJuan Castillo 5181779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 5191779ba6bSJuan Castillo unsigned int parent_id; 5201779ba6bSJuan Castillo 5211779ba6bSJuan Castillo /* Use recursion to authenticate parent images */ 5221779ba6bSJuan Castillo rc = auth_mod_get_parent_id(image_id, &parent_id); 5231779ba6bSJuan Castillo if (rc == 0) { 524*0f325c67SAntonio Nino Diaz rc = load_auth_image_internal(mem_layout, parent_id, image_base, 525*0f325c67SAntonio Nino Diaz image_data, NULL, 1); 52678460a05SJuan Castillo if (rc != 0) { 5271779ba6bSJuan Castillo return rc; 5281779ba6bSJuan Castillo } 5291779ba6bSJuan Castillo } 5301779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 5311779ba6bSJuan Castillo 5321779ba6bSJuan Castillo /* Load the image */ 5331779ba6bSJuan Castillo rc = load_image(mem_layout, image_id, image_base, image_data, 5341779ba6bSJuan Castillo entry_point_info); 53578460a05SJuan Castillo if (rc != 0) { 53678460a05SJuan Castillo return rc; 5371779ba6bSJuan Castillo } 5381779ba6bSJuan Castillo 5391779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 5401779ba6bSJuan Castillo /* Authenticate it */ 5411779ba6bSJuan Castillo rc = auth_mod_verify_img(image_id, 5421779ba6bSJuan Castillo (void *)image_data->image_base, 5431779ba6bSJuan Castillo image_data->image_size); 5441779ba6bSJuan Castillo if (rc != 0) { 545*0f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 546fedbc049SJuan Castillo memset((void *)image_data->image_base, 0x00, 547fedbc049SJuan Castillo image_data->image_size); 548fedbc049SJuan Castillo flush_dcache_range(image_data->image_base, 549fedbc049SJuan Castillo image_data->image_size); 55078460a05SJuan Castillo return -EAUTH; 5511779ba6bSJuan Castillo } 552ad4494dcSDan Handley /* 553ad4494dcSDan Handley * File has been successfully loaded and authenticated. 554ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 555ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 556*0f325c67SAntonio Nino Diaz * Do it only for child images, not for the parents (certificates). 557ad4494dcSDan Handley */ 558*0f325c67SAntonio Nino Diaz if (!is_parent_image) { 559*0f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 560*0f325c67SAntonio Nino Diaz image_data->image_size); 561*0f325c67SAntonio Nino Diaz } 5621779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 5631779ba6bSJuan Castillo 56478460a05SJuan Castillo return 0; 5651779ba6bSJuan Castillo } 56668a68c92SSandrine Bailleux 567*0f325c67SAntonio Nino Diaz /******************************************************************************* 568*0f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 569*0f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 570*0f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 571*0f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 572*0f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 573*0f325c67SAntonio Nino Diaz ******************************************************************************/ 574*0f325c67SAntonio Nino Diaz int load_auth_image(meminfo_t *mem_layout, 575*0f325c67SAntonio Nino Diaz unsigned int image_id, 576*0f325c67SAntonio Nino Diaz uintptr_t image_base, 577*0f325c67SAntonio Nino Diaz image_info_t *image_data, 578*0f325c67SAntonio Nino Diaz entry_point_info_t *entry_point_info) 579*0f325c67SAntonio Nino Diaz { 580*0f325c67SAntonio Nino Diaz return load_auth_image_internal(mem_layout, image_id, image_base, 581*0f325c67SAntonio Nino Diaz image_data, entry_point_info, 0); 582*0f325c67SAntonio Nino Diaz } 583*0f325c67SAntonio Nino Diaz 58472600226SYatharth Kochar #endif /* LOAD_IMAGE_V2 */ 58572600226SYatharth Kochar 58668a68c92SSandrine Bailleux /******************************************************************************* 58768a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 58868a68c92SSandrine Bailleux ******************************************************************************/ 58968a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 59068a68c92SSandrine Bailleux { 5914c0d0390SSoby Mathew INFO("Entry point address = %p\n", (void *)ep_info->pc); 5924c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 59368a68c92SSandrine Bailleux 59468a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 59568a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 59668a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 59768a68c92SSandrine Bailleux 59868a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 59968a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 60068a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 60168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 60251c79b73SSoby Mathew #ifndef AARCH32 60368a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 60468a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 60568a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 60668a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 60751c79b73SSoby Mathew #endif 60868a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 60968a68c92SSandrine Bailleux } 610