14f6ad66aSAchin Gupta /* 2e83b0cadSDan Handley * Copyright (c) 2013-2014, 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> 344f6ad66aSAchin Gupta #include <bl_common.h> 3535e98e55SDan Handley #include <debug.h> 36*8f55dfb4SSandrine Bailleux #include <errno.h> 3797043ac9SDan Handley #include <io_storage.h> 3897043ac9SDan Handley #include <platform.h> 394f6ad66aSAchin Gupta 404f6ad66aSAchin Gupta unsigned long page_align(unsigned long value, unsigned dir) 414f6ad66aSAchin Gupta { 424f6ad66aSAchin Gupta unsigned long page_size = 1 << FOUR_KB_SHIFT; 434f6ad66aSAchin Gupta 444f6ad66aSAchin Gupta /* Round up the limit to the next page boundary */ 454f6ad66aSAchin Gupta if (value & (page_size - 1)) { 464f6ad66aSAchin Gupta value &= ~(page_size - 1); 474f6ad66aSAchin Gupta if (dir == UP) 484f6ad66aSAchin Gupta value += page_size; 494f6ad66aSAchin Gupta } 504f6ad66aSAchin Gupta 514f6ad66aSAchin Gupta return value; 524f6ad66aSAchin Gupta } 534f6ad66aSAchin Gupta 544f6ad66aSAchin Gupta static inline unsigned int is_page_aligned (unsigned long addr) { 554f6ad66aSAchin Gupta const unsigned long page_size = 1 << FOUR_KB_SHIFT; 564f6ad66aSAchin Gupta 574f6ad66aSAchin Gupta return (addr & (page_size - 1)) == 0; 584f6ad66aSAchin Gupta } 594f6ad66aSAchin Gupta 604f6ad66aSAchin Gupta void change_security_state(unsigned int target_security_state) 614f6ad66aSAchin Gupta { 624f6ad66aSAchin Gupta unsigned long scr = read_scr(); 634f6ad66aSAchin Gupta 644f6ad66aSAchin Gupta if (target_security_state == SECURE) 654f6ad66aSAchin Gupta scr &= ~SCR_NS_BIT; 664f6ad66aSAchin Gupta else if (target_security_state == NON_SECURE) 674f6ad66aSAchin Gupta scr |= SCR_NS_BIT; 684f6ad66aSAchin Gupta else 694f6ad66aSAchin Gupta assert(0); 704f6ad66aSAchin Gupta 714f6ad66aSAchin Gupta write_scr(scr); 724f6ad66aSAchin Gupta } 734f6ad66aSAchin Gupta 74*8f55dfb4SSandrine Bailleux /****************************************************************************** 75*8f55dfb4SSandrine Bailleux * Determine whether the memory region delimited by 'addr' and 'size' is free, 76*8f55dfb4SSandrine Bailleux * given the extents of free memory. 77*8f55dfb4SSandrine Bailleux * Return 1 if it is free, 0 otherwise. 78*8f55dfb4SSandrine Bailleux *****************************************************************************/ 79*8f55dfb4SSandrine Bailleux static int is_mem_free(uint64_t free_base, size_t free_size, 80*8f55dfb4SSandrine Bailleux uint64_t addr, size_t size) 814f6ad66aSAchin Gupta { 82*8f55dfb4SSandrine Bailleux return (addr >= free_base) && (addr + size <= free_base + free_size); 834f6ad66aSAchin Gupta } 844f6ad66aSAchin Gupta 85*8f55dfb4SSandrine Bailleux /****************************************************************************** 86*8f55dfb4SSandrine Bailleux * Inside a given memory region, determine whether a sub-region of memory is 87*8f55dfb4SSandrine Bailleux * closer from the top or the bottom of the encompassing region. Return the 88*8f55dfb4SSandrine Bailleux * size of the smallest chunk of free memory surrounding the sub-region in 89*8f55dfb4SSandrine Bailleux * 'small_chunk_size'. 90*8f55dfb4SSandrine Bailleux *****************************************************************************/ 91*8f55dfb4SSandrine Bailleux static unsigned int choose_mem_pos(uint64_t mem_start, uint64_t mem_end, 92*8f55dfb4SSandrine Bailleux uint64_t submem_start, uint64_t submem_end, 93*8f55dfb4SSandrine Bailleux size_t *small_chunk_size) 94*8f55dfb4SSandrine Bailleux { 95*8f55dfb4SSandrine Bailleux size_t top_chunk_size, bottom_chunk_size; 964f6ad66aSAchin Gupta 97*8f55dfb4SSandrine Bailleux assert(mem_start <= submem_start); 98*8f55dfb4SSandrine Bailleux assert(submem_start <= submem_end); 99*8f55dfb4SSandrine Bailleux assert(submem_end <= mem_end); 100*8f55dfb4SSandrine Bailleux assert(small_chunk_size != NULL); 101*8f55dfb4SSandrine Bailleux 102*8f55dfb4SSandrine Bailleux top_chunk_size = mem_end - submem_end; 103*8f55dfb4SSandrine Bailleux bottom_chunk_size = submem_start - mem_start; 104*8f55dfb4SSandrine Bailleux 105*8f55dfb4SSandrine Bailleux if (top_chunk_size < bottom_chunk_size) { 106*8f55dfb4SSandrine Bailleux *small_chunk_size = top_chunk_size; 107*8f55dfb4SSandrine Bailleux return TOP; 108*8f55dfb4SSandrine Bailleux } else { 109*8f55dfb4SSandrine Bailleux *small_chunk_size = bottom_chunk_size; 110*8f55dfb4SSandrine Bailleux return BOTTOM; 111*8f55dfb4SSandrine Bailleux } 112*8f55dfb4SSandrine Bailleux } 113*8f55dfb4SSandrine Bailleux 114*8f55dfb4SSandrine Bailleux /****************************************************************************** 115*8f55dfb4SSandrine Bailleux * Reserve the memory region delimited by 'addr' and 'size'. The extents of free 116*8f55dfb4SSandrine Bailleux * memory are passed in 'free_base' and 'free_size' and they will be updated to 117*8f55dfb4SSandrine Bailleux * reflect the memory usage. 118*8f55dfb4SSandrine Bailleux * The caller must ensure the memory to reserve is free. 119*8f55dfb4SSandrine Bailleux *****************************************************************************/ 120*8f55dfb4SSandrine Bailleux void reserve_mem(uint64_t *free_base, size_t *free_size, 121*8f55dfb4SSandrine Bailleux uint64_t addr, size_t size) 122*8f55dfb4SSandrine Bailleux { 123*8f55dfb4SSandrine Bailleux size_t discard_size; 124*8f55dfb4SSandrine Bailleux size_t reserved_size; 125*8f55dfb4SSandrine Bailleux unsigned int pos; 126*8f55dfb4SSandrine Bailleux 127*8f55dfb4SSandrine Bailleux assert(free_base != NULL); 128*8f55dfb4SSandrine Bailleux assert(free_size != NULL); 129*8f55dfb4SSandrine Bailleux assert(is_mem_free(*free_base, *free_size, addr, size)); 130*8f55dfb4SSandrine Bailleux 131*8f55dfb4SSandrine Bailleux pos = choose_mem_pos(*free_base, *free_base + *free_size, 132*8f55dfb4SSandrine Bailleux addr, addr + size, 133*8f55dfb4SSandrine Bailleux &discard_size); 134*8f55dfb4SSandrine Bailleux 135*8f55dfb4SSandrine Bailleux reserved_size = size + discard_size; 136*8f55dfb4SSandrine Bailleux *free_size -= reserved_size; 137*8f55dfb4SSandrine Bailleux 138*8f55dfb4SSandrine Bailleux if (pos == BOTTOM) 139*8f55dfb4SSandrine Bailleux *free_base = addr + size; 140*8f55dfb4SSandrine Bailleux 141*8f55dfb4SSandrine Bailleux INFO("Reserved %u bytes (discarded %u bytes %s)\n", 142*8f55dfb4SSandrine Bailleux reserved_size, discard_size, 143*8f55dfb4SSandrine Bailleux pos == TOP ? "above" : "below"); 1444f6ad66aSAchin Gupta } 1454f6ad66aSAchin Gupta 1464f6ad66aSAchin Gupta static void dump_load_info(unsigned long image_load_addr, 1474f6ad66aSAchin Gupta unsigned long image_size, 148fb037bfbSDan Handley const meminfo_t *mem_layout) 1494f6ad66aSAchin Gupta { 1504f6ad66aSAchin Gupta #if DEBUG 1514f6ad66aSAchin Gupta printf("Trying to load image at address 0x%lx, size = 0x%lx\r\n", 1524f6ad66aSAchin Gupta image_load_addr, image_size); 1534f6ad66aSAchin Gupta printf("Current memory layout:\r\n"); 1544f6ad66aSAchin Gupta printf(" total region = [0x%lx, 0x%lx]\r\n", mem_layout->total_base, 1554f6ad66aSAchin Gupta mem_layout->total_base + mem_layout->total_size); 1564f6ad66aSAchin Gupta printf(" free region = [0x%lx, 0x%lx]\r\n", mem_layout->free_base, 1574f6ad66aSAchin Gupta mem_layout->free_base + mem_layout->free_size); 1584f6ad66aSAchin Gupta #endif 1594f6ad66aSAchin Gupta } 1604f6ad66aSAchin Gupta 161ee9ad785SRyan Harkin /* Generic function to return the size of an image */ 162ee9ad785SRyan Harkin unsigned long image_size(const char *image_name) 163ee9ad785SRyan Harkin { 164625de1d4SDan Handley uintptr_t dev_handle; 165625de1d4SDan Handley uintptr_t image_handle; 166625de1d4SDan Handley uintptr_t image_spec; 167ee9ad785SRyan Harkin size_t image_size = 0; 168ee9ad785SRyan Harkin int io_result = IO_FAIL; 169ee9ad785SRyan Harkin 170ee9ad785SRyan Harkin assert(image_name != NULL); 171ee9ad785SRyan Harkin 172ee9ad785SRyan Harkin /* Obtain a reference to the image by querying the platform layer */ 173ee9ad785SRyan Harkin io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); 174ee9ad785SRyan Harkin if (io_result != IO_SUCCESS) { 175ee9ad785SRyan Harkin WARN("Failed to obtain reference to image '%s' (%i)\n", 176ee9ad785SRyan Harkin image_name, io_result); 177ee9ad785SRyan Harkin return 0; 178ee9ad785SRyan Harkin } 179ee9ad785SRyan Harkin 180ee9ad785SRyan Harkin /* Attempt to access the image */ 181ee9ad785SRyan Harkin io_result = io_open(dev_handle, image_spec, &image_handle); 182ee9ad785SRyan Harkin if (io_result != IO_SUCCESS) { 183ee9ad785SRyan Harkin WARN("Failed to access image '%s' (%i)\n", 184ee9ad785SRyan Harkin image_name, io_result); 185ee9ad785SRyan Harkin return 0; 186ee9ad785SRyan Harkin } 187ee9ad785SRyan Harkin 188ee9ad785SRyan Harkin /* Find the size of the image */ 189ee9ad785SRyan Harkin io_result = io_size(image_handle, &image_size); 190ee9ad785SRyan Harkin if ((io_result != IO_SUCCESS) || (image_size == 0)) { 191ee9ad785SRyan Harkin WARN("Failed to determine the size of the image '%s' file (%i)\n", 192ee9ad785SRyan Harkin image_name, io_result); 193ee9ad785SRyan Harkin } 194ee9ad785SRyan Harkin io_result = io_close(image_handle); 195ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'close' */ 196ee9ad785SRyan Harkin 197ee9ad785SRyan Harkin /* TODO: Consider maintaining open device connection from this 198ee9ad785SRyan Harkin * bootloader stage 199ee9ad785SRyan Harkin */ 200ee9ad785SRyan Harkin io_result = io_dev_close(dev_handle); 201ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'dev_close' */ 202ee9ad785SRyan Harkin 203ee9ad785SRyan Harkin return image_size; 204ee9ad785SRyan Harkin } 205*8f55dfb4SSandrine Bailleux 2064f6ad66aSAchin Gupta /******************************************************************************* 207*8f55dfb4SSandrine Bailleux * Generic function to load an image at a specific address given a name and 208*8f55dfb4SSandrine Bailleux * extents of free memory. It updates the memory layout if the load is 209*8f55dfb4SSandrine Bailleux * successful, as well as the image information and the entry point information. 210*8f55dfb4SSandrine Bailleux * The caller might pass a NULL pointer for the entry point if it is not 211*8f55dfb4SSandrine Bailleux * interested in this information, e.g. because the image just needs to be 212*8f55dfb4SSandrine Bailleux * loaded in memory but won't ever be executed. 213*8f55dfb4SSandrine Bailleux * Returns 0 on success, a negative error code otherwise. 2144f6ad66aSAchin Gupta ******************************************************************************/ 2154112bfa0SVikram Kanigiri int load_image(meminfo_t *mem_layout, 2164f6ad66aSAchin Gupta const char *image_name, 217*8f55dfb4SSandrine Bailleux uint64_t image_base, 2184112bfa0SVikram Kanigiri image_info_t *image_data, 2194112bfa0SVikram Kanigiri entry_point_info_t *entry_point_info) 2204f6ad66aSAchin Gupta { 221625de1d4SDan Handley uintptr_t dev_handle; 222625de1d4SDan Handley uintptr_t image_handle; 223625de1d4SDan Handley uintptr_t image_spec; 224*8f55dfb4SSandrine Bailleux size_t image_size; 225*8f55dfb4SSandrine Bailleux size_t bytes_read; 2269d72b4eaSJames Morrissey int io_result = IO_FAIL; 2274f6ad66aSAchin Gupta 2289d72b4eaSJames Morrissey assert(mem_layout != NULL); 2299d72b4eaSJames Morrissey assert(image_name != NULL); 230*8f55dfb4SSandrine Bailleux assert(image_data != NULL); 2314112bfa0SVikram Kanigiri assert(image_data->h.version >= VERSION_1); 2329d72b4eaSJames Morrissey 2339d72b4eaSJames Morrissey /* Obtain a reference to the image by querying the platform layer */ 2349d72b4eaSJames Morrissey io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); 2359d72b4eaSJames Morrissey if (io_result != IO_SUCCESS) { 23608c28d53SJeenu Viswambharan WARN("Failed to obtain reference to image '%s' (%i)\n", 2379d72b4eaSJames Morrissey image_name, io_result); 2384112bfa0SVikram Kanigiri return io_result; 2394f6ad66aSAchin Gupta } 2404f6ad66aSAchin Gupta 2419d72b4eaSJames Morrissey /* Attempt to access the image */ 2429d72b4eaSJames Morrissey io_result = io_open(dev_handle, image_spec, &image_handle); 2439d72b4eaSJames Morrissey if (io_result != IO_SUCCESS) { 24408c28d53SJeenu Viswambharan WARN("Failed to access image '%s' (%i)\n", 2459d72b4eaSJames Morrissey image_name, io_result); 2464112bfa0SVikram Kanigiri return io_result; 2474f6ad66aSAchin Gupta } 2484f6ad66aSAchin Gupta 249*8f55dfb4SSandrine Bailleux INFO("Loading file '%s' at address 0x%lx\n", image_name, image_base); 250*8f55dfb4SSandrine Bailleux 2519d72b4eaSJames Morrissey /* Find the size of the image */ 2529d72b4eaSJames Morrissey io_result = io_size(image_handle, &image_size); 2539d72b4eaSJames Morrissey if ((io_result != IO_SUCCESS) || (image_size == 0)) { 25408c28d53SJeenu Viswambharan WARN("Failed to determine the size of the image '%s' file (%i)\n", 2559d72b4eaSJames Morrissey image_name, io_result); 2564112bfa0SVikram Kanigiri goto exit; 2579d72b4eaSJames Morrissey } 2589d72b4eaSJames Morrissey 259*8f55dfb4SSandrine Bailleux /* Check that the memory where the image will be loaded is free */ 260*8f55dfb4SSandrine Bailleux if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, 261*8f55dfb4SSandrine Bailleux image_base, image_size)) { 262*8f55dfb4SSandrine Bailleux WARN("Failed to reserve memory: 0x%lx - 0x%lx\n", 263*8f55dfb4SSandrine Bailleux image_base, image_base + image_size); 2649d72b4eaSJames Morrissey dump_load_info(image_base, image_size, mem_layout); 2654112bfa0SVikram Kanigiri io_result = -ENOMEM; 2664112bfa0SVikram Kanigiri goto exit; 2674f6ad66aSAchin Gupta } 2684f6ad66aSAchin Gupta 2694f6ad66aSAchin Gupta /* We have enough space so load the image now */ 2709d72b4eaSJames Morrissey /* TODO: Consider whether to try to recover/retry a partially successful read */ 271625de1d4SDan Handley io_result = io_read(image_handle, image_base, image_size, &bytes_read); 2729d72b4eaSJames Morrissey if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { 27308c28d53SJeenu Viswambharan WARN("Failed to load '%s' file (%i)\n", image_name, io_result); 2744112bfa0SVikram Kanigiri goto exit; 2754f6ad66aSAchin Gupta } 2764f6ad66aSAchin Gupta 277*8f55dfb4SSandrine Bailleux /* 278*8f55dfb4SSandrine Bailleux * Update the memory usage info. 279*8f55dfb4SSandrine Bailleux * This is done after the actual loading so that it is not updated when 280*8f55dfb4SSandrine Bailleux * the load is unsuccessful. 281*8f55dfb4SSandrine Bailleux */ 282*8f55dfb4SSandrine Bailleux reserve_mem(&mem_layout->free_base, &mem_layout->free_size, 283*8f55dfb4SSandrine Bailleux image_base, image_size); 284*8f55dfb4SSandrine Bailleux 2854112bfa0SVikram Kanigiri image_data->image_base = image_base; 2864112bfa0SVikram Kanigiri image_data->image_size = image_size; 2874112bfa0SVikram Kanigiri 28863db7ba2SSandrine Bailleux if (entry_point_info != NULL) 2894112bfa0SVikram Kanigiri entry_point_info->pc = image_base; 2904112bfa0SVikram Kanigiri 2914f6ad66aSAchin Gupta /* 292*8f55dfb4SSandrine Bailleux * File has been successfully loaded. 293*8f55dfb4SSandrine Bailleux * Flush the image in TZRAM so that the next EL can see it. 2944f6ad66aSAchin Gupta */ 2959d72b4eaSJames Morrissey flush_dcache_range(image_base, image_size); 2964f6ad66aSAchin Gupta 297*8f55dfb4SSandrine Bailleux INFO("File '%s' loaded: 0x%lx - 0x%lx\n", image_name, image_base, 298*8f55dfb4SSandrine Bailleux image_base + image_size); 2999d72b4eaSJames Morrissey 3009d72b4eaSJames Morrissey exit: 3014112bfa0SVikram Kanigiri io_close(image_handle); 3029d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'close' */ 3039d72b4eaSJames Morrissey 3049d72b4eaSJames Morrissey /* TODO: Consider maintaining open device connection from this bootloader stage */ 3054112bfa0SVikram Kanigiri io_dev_close(dev_handle); 3069d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'dev_close' */ 3074f6ad66aSAchin Gupta 3084112bfa0SVikram Kanigiri return io_result; 3094f6ad66aSAchin Gupta } 310