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 564c0d0390SSoby Mathew static inline unsigned int is_page_aligned (uintptr_t addr) { 574c0d0390SSoby Mathew return (addr & (PAGE_SIZE - 1)) == 0; 584f6ad66aSAchin Gupta } 594f6ad66aSAchin Gupta 608f55dfb4SSandrine Bailleux /****************************************************************************** 618f55dfb4SSandrine Bailleux * Determine whether the memory region delimited by 'addr' and 'size' is free, 628f55dfb4SSandrine Bailleux * given the extents of free memory. 637b6d330cSSandrine Bailleux * Return 1 if it is free, 0 if it is not free or if the input values are 647b6d330cSSandrine Bailleux * invalid. 658f55dfb4SSandrine Bailleux *****************************************************************************/ 664c0d0390SSoby Mathew static int is_mem_free(uintptr_t free_base, size_t free_size, 674c0d0390SSoby Mathew uintptr_t addr, size_t size) 684f6ad66aSAchin Gupta { 697b6d330cSSandrine Bailleux uintptr_t free_end, requested_end; 707b6d330cSSandrine Bailleux 717b6d330cSSandrine Bailleux /* 727b6d330cSSandrine Bailleux * Handle corner cases first. 737b6d330cSSandrine Bailleux * 747b6d330cSSandrine Bailleux * The order of the 2 tests is important, because if there's no space 757b6d330cSSandrine Bailleux * left (i.e. free_size == 0) but we don't ask for any memory 767b6d330cSSandrine Bailleux * (i.e. size == 0) then we should report that the memory is free. 777b6d330cSSandrine Bailleux */ 787b6d330cSSandrine Bailleux if (size == 0) 797b6d330cSSandrine Bailleux return 1; /* A zero-byte region is always free */ 807b6d330cSSandrine Bailleux if (free_size == 0) 817b6d330cSSandrine Bailleux return 0; 827b6d330cSSandrine Bailleux 837b6d330cSSandrine Bailleux /* 847b6d330cSSandrine Bailleux * Check that the end addresses don't overflow. 857b6d330cSSandrine Bailleux * If they do, consider that this memory region is not free, as this 867b6d330cSSandrine Bailleux * is an invalid scenario. 877b6d330cSSandrine Bailleux */ 887b6d330cSSandrine Bailleux if (check_uptr_overflow(free_base, free_size - 1)) 897b6d330cSSandrine Bailleux return 0; 907b6d330cSSandrine Bailleux free_end = free_base + (free_size - 1); 917b6d330cSSandrine Bailleux 927b6d330cSSandrine Bailleux if (check_uptr_overflow(addr, size - 1)) 937b6d330cSSandrine Bailleux return 0; 947b6d330cSSandrine Bailleux requested_end = addr + (size - 1); 957b6d330cSSandrine Bailleux 967b6d330cSSandrine Bailleux /* 977b6d330cSSandrine Bailleux * Finally, check that the requested memory region lies within the free 987b6d330cSSandrine Bailleux * region. 997b6d330cSSandrine Bailleux */ 1007b6d330cSSandrine Bailleux return (addr >= free_base) && (requested_end <= free_end); 1014f6ad66aSAchin Gupta } 1024f6ad66aSAchin Gupta 1038f55dfb4SSandrine Bailleux /****************************************************************************** 1048f55dfb4SSandrine Bailleux * Inside a given memory region, determine whether a sub-region of memory is 1058f55dfb4SSandrine Bailleux * closer from the top or the bottom of the encompassing region. Return the 1068f55dfb4SSandrine Bailleux * size of the smallest chunk of free memory surrounding the sub-region in 1078f55dfb4SSandrine Bailleux * 'small_chunk_size'. 1088f55dfb4SSandrine Bailleux *****************************************************************************/ 1094c0d0390SSoby Mathew static unsigned int choose_mem_pos(uintptr_t mem_start, uintptr_t mem_end, 1104c0d0390SSoby Mathew uintptr_t submem_start, uintptr_t submem_end, 1118f55dfb4SSandrine Bailleux size_t *small_chunk_size) 1128f55dfb4SSandrine Bailleux { 1138f55dfb4SSandrine Bailleux size_t top_chunk_size, bottom_chunk_size; 1144f6ad66aSAchin Gupta 1158f55dfb4SSandrine Bailleux assert(mem_start <= submem_start); 1168f55dfb4SSandrine Bailleux assert(submem_start <= submem_end); 1178f55dfb4SSandrine Bailleux assert(submem_end <= mem_end); 1188f55dfb4SSandrine Bailleux assert(small_chunk_size != NULL); 1198f55dfb4SSandrine Bailleux 1208f55dfb4SSandrine Bailleux top_chunk_size = mem_end - submem_end; 1218f55dfb4SSandrine Bailleux bottom_chunk_size = submem_start - mem_start; 1228f55dfb4SSandrine Bailleux 1238f55dfb4SSandrine Bailleux if (top_chunk_size < bottom_chunk_size) { 1248f55dfb4SSandrine Bailleux *small_chunk_size = top_chunk_size; 1258f55dfb4SSandrine Bailleux return TOP; 1268f55dfb4SSandrine Bailleux } else { 1278f55dfb4SSandrine Bailleux *small_chunk_size = bottom_chunk_size; 1288f55dfb4SSandrine Bailleux return BOTTOM; 1298f55dfb4SSandrine Bailleux } 1308f55dfb4SSandrine Bailleux } 1318f55dfb4SSandrine Bailleux 1328f55dfb4SSandrine Bailleux /****************************************************************************** 1338f55dfb4SSandrine Bailleux * Reserve the memory region delimited by 'addr' and 'size'. The extents of free 1348f55dfb4SSandrine Bailleux * memory are passed in 'free_base' and 'free_size' and they will be updated to 1358f55dfb4SSandrine Bailleux * reflect the memory usage. 1367b6d330cSSandrine Bailleux * The caller must ensure the memory to reserve is free and that the addresses 1377b6d330cSSandrine Bailleux * and sizes passed in arguments are sane. 1388f55dfb4SSandrine Bailleux *****************************************************************************/ 1394c0d0390SSoby Mathew void reserve_mem(uintptr_t *free_base, size_t *free_size, 1404c0d0390SSoby Mathew uintptr_t addr, size_t size) 1418f55dfb4SSandrine Bailleux { 1428f55dfb4SSandrine Bailleux size_t discard_size; 1438f55dfb4SSandrine Bailleux size_t reserved_size; 1448f55dfb4SSandrine Bailleux unsigned int pos; 1458f55dfb4SSandrine Bailleux 1468f55dfb4SSandrine Bailleux assert(free_base != NULL); 1478f55dfb4SSandrine Bailleux assert(free_size != NULL); 1488f55dfb4SSandrine Bailleux assert(is_mem_free(*free_base, *free_size, addr, size)); 1498f55dfb4SSandrine Bailleux 1507b6d330cSSandrine Bailleux if (size == 0) { 1517b6d330cSSandrine Bailleux WARN("Nothing to allocate, requested size is zero\n"); 1527b6d330cSSandrine Bailleux return; 1537b6d330cSSandrine Bailleux } 1547b6d330cSSandrine Bailleux 1557b6d330cSSandrine Bailleux pos = choose_mem_pos(*free_base, *free_base + (*free_size - 1), 1567b6d330cSSandrine Bailleux addr, addr + (size - 1), 1578f55dfb4SSandrine Bailleux &discard_size); 1588f55dfb4SSandrine Bailleux 1598f55dfb4SSandrine Bailleux reserved_size = size + discard_size; 1608f55dfb4SSandrine Bailleux *free_size -= reserved_size; 1618f55dfb4SSandrine Bailleux 1628f55dfb4SSandrine Bailleux if (pos == BOTTOM) 1638f55dfb4SSandrine Bailleux *free_base = addr + size; 1648f55dfb4SSandrine Bailleux 1654c0d0390SSoby Mathew VERBOSE("Reserved 0x%zx bytes (discarded 0x%zx bytes %s)\n", 1668f55dfb4SSandrine Bailleux reserved_size, discard_size, 1678f55dfb4SSandrine Bailleux pos == TOP ? "above" : "below"); 1684f6ad66aSAchin Gupta } 1694f6ad66aSAchin Gupta 1704c0d0390SSoby Mathew static void dump_load_info(uintptr_t image_load_addr, 1714c0d0390SSoby Mathew size_t image_size, 172fb037bfbSDan Handley const meminfo_t *mem_layout) 1734f6ad66aSAchin Gupta { 1744c0d0390SSoby Mathew INFO("Trying to load image at address %p, size = 0x%zx\n", 1754c0d0390SSoby Mathew (void *)image_load_addr, image_size); 1766ad2e461SDan Handley INFO("Current memory layout:\n"); 1777b6d330cSSandrine Bailleux INFO(" total region = [base = %p, size = 0x%zx]\n", 1787b6d330cSSandrine Bailleux (void *) mem_layout->total_base, mem_layout->total_size); 1797b6d330cSSandrine Bailleux INFO(" free region = [base = %p, size = 0x%zx]\n", 1807b6d330cSSandrine Bailleux (void *) mem_layout->free_base, mem_layout->free_size); 1814f6ad66aSAchin Gupta } 1824f6ad66aSAchin Gupta 183ee9ad785SRyan Harkin /* Generic function to return the size of an image */ 1844c0d0390SSoby Mathew size_t image_size(unsigned int image_id) 185ee9ad785SRyan Harkin { 186625de1d4SDan Handley uintptr_t dev_handle; 187625de1d4SDan Handley uintptr_t image_handle; 188625de1d4SDan Handley uintptr_t image_spec; 189ee9ad785SRyan Harkin size_t image_size = 0; 190e098e244SJuan Castillo int io_result; 191ee9ad785SRyan Harkin 192ee9ad785SRyan Harkin /* Obtain a reference to the image by querying the platform layer */ 19316948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 194e098e244SJuan Castillo if (io_result != 0) { 19516948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 19616948ae1SJuan Castillo image_id, io_result); 197ee9ad785SRyan Harkin return 0; 198ee9ad785SRyan Harkin } 199ee9ad785SRyan Harkin 200ee9ad785SRyan Harkin /* Attempt to access the image */ 201ee9ad785SRyan Harkin io_result = io_open(dev_handle, image_spec, &image_handle); 202e098e244SJuan Castillo if (io_result != 0) { 20316948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 20416948ae1SJuan Castillo image_id, io_result); 205ee9ad785SRyan Harkin return 0; 206ee9ad785SRyan Harkin } 207ee9ad785SRyan Harkin 208ee9ad785SRyan Harkin /* Find the size of the image */ 209ee9ad785SRyan Harkin io_result = io_size(image_handle, &image_size); 210e098e244SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 21116948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 21216948ae1SJuan Castillo image_id, io_result); 213ee9ad785SRyan Harkin } 214ee9ad785SRyan Harkin io_result = io_close(image_handle); 215ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'close' */ 216ee9ad785SRyan Harkin 217ee9ad785SRyan Harkin /* TODO: Consider maintaining open device connection from this 218ee9ad785SRyan Harkin * bootloader stage 219ee9ad785SRyan Harkin */ 220ee9ad785SRyan Harkin io_result = io_dev_close(dev_handle); 221ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'dev_close' */ 222ee9ad785SRyan Harkin 223ee9ad785SRyan Harkin return image_size; 224ee9ad785SRyan Harkin } 2258f55dfb4SSandrine Bailleux 2264f6ad66aSAchin Gupta /******************************************************************************* 227a6b995fbSSandrine Bailleux * Generic function to load an image at a specific address given an image ID and 228a6b995fbSSandrine Bailleux * extents of free memory. 229a6b995fbSSandrine Bailleux * 230a6b995fbSSandrine Bailleux * If the load is successful then the image information is updated. 231a6b995fbSSandrine Bailleux * 232a6b995fbSSandrine Bailleux * If the entry_point_info argument is not NULL then this function also updates: 233a6b995fbSSandrine Bailleux * - the memory layout to mark the memory as reserved; 234a6b995fbSSandrine Bailleux * - the entry point information. 235a6b995fbSSandrine Bailleux * 236a6b995fbSSandrine Bailleux * The caller might pass a NULL pointer for the entry point if they are not 237a6b995fbSSandrine Bailleux * interested in this information. This is typically the case for non-executable 238a6b995fbSSandrine Bailleux * images (e.g. certificates) and executable images that won't ever be executed 239a6b995fbSSandrine Bailleux * on the application processor (e.g. additional microcontroller firmware). 240a6b995fbSSandrine Bailleux * 2418f55dfb4SSandrine Bailleux * Returns 0 on success, a negative error code otherwise. 2424f6ad66aSAchin Gupta ******************************************************************************/ 2434112bfa0SVikram Kanigiri int load_image(meminfo_t *mem_layout, 24416948ae1SJuan Castillo unsigned int image_id, 2451779ba6bSJuan Castillo uintptr_t image_base, 2464112bfa0SVikram Kanigiri image_info_t *image_data, 2474112bfa0SVikram Kanigiri entry_point_info_t *entry_point_info) 2484f6ad66aSAchin Gupta { 249625de1d4SDan Handley uintptr_t dev_handle; 250625de1d4SDan Handley uintptr_t image_handle; 251625de1d4SDan Handley uintptr_t image_spec; 2528f55dfb4SSandrine Bailleux size_t image_size; 2538f55dfb4SSandrine Bailleux size_t bytes_read; 25478460a05SJuan Castillo int io_result; 2554f6ad66aSAchin Gupta 2569d72b4eaSJames Morrissey assert(mem_layout != NULL); 2578f55dfb4SSandrine Bailleux assert(image_data != NULL); 2584112bfa0SVikram Kanigiri assert(image_data->h.version >= VERSION_1); 2599d72b4eaSJames Morrissey 2609d72b4eaSJames Morrissey /* Obtain a reference to the image by querying the platform layer */ 26116948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 26278460a05SJuan Castillo if (io_result != 0) { 26316948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 26416948ae1SJuan Castillo image_id, io_result); 2654112bfa0SVikram Kanigiri return io_result; 2664f6ad66aSAchin Gupta } 2674f6ad66aSAchin Gupta 2689d72b4eaSJames Morrissey /* Attempt to access the image */ 2699d72b4eaSJames Morrissey io_result = io_open(dev_handle, image_spec, &image_handle); 27078460a05SJuan Castillo if (io_result != 0) { 27116948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 27216948ae1SJuan Castillo image_id, io_result); 2734112bfa0SVikram Kanigiri return io_result; 2744f6ad66aSAchin Gupta } 2754f6ad66aSAchin Gupta 276f0dd061aSAntonio Nino Diaz INFO("Loading image id=%u at address %p\n", image_id, 277f0dd061aSAntonio Nino Diaz (void *) image_base); 2788f55dfb4SSandrine Bailleux 2799d72b4eaSJames Morrissey /* Find the size of the image */ 2809d72b4eaSJames Morrissey io_result = io_size(image_handle, &image_size); 28178460a05SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 28216948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 28316948ae1SJuan Castillo image_id, io_result); 2844112bfa0SVikram Kanigiri goto exit; 2859d72b4eaSJames Morrissey } 2869d72b4eaSJames Morrissey 2878f55dfb4SSandrine Bailleux /* Check that the memory where the image will be loaded is free */ 2888f55dfb4SSandrine Bailleux if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, 2898f55dfb4SSandrine Bailleux image_base, image_size)) { 2907b6d330cSSandrine Bailleux WARN("Failed to reserve region [base = %p, size = 0x%zx]\n", 2917b6d330cSSandrine Bailleux (void *) image_base, image_size); 2929d72b4eaSJames Morrissey dump_load_info(image_base, image_size, mem_layout); 2934112bfa0SVikram Kanigiri io_result = -ENOMEM; 2944112bfa0SVikram Kanigiri goto exit; 2954f6ad66aSAchin Gupta } 2964f6ad66aSAchin Gupta 2974f6ad66aSAchin Gupta /* We have enough space so load the image now */ 2989d72b4eaSJames Morrissey /* TODO: Consider whether to try to recover/retry a partially successful read */ 299625de1d4SDan Handley io_result = io_read(image_handle, image_base, image_size, &bytes_read); 30078460a05SJuan Castillo if ((io_result != 0) || (bytes_read < image_size)) { 30116948ae1SJuan Castillo WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 3024112bfa0SVikram Kanigiri goto exit; 3034f6ad66aSAchin Gupta } 3044f6ad66aSAchin Gupta 305a6b995fbSSandrine Bailleux image_data->image_base = image_base; 306a6b995fbSSandrine Bailleux image_data->image_size = image_size; 307a6b995fbSSandrine Bailleux 3088f55dfb4SSandrine Bailleux /* 3098f55dfb4SSandrine Bailleux * Update the memory usage info. 3108f55dfb4SSandrine Bailleux * This is done after the actual loading so that it is not updated when 3118f55dfb4SSandrine Bailleux * the load is unsuccessful. 312c5fb47c3SJuan Castillo * If the caller does not provide an entry point, bypass the memory 313c5fb47c3SJuan Castillo * reservation. 3148f55dfb4SSandrine Bailleux */ 315c5fb47c3SJuan Castillo if (entry_point_info != NULL) { 3168f55dfb4SSandrine Bailleux reserve_mem(&mem_layout->free_base, &mem_layout->free_size, 3178f55dfb4SSandrine Bailleux image_base, image_size); 318a6b995fbSSandrine Bailleux entry_point_info->pc = image_base; 319c5fb47c3SJuan Castillo } else { 3207b6d330cSSandrine Bailleux INFO("Skip reserving region [base = %p, size = 0x%zx]\n", 3217b6d330cSSandrine Bailleux (void *) image_base, image_size); 322c5fb47c3SJuan Castillo } 3238f55dfb4SSandrine Bailleux 324*ad4494dcSDan Handley #if !TRUSTED_BOARD_BOOT 3254f6ad66aSAchin Gupta /* 3268f55dfb4SSandrine Bailleux * File has been successfully loaded. 327*ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 328*ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 329*ad4494dcSDan Handley * When TBB is enabled the image is flushed later, after image 330*ad4494dcSDan Handley * authentication. 3314f6ad66aSAchin Gupta */ 3329d72b4eaSJames Morrissey flush_dcache_range(image_base, image_size); 333*ad4494dcSDan Handley #endif /* TRUSTED_BOARD_BOOT */ 3344f6ad66aSAchin Gupta 3357b6d330cSSandrine Bailleux INFO("Image id=%u loaded at address %p, size = 0x%zx\n", image_id, 3367b6d330cSSandrine Bailleux (void *) image_base, image_size); 3379d72b4eaSJames Morrissey 3389d72b4eaSJames Morrissey exit: 3394112bfa0SVikram Kanigiri io_close(image_handle); 3409d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'close' */ 3419d72b4eaSJames Morrissey 3429d72b4eaSJames Morrissey /* TODO: Consider maintaining open device connection from this bootloader stage */ 3434112bfa0SVikram Kanigiri io_dev_close(dev_handle); 3449d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'dev_close' */ 3454f6ad66aSAchin Gupta 3464112bfa0SVikram Kanigiri return io_result; 3474f6ad66aSAchin Gupta } 3481779ba6bSJuan Castillo 3491779ba6bSJuan Castillo /******************************************************************************* 3501779ba6bSJuan Castillo * Generic function to load and authenticate an image. The image is actually 3511779ba6bSJuan Castillo * loaded by calling the 'load_image()' function. In addition, this function 3521779ba6bSJuan Castillo * uses recursion to authenticate the parent images up to the root of trust. 3531779ba6bSJuan Castillo ******************************************************************************/ 3541779ba6bSJuan Castillo int load_auth_image(meminfo_t *mem_layout, 3551779ba6bSJuan Castillo unsigned int image_id, 3561779ba6bSJuan Castillo uintptr_t image_base, 3571779ba6bSJuan Castillo image_info_t *image_data, 3581779ba6bSJuan Castillo entry_point_info_t *entry_point_info) 3591779ba6bSJuan Castillo { 3601779ba6bSJuan Castillo int rc; 3611779ba6bSJuan Castillo 3621779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 3631779ba6bSJuan Castillo unsigned int parent_id; 3641779ba6bSJuan Castillo 3651779ba6bSJuan Castillo /* Use recursion to authenticate parent images */ 3661779ba6bSJuan Castillo rc = auth_mod_get_parent_id(image_id, &parent_id); 3671779ba6bSJuan Castillo if (rc == 0) { 3681779ba6bSJuan Castillo rc = load_auth_image(mem_layout, parent_id, image_base, 3691779ba6bSJuan Castillo image_data, NULL); 37078460a05SJuan Castillo if (rc != 0) { 3711779ba6bSJuan Castillo return rc; 3721779ba6bSJuan Castillo } 3731779ba6bSJuan Castillo } 3741779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 3751779ba6bSJuan Castillo 3761779ba6bSJuan Castillo /* Load the image */ 3771779ba6bSJuan Castillo rc = load_image(mem_layout, image_id, image_base, image_data, 3781779ba6bSJuan Castillo entry_point_info); 37978460a05SJuan Castillo if (rc != 0) { 38078460a05SJuan Castillo return rc; 3811779ba6bSJuan Castillo } 3821779ba6bSJuan Castillo 3831779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 3841779ba6bSJuan Castillo /* Authenticate it */ 3851779ba6bSJuan Castillo rc = auth_mod_verify_img(image_id, 3861779ba6bSJuan Castillo (void *)image_data->image_base, 3871779ba6bSJuan Castillo image_data->image_size); 3881779ba6bSJuan Castillo if (rc != 0) { 389fedbc049SJuan Castillo memset((void *)image_data->image_base, 0x00, 390fedbc049SJuan Castillo image_data->image_size); 391fedbc049SJuan Castillo flush_dcache_range(image_data->image_base, 392fedbc049SJuan Castillo image_data->image_size); 39378460a05SJuan Castillo return -EAUTH; 3941779ba6bSJuan Castillo } 395*ad4494dcSDan Handley /* 396*ad4494dcSDan Handley * File has been successfully loaded and authenticated. 397*ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 398*ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 399*ad4494dcSDan Handley */ 400*ad4494dcSDan Handley flush_dcache_range(image_data->image_base, image_data->image_size); 4011779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 4021779ba6bSJuan Castillo 40378460a05SJuan Castillo return 0; 4041779ba6bSJuan Castillo } 40568a68c92SSandrine Bailleux 40668a68c92SSandrine Bailleux /******************************************************************************* 40768a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 40868a68c92SSandrine Bailleux ******************************************************************************/ 40968a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 41068a68c92SSandrine Bailleux { 4114c0d0390SSoby Mathew INFO("Entry point address = %p\n", (void *)ep_info->pc); 4124c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 41368a68c92SSandrine Bailleux 41468a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 41568a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 41668a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 41768a68c92SSandrine Bailleux 41868a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 41968a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 42068a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 42168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 42268a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 42368a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 42468a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 42568a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 42668a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 42768a68c92SSandrine Bailleux } 428