14f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta/* 2e83b0cadc67882c1ba7f430d16dab80c9b3a0228Dan Handley * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. 34f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * 44f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * Redistribution and use in source and binary forms, with or without 54f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * modification, are permitted provided that the following conditions are met: 64f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * 74f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * Redistributions of source code must retain the above copyright notice, this 84f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * list of conditions and the following disclaimer. 94f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * 104f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * Redistributions in binary form must reproduce the above copyright notice, 114f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * this list of conditions and the following disclaimer in the documentation 124f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * and/or other materials provided with the distribution. 134f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * 144f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * Neither the name of ARM nor the names of its contributors may be used 154f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * to endorse or promote products derived from this software without specific 164f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * prior written permission. 174f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * 184f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 194f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 204f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 214f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 224f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 234f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 244f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 254f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 264f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 274f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 284f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta * POSSIBILITY OF SUCH DAMAGE. 294f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta */ 304f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 3197043ac98e13a726dbf8b3b41654dca759e3da2cDan Handley#include <arch.h> 324f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta#include <arch_helpers.h> 3397043ac98e13a726dbf8b3b41654dca759e3da2cDan Handley#include <assert.h> 344f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta#include <bl_common.h> 3535e98e5588d09145f7d0d4d98624f6b75321a187Dan Handley#include <debug.h> 368f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux#include <errno.h> 3797043ac98e13a726dbf8b3b41654dca759e3da2cDan Handley#include <io_storage.h> 3897043ac98e13a726dbf8b3b41654dca759e3da2cDan Handley#include <platform.h> 394f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 404f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Guptaunsigned long page_align(unsigned long value, unsigned dir) 414f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta{ 424f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta unsigned long page_size = 1 << FOUR_KB_SHIFT; 434f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 444f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta /* Round up the limit to the next page boundary */ 454f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta if (value & (page_size - 1)) { 464f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta value &= ~(page_size - 1); 474f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta if (dir == UP) 484f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta value += page_size; 494f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta } 504f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 514f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta return value; 524f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta} 534f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 544f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Guptastatic inline unsigned int is_page_aligned (unsigned long addr) { 554f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta const unsigned long page_size = 1 << FOUR_KB_SHIFT; 564f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 574f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta return (addr & (page_size - 1)) == 0; 584f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta} 594f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 604f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Guptavoid change_security_state(unsigned int target_security_state) 614f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta{ 624f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta unsigned long scr = read_scr(); 634f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 64d3280beb700321b0ef47b4f61d84667ba501bc61Juan Castillo assert(sec_state_is_valid(target_security_state)); 654f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta if (target_security_state == SECURE) 664f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta scr &= ~SCR_NS_BIT; 674f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta else 68d3280beb700321b0ef47b4f61d84667ba501bc61Juan Castillo scr |= SCR_NS_BIT; 694f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 704f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta write_scr(scr); 714f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta} 724f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 738f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux/****************************************************************************** 748f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * Determine whether the memory region delimited by 'addr' and 'size' is free, 758f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * given the extents of free memory. 768f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * Return 1 if it is free, 0 otherwise. 778f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux *****************************************************************************/ 788f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleuxstatic int is_mem_free(uint64_t free_base, size_t free_size, 798f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux uint64_t addr, size_t size) 808f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux{ 818f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux return (addr >= free_base) && (addr + size <= free_base + free_size); 828f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux} 834f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 848f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux/****************************************************************************** 858f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * Inside a given memory region, determine whether a sub-region of memory is 868f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * closer from the top or the bottom of the encompassing region. Return the 878f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * size of the smallest chunk of free memory surrounding the sub-region in 888f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * 'small_chunk_size'. 898f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux *****************************************************************************/ 908f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleuxstatic unsigned int choose_mem_pos(uint64_t mem_start, uint64_t mem_end, 918f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux uint64_t submem_start, uint64_t submem_end, 928f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux size_t *small_chunk_size) 934f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta{ 948f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux size_t top_chunk_size, bottom_chunk_size; 954f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 968f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux assert(mem_start <= submem_start); 978f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux assert(submem_start <= submem_end); 988f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux assert(submem_end <= mem_end); 998f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux assert(small_chunk_size != NULL); 1004f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 1018f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux top_chunk_size = mem_end - submem_end; 1028f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux bottom_chunk_size = submem_start - mem_start; 1038f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux 1048f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux if (top_chunk_size < bottom_chunk_size) { 1058f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux *small_chunk_size = top_chunk_size; 1068f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux return TOP; 1074f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta } else { 1088f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux *small_chunk_size = bottom_chunk_size; 1098f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux return BOTTOM; 1104f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta } 1118f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux} 1124f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 1138f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux/****************************************************************************** 1148f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * Reserve the memory region delimited by 'addr' and 'size'. The extents of free 1158f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * memory are passed in 'free_base' and 'free_size' and they will be updated to 1168f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * reflect the memory usage. 1178f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * The caller must ensure the memory to reserve is free. 1188f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux *****************************************************************************/ 1198f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleuxvoid reserve_mem(uint64_t *free_base, size_t *free_size, 1208f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux uint64_t addr, size_t size) 1218f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux{ 1228f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux size_t discard_size; 1238f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux size_t reserved_size; 1248f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux unsigned int pos; 1254f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 1268f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux assert(free_base != NULL); 1278f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux assert(free_size != NULL); 1288f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux assert(is_mem_free(*free_base, *free_size, addr, size)); 1298f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux 1308f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux pos = choose_mem_pos(*free_base, *free_base + *free_size, 1318f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux addr, addr + size, 1328f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux &discard_size); 1338f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux 1348f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux reserved_size = size + discard_size; 1358f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux *free_size -= reserved_size; 1368f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux 1378f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux if (pos == BOTTOM) 1388f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux *free_base = addr + size; 1398f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux 1406ad2e461f0cd6de5aefd89fa0ba7acf2c293b8c2Dan Handley VERBOSE("Reserved %u bytes (discarded %u bytes %s)\n", 1418f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux reserved_size, discard_size, 1428f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux pos == TOP ? "above" : "below"); 1434f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta} 1444f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 1454f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Guptastatic void dump_load_info(unsigned long image_load_addr, 1464f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta unsigned long image_size, 147fb037bfb7cbf7b404c069b4ebac5a10059d948b1Dan Handley const meminfo_t *mem_layout) 1484f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta{ 1496ad2e461f0cd6de5aefd89fa0ba7acf2c293b8c2Dan Handley INFO("Trying to load image at address 0x%lx, size = 0x%lx\n", 1504f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta image_load_addr, image_size); 1516ad2e461f0cd6de5aefd89fa0ba7acf2c293b8c2Dan Handley INFO("Current memory layout:\n"); 1526ad2e461f0cd6de5aefd89fa0ba7acf2c293b8c2Dan Handley INFO(" total region = [0x%lx, 0x%lx]\n", mem_layout->total_base, 1534f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta mem_layout->total_base + mem_layout->total_size); 1546ad2e461f0cd6de5aefd89fa0ba7acf2c293b8c2Dan Handley INFO(" free region = [0x%lx, 0x%lx]\n", mem_layout->free_base, 1554f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta mem_layout->free_base + mem_layout->free_size); 1564f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta} 1574f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 158ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin/* Generic function to return the size of an image */ 159ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkinunsigned long image_size(const char *image_name) 160ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin{ 161625de1d4f04b30383354bee944d0a7ca3dba1e67Dan Handley uintptr_t dev_handle; 162625de1d4f04b30383354bee944d0a7ca3dba1e67Dan Handley uintptr_t image_handle; 163625de1d4f04b30383354bee944d0a7ca3dba1e67Dan Handley uintptr_t image_spec; 164ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin size_t image_size = 0; 165ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin int io_result = IO_FAIL; 166ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin 167ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin assert(image_name != NULL); 168ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin 169ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin /* Obtain a reference to the image by querying the platform layer */ 170ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); 171ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin if (io_result != IO_SUCCESS) { 172ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin WARN("Failed to obtain reference to image '%s' (%i)\n", 173ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin image_name, io_result); 174ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin return 0; 175ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin } 176ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin 177ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin /* Attempt to access the image */ 178ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin io_result = io_open(dev_handle, image_spec, &image_handle); 179ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin if (io_result != IO_SUCCESS) { 180ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin WARN("Failed to access image '%s' (%i)\n", 181ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin image_name, io_result); 182ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin return 0; 183ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin } 184ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin 185ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin /* Find the size of the image */ 186ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin io_result = io_size(image_handle, &image_size); 187ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin if ((io_result != IO_SUCCESS) || (image_size == 0)) { 188ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin WARN("Failed to determine the size of the image '%s' file (%i)\n", 189ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin image_name, io_result); 190ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin } 191ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin io_result = io_close(image_handle); 192ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin /* Ignore improbable/unrecoverable error in 'close' */ 193ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin 194ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin /* TODO: Consider maintaining open device connection from this 195ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin * bootloader stage 196ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin */ 197ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin io_result = io_dev_close(dev_handle); 198ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin /* Ignore improbable/unrecoverable error in 'dev_close' */ 199ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin 200ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin return image_size; 201ee9ad7856c21835c0ad080d1e04d90e8c3535a4cRyan Harkin} 2028f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux 2034f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta/******************************************************************************* 2048f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * Generic function to load an image at a specific address given a name and 2058f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * extents of free memory. It updates the memory layout if the load is 2068f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * successful, as well as the image information and the entry point information. 2078f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * The caller might pass a NULL pointer for the entry point if it is not 2088f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * interested in this information, e.g. because the image just needs to be 2098f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * loaded in memory but won't ever be executed. 2108f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * Returns 0 on success, a negative error code otherwise. 2114f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta ******************************************************************************/ 2124112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiriint load_image(meminfo_t *mem_layout, 2138f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux const char *image_name, 2148f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux uint64_t image_base, 2158f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux image_info_t *image_data, 2168f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux entry_point_info_t *entry_point_info) 2174f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta{ 218625de1d4f04b30383354bee944d0a7ca3dba1e67Dan Handley uintptr_t dev_handle; 219625de1d4f04b30383354bee944d0a7ca3dba1e67Dan Handley uintptr_t image_handle; 220625de1d4f04b30383354bee944d0a7ca3dba1e67Dan Handley uintptr_t image_spec; 2218f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux size_t image_size; 2228f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux size_t bytes_read; 2239d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey int io_result = IO_FAIL; 2249d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey 2259d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey assert(mem_layout != NULL); 2269d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey assert(image_name != NULL); 2278f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux assert(image_data != NULL); 2284112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri assert(image_data->h.version >= VERSION_1); 2299d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey 2309d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey /* Obtain a reference to the image by querying the platform layer */ 2319d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); 2329d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey if (io_result != IO_SUCCESS) { 23308c28d5385f8fae3d5c61475a109b86ef11770d0Jeenu Viswambharan WARN("Failed to obtain reference to image '%s' (%i)\n", 2349d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey image_name, io_result); 2354112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri return io_result; 2369d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey } 2374f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 2389d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey /* Attempt to access the image */ 2399d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey io_result = io_open(dev_handle, image_spec, &image_handle); 2409d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey if (io_result != IO_SUCCESS) { 24108c28d5385f8fae3d5c61475a109b86ef11770d0Jeenu Viswambharan WARN("Failed to access image '%s' (%i)\n", 2429d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey image_name, io_result); 2434112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri return io_result; 2444f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta } 2454f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 2468f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux INFO("Loading file '%s' at address 0x%lx\n", image_name, image_base); 2478f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux 2489d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey /* Find the size of the image */ 2499d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey io_result = io_size(image_handle, &image_size); 2509d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey if ((io_result != IO_SUCCESS) || (image_size == 0)) { 25108c28d5385f8fae3d5c61475a109b86ef11770d0Jeenu Viswambharan WARN("Failed to determine the size of the image '%s' file (%i)\n", 2529d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey image_name, io_result); 2534112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri goto exit; 2549d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey } 2559d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey 2568f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux /* Check that the memory where the image will be loaded is free */ 2578f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, 2588f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux image_base, image_size)) { 2598f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux WARN("Failed to reserve memory: 0x%lx - 0x%lx\n", 2608f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux image_base, image_base + image_size); 2614112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri dump_load_info(image_base, image_size, mem_layout); 2624112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri io_result = -ENOMEM; 2634112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri goto exit; 2644f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta } 2654f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 2664f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta /* We have enough space so load the image now */ 2679d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey /* TODO: Consider whether to try to recover/retry a partially successful read */ 268625de1d4f04b30383354bee944d0a7ca3dba1e67Dan Handley io_result = io_read(image_handle, image_base, image_size, &bytes_read); 2699d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { 27008c28d5385f8fae3d5c61475a109b86ef11770d0Jeenu Viswambharan WARN("Failed to load '%s' file (%i)\n", image_name, io_result); 2714112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri goto exit; 2724f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta } 2734f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 2748f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux /* 2758f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * Update the memory usage info. 2768f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * This is done after the actual loading so that it is not updated when 2778f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * the load is unsuccessful. 278c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo * If the caller does not provide an entry point, bypass the memory 279c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo * reservation. 2808f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux */ 281c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo if (entry_point_info != NULL) { 282c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo reserve_mem(&mem_layout->free_base, &mem_layout->free_size, 283c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo image_base, image_size); 284c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo } else { 285c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo INFO("Skip reserving memory: 0x%lx - 0x%lx\n", 286c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo image_base, image_base + image_size); 287c5fb47c389000c7a5189c0ad28a26bf50bf7e65cJuan Castillo } 2888f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux 2894112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri image_data->image_base = image_base; 2904112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri image_data->image_size = image_size; 2914112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri 29263db7ba2931f477ae09811a650825b44a967ea73Sandrine Bailleux if (entry_point_info != NULL) 29363db7ba2931f477ae09811a650825b44a967ea73Sandrine Bailleux entry_point_info->pc = image_base; 2944112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri 2954f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta /* 2968f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * File has been successfully loaded. 2978f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux * Flush the image in TZRAM so that the next EL can see it. 2984f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta */ 2999d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey flush_dcache_range(image_base, image_size); 3004f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 3018f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux INFO("File '%s' loaded: 0x%lx - 0x%lx\n", image_name, image_base, 3028f55dfb4ba1a7c2cb5af355ff614923b6000864dSandrine Bailleux image_base + image_size); 3039d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey 3049d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrisseyexit: 3054112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri io_close(image_handle); 3069d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey /* Ignore improbable/unrecoverable error in 'close' */ 3079d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey 3089d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey /* TODO: Consider maintaining open device connection from this bootloader stage */ 3094112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri io_dev_close(dev_handle); 3109d72b4ea9c7d9cac386f70d8a6581d4b1a45d7b0James Morrissey /* Ignore improbable/unrecoverable error in 'dev_close' */ 3114f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta 3124112bfa0c223eda73af1cfe57ca7dc926f767dd8Vikram Kanigiri return io_result; 3134f6ad66ae9fcc8bcb3b0fcee10b7ab1ffcaf1a5Achin Gupta} 314