14f6ad66aSAchin Gupta /* 2308d359bSDouglas Raillard * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. 34f6ad66aSAchin Gupta * 4*82cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 54f6ad66aSAchin Gupta */ 64f6ad66aSAchin Gupta 797043ac9SDan Handley #include <arch.h> 84f6ad66aSAchin Gupta #include <arch_helpers.h> 997043ac9SDan Handley #include <assert.h> 101779ba6bSJuan Castillo #include <auth_mod.h> 114f6ad66aSAchin Gupta #include <bl_common.h> 1235e98e55SDan Handley #include <debug.h> 138f55dfb4SSandrine Bailleux #include <errno.h> 1497043ac9SDan Handley #include <io_storage.h> 1597043ac9SDan Handley #include <platform.h> 16fedbc049SJuan Castillo #include <string.h> 177b6d330cSSandrine Bailleux #include <utils.h> 18d50ece03SAntonio Nino Diaz #include <xlat_tables_defs.h> 194f6ad66aSAchin Gupta 204c0d0390SSoby Mathew uintptr_t page_align(uintptr_t value, unsigned dir) 214f6ad66aSAchin Gupta { 224f6ad66aSAchin Gupta /* Round up the limit to the next page boundary */ 234c0d0390SSoby Mathew if (value & (PAGE_SIZE - 1)) { 244c0d0390SSoby Mathew value &= ~(PAGE_SIZE - 1); 254f6ad66aSAchin Gupta if (dir == UP) 264c0d0390SSoby Mathew value += PAGE_SIZE; 274f6ad66aSAchin Gupta } 284f6ad66aSAchin Gupta 294f6ad66aSAchin Gupta return value; 304f6ad66aSAchin Gupta } 314f6ad66aSAchin Gupta 328f55dfb4SSandrine Bailleux /****************************************************************************** 338f55dfb4SSandrine Bailleux * Determine whether the memory region delimited by 'addr' and 'size' is free, 348f55dfb4SSandrine Bailleux * given the extents of free memory. 357b6d330cSSandrine Bailleux * Return 1 if it is free, 0 if it is not free or if the input values are 367b6d330cSSandrine Bailleux * invalid. 378f55dfb4SSandrine Bailleux *****************************************************************************/ 3899c5ebafSSandrine Bailleux int is_mem_free(uintptr_t free_base, size_t free_size, 394c0d0390SSoby Mathew uintptr_t addr, size_t size) 404f6ad66aSAchin Gupta { 417b6d330cSSandrine Bailleux uintptr_t free_end, requested_end; 427b6d330cSSandrine Bailleux 437b6d330cSSandrine Bailleux /* 447b6d330cSSandrine Bailleux * Handle corner cases first. 457b6d330cSSandrine Bailleux * 467b6d330cSSandrine Bailleux * The order of the 2 tests is important, because if there's no space 477b6d330cSSandrine Bailleux * left (i.e. free_size == 0) but we don't ask for any memory 487b6d330cSSandrine Bailleux * (i.e. size == 0) then we should report that the memory is free. 497b6d330cSSandrine Bailleux */ 507b6d330cSSandrine Bailleux if (size == 0) 517b6d330cSSandrine Bailleux return 1; /* A zero-byte region is always free */ 527b6d330cSSandrine Bailleux if (free_size == 0) 537b6d330cSSandrine Bailleux return 0; 547b6d330cSSandrine Bailleux 557b6d330cSSandrine Bailleux /* 567b6d330cSSandrine Bailleux * Check that the end addresses don't overflow. 577b6d330cSSandrine Bailleux * If they do, consider that this memory region is not free, as this 587b6d330cSSandrine Bailleux * is an invalid scenario. 597b6d330cSSandrine Bailleux */ 607b6d330cSSandrine Bailleux if (check_uptr_overflow(free_base, free_size - 1)) 617b6d330cSSandrine Bailleux return 0; 627b6d330cSSandrine Bailleux free_end = free_base + (free_size - 1); 637b6d330cSSandrine Bailleux 647b6d330cSSandrine Bailleux if (check_uptr_overflow(addr, size - 1)) 657b6d330cSSandrine Bailleux return 0; 667b6d330cSSandrine Bailleux requested_end = addr + (size - 1); 677b6d330cSSandrine Bailleux 687b6d330cSSandrine Bailleux /* 697b6d330cSSandrine Bailleux * Finally, check that the requested memory region lies within the free 707b6d330cSSandrine Bailleux * region. 717b6d330cSSandrine Bailleux */ 727b6d330cSSandrine Bailleux return (addr >= free_base) && (requested_end <= free_end); 734f6ad66aSAchin Gupta } 744f6ad66aSAchin Gupta 7599c5ebafSSandrine Bailleux #if !LOAD_IMAGE_V2 768f55dfb4SSandrine Bailleux /****************************************************************************** 778f55dfb4SSandrine Bailleux * Inside a given memory region, determine whether a sub-region of memory is 788f55dfb4SSandrine Bailleux * closer from the top or the bottom of the encompassing region. Return the 798f55dfb4SSandrine Bailleux * size of the smallest chunk of free memory surrounding the sub-region in 808f55dfb4SSandrine Bailleux * 'small_chunk_size'. 818f55dfb4SSandrine Bailleux *****************************************************************************/ 824c0d0390SSoby Mathew static unsigned int choose_mem_pos(uintptr_t mem_start, uintptr_t mem_end, 834c0d0390SSoby Mathew uintptr_t submem_start, uintptr_t submem_end, 848f55dfb4SSandrine Bailleux size_t *small_chunk_size) 858f55dfb4SSandrine Bailleux { 868f55dfb4SSandrine Bailleux size_t top_chunk_size, bottom_chunk_size; 874f6ad66aSAchin Gupta 888f55dfb4SSandrine Bailleux assert(mem_start <= submem_start); 898f55dfb4SSandrine Bailleux assert(submem_start <= submem_end); 908f55dfb4SSandrine Bailleux assert(submem_end <= mem_end); 918f55dfb4SSandrine Bailleux assert(small_chunk_size != NULL); 928f55dfb4SSandrine Bailleux 938f55dfb4SSandrine Bailleux top_chunk_size = mem_end - submem_end; 948f55dfb4SSandrine Bailleux bottom_chunk_size = submem_start - mem_start; 958f55dfb4SSandrine Bailleux 968f55dfb4SSandrine Bailleux if (top_chunk_size < bottom_chunk_size) { 978f55dfb4SSandrine Bailleux *small_chunk_size = top_chunk_size; 988f55dfb4SSandrine Bailleux return TOP; 998f55dfb4SSandrine Bailleux } else { 1008f55dfb4SSandrine Bailleux *small_chunk_size = bottom_chunk_size; 1018f55dfb4SSandrine Bailleux return BOTTOM; 1028f55dfb4SSandrine Bailleux } 1038f55dfb4SSandrine Bailleux } 1048f55dfb4SSandrine Bailleux 1058f55dfb4SSandrine Bailleux /****************************************************************************** 1068f55dfb4SSandrine Bailleux * Reserve the memory region delimited by 'addr' and 'size'. The extents of free 1078f55dfb4SSandrine Bailleux * memory are passed in 'free_base' and 'free_size' and they will be updated to 1088f55dfb4SSandrine Bailleux * reflect the memory usage. 1097b6d330cSSandrine Bailleux * The caller must ensure the memory to reserve is free and that the addresses 1107b6d330cSSandrine Bailleux * and sizes passed in arguments are sane. 1118f55dfb4SSandrine Bailleux *****************************************************************************/ 1124c0d0390SSoby Mathew void reserve_mem(uintptr_t *free_base, size_t *free_size, 1134c0d0390SSoby Mathew uintptr_t addr, size_t size) 1148f55dfb4SSandrine Bailleux { 1158f55dfb4SSandrine Bailleux size_t discard_size; 1168f55dfb4SSandrine Bailleux size_t reserved_size; 1178f55dfb4SSandrine Bailleux unsigned int pos; 1188f55dfb4SSandrine Bailleux 1198f55dfb4SSandrine Bailleux assert(free_base != NULL); 1208f55dfb4SSandrine Bailleux assert(free_size != NULL); 1218f55dfb4SSandrine Bailleux assert(is_mem_free(*free_base, *free_size, addr, size)); 1228f55dfb4SSandrine Bailleux 1237b6d330cSSandrine Bailleux if (size == 0) { 1247b6d330cSSandrine Bailleux WARN("Nothing to allocate, requested size is zero\n"); 1257b6d330cSSandrine Bailleux return; 1267b6d330cSSandrine Bailleux } 1277b6d330cSSandrine Bailleux 1287b6d330cSSandrine Bailleux pos = choose_mem_pos(*free_base, *free_base + (*free_size - 1), 1297b6d330cSSandrine Bailleux addr, addr + (size - 1), 1308f55dfb4SSandrine Bailleux &discard_size); 1318f55dfb4SSandrine Bailleux 1328f55dfb4SSandrine Bailleux reserved_size = size + discard_size; 1338f55dfb4SSandrine Bailleux *free_size -= reserved_size; 1348f55dfb4SSandrine Bailleux 1358f55dfb4SSandrine Bailleux if (pos == BOTTOM) 1368f55dfb4SSandrine Bailleux *free_base = addr + size; 1378f55dfb4SSandrine Bailleux 1384c0d0390SSoby Mathew VERBOSE("Reserved 0x%zx bytes (discarded 0x%zx bytes %s)\n", 1398f55dfb4SSandrine Bailleux reserved_size, discard_size, 1408f55dfb4SSandrine Bailleux pos == TOP ? "above" : "below"); 1414f6ad66aSAchin Gupta } 1424f6ad66aSAchin Gupta 1434c0d0390SSoby Mathew static void dump_load_info(uintptr_t image_load_addr, 1444c0d0390SSoby Mathew size_t image_size, 145fb037bfbSDan Handley const meminfo_t *mem_layout) 1464f6ad66aSAchin Gupta { 1474c0d0390SSoby Mathew INFO("Trying to load image at address %p, size = 0x%zx\n", 1484c0d0390SSoby Mathew (void *)image_load_addr, image_size); 1496ad2e461SDan Handley INFO("Current memory layout:\n"); 1507b6d330cSSandrine Bailleux INFO(" total region = [base = %p, size = 0x%zx]\n", 1517b6d330cSSandrine Bailleux (void *) mem_layout->total_base, mem_layout->total_size); 1527b6d330cSSandrine Bailleux INFO(" free region = [base = %p, size = 0x%zx]\n", 1537b6d330cSSandrine Bailleux (void *) mem_layout->free_base, mem_layout->free_size); 1544f6ad66aSAchin Gupta } 15572600226SYatharth Kochar #endif /* LOAD_IMAGE_V2 */ 1564f6ad66aSAchin Gupta 157ee9ad785SRyan Harkin /* Generic function to return the size of an image */ 1584c0d0390SSoby Mathew size_t image_size(unsigned int image_id) 159ee9ad785SRyan Harkin { 160625de1d4SDan Handley uintptr_t dev_handle; 161625de1d4SDan Handley uintptr_t image_handle; 162625de1d4SDan Handley uintptr_t image_spec; 163ee9ad785SRyan Harkin size_t image_size = 0; 164e098e244SJuan Castillo int io_result; 165ee9ad785SRyan Harkin 166ee9ad785SRyan Harkin /* Obtain a reference to the image by querying the platform layer */ 16716948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 168e098e244SJuan Castillo if (io_result != 0) { 16916948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 17016948ae1SJuan Castillo image_id, io_result); 171ee9ad785SRyan Harkin return 0; 172ee9ad785SRyan Harkin } 173ee9ad785SRyan Harkin 174ee9ad785SRyan Harkin /* Attempt to access the image */ 175ee9ad785SRyan Harkin io_result = io_open(dev_handle, image_spec, &image_handle); 176e098e244SJuan Castillo if (io_result != 0) { 17716948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 17816948ae1SJuan Castillo image_id, io_result); 179ee9ad785SRyan Harkin return 0; 180ee9ad785SRyan Harkin } 181ee9ad785SRyan Harkin 182ee9ad785SRyan Harkin /* Find the size of the image */ 183ee9ad785SRyan Harkin io_result = io_size(image_handle, &image_size); 184e098e244SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 18516948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 18616948ae1SJuan Castillo image_id, io_result); 187ee9ad785SRyan Harkin } 188ee9ad785SRyan Harkin io_result = io_close(image_handle); 189ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'close' */ 190ee9ad785SRyan Harkin 191ee9ad785SRyan Harkin /* TODO: Consider maintaining open device connection from this 192ee9ad785SRyan Harkin * bootloader stage 193ee9ad785SRyan Harkin */ 194ee9ad785SRyan Harkin io_result = io_dev_close(dev_handle); 195ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'dev_close' */ 196ee9ad785SRyan Harkin 197ee9ad785SRyan Harkin return image_size; 198ee9ad785SRyan Harkin } 1998f55dfb4SSandrine Bailleux 20072600226SYatharth Kochar #if LOAD_IMAGE_V2 20172600226SYatharth Kochar 20272600226SYatharth Kochar /******************************************************************************* 20372600226SYatharth Kochar * Generic function to load an image at a specific address given 20472600226SYatharth Kochar * an image ID and extents of free memory. 20572600226SYatharth Kochar * 20672600226SYatharth Kochar * If the load is successful then the image information is updated. 20772600226SYatharth Kochar * 20872600226SYatharth Kochar * Returns 0 on success, a negative error code otherwise. 20972600226SYatharth Kochar ******************************************************************************/ 21072600226SYatharth Kochar int load_image(unsigned int image_id, image_info_t *image_data) 21172600226SYatharth Kochar { 21272600226SYatharth Kochar uintptr_t dev_handle; 21372600226SYatharth Kochar uintptr_t image_handle; 21472600226SYatharth Kochar uintptr_t image_spec; 21572600226SYatharth Kochar uintptr_t image_base; 21672600226SYatharth Kochar size_t image_size; 21772600226SYatharth Kochar size_t bytes_read; 21872600226SYatharth Kochar int io_result; 21972600226SYatharth Kochar 22072600226SYatharth Kochar assert(image_data != NULL); 22172600226SYatharth Kochar assert(image_data->h.version >= VERSION_2); 22272600226SYatharth Kochar 22372600226SYatharth Kochar image_base = image_data->image_base; 22472600226SYatharth Kochar 22572600226SYatharth Kochar /* Obtain a reference to the image by querying the platform layer */ 22672600226SYatharth Kochar io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 22772600226SYatharth Kochar if (io_result != 0) { 22872600226SYatharth Kochar WARN("Failed to obtain reference to image id=%u (%i)\n", 22972600226SYatharth Kochar image_id, io_result); 23072600226SYatharth Kochar return io_result; 23172600226SYatharth Kochar } 23272600226SYatharth Kochar 23372600226SYatharth Kochar /* Attempt to access the image */ 23472600226SYatharth Kochar io_result = io_open(dev_handle, image_spec, &image_handle); 23572600226SYatharth Kochar if (io_result != 0) { 23672600226SYatharth Kochar WARN("Failed to access image id=%u (%i)\n", 23772600226SYatharth Kochar image_id, io_result); 23872600226SYatharth Kochar return io_result; 23972600226SYatharth Kochar } 24072600226SYatharth Kochar 24172600226SYatharth Kochar INFO("Loading image id=%u at address %p\n", image_id, 24272600226SYatharth Kochar (void *) image_base); 24372600226SYatharth Kochar 24472600226SYatharth Kochar /* Find the size of the image */ 24572600226SYatharth Kochar io_result = io_size(image_handle, &image_size); 24672600226SYatharth Kochar if ((io_result != 0) || (image_size == 0)) { 24772600226SYatharth Kochar WARN("Failed to determine the size of the image id=%u (%i)\n", 24872600226SYatharth Kochar image_id, io_result); 24972600226SYatharth Kochar goto exit; 25072600226SYatharth Kochar } 25172600226SYatharth Kochar 25272600226SYatharth Kochar /* Check that the image size to load is within limit */ 25372600226SYatharth Kochar if (image_size > image_data->image_max_size) { 25472600226SYatharth Kochar WARN("Image id=%u size out of bounds\n", image_id); 25572600226SYatharth Kochar io_result = -EFBIG; 25672600226SYatharth Kochar goto exit; 25772600226SYatharth Kochar } 25872600226SYatharth Kochar 25972600226SYatharth Kochar image_data->image_size = image_size; 26072600226SYatharth Kochar 26172600226SYatharth Kochar /* We have enough space so load the image now */ 26272600226SYatharth Kochar /* TODO: Consider whether to try to recover/retry a partially successful read */ 26372600226SYatharth Kochar io_result = io_read(image_handle, image_base, image_size, &bytes_read); 26472600226SYatharth Kochar if ((io_result != 0) || (bytes_read < image_size)) { 26572600226SYatharth Kochar WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 26672600226SYatharth Kochar goto exit; 26772600226SYatharth Kochar } 26872600226SYatharth Kochar 26972600226SYatharth Kochar #if !TRUSTED_BOARD_BOOT 27072600226SYatharth Kochar /* 27172600226SYatharth Kochar * File has been successfully loaded. 27272600226SYatharth Kochar * Flush the image to main memory so that it can be executed later by 27372600226SYatharth Kochar * any CPU, regardless of cache and MMU state. 27472600226SYatharth Kochar * When TBB is enabled the image is flushed later, after image 27572600226SYatharth Kochar * authentication. 27672600226SYatharth Kochar */ 27772600226SYatharth Kochar flush_dcache_range(image_base, image_size); 27872600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 27972600226SYatharth Kochar 28072600226SYatharth Kochar INFO("Image id=%u loaded: %p - %p\n", image_id, (void *) image_base, 28172600226SYatharth Kochar (void *) (image_base + image_size)); 28272600226SYatharth Kochar 28372600226SYatharth Kochar exit: 28472600226SYatharth Kochar io_close(image_handle); 28572600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'close' */ 28672600226SYatharth Kochar 28772600226SYatharth Kochar /* TODO: Consider maintaining open device connection from this bootloader stage */ 28872600226SYatharth Kochar io_dev_close(dev_handle); 28972600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'dev_close' */ 29072600226SYatharth Kochar 29172600226SYatharth Kochar return io_result; 29272600226SYatharth Kochar } 29372600226SYatharth Kochar 2940f325c67SAntonio Nino Diaz static int load_auth_image_internal(unsigned int image_id, 2950f325c67SAntonio Nino Diaz image_info_t *image_data, 2960f325c67SAntonio Nino Diaz int is_parent_image) 29772600226SYatharth Kochar { 29872600226SYatharth Kochar int rc; 29972600226SYatharth Kochar 30072600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 30172600226SYatharth Kochar unsigned int parent_id; 30272600226SYatharth Kochar 30372600226SYatharth Kochar /* Use recursion to authenticate parent images */ 30472600226SYatharth Kochar rc = auth_mod_get_parent_id(image_id, &parent_id); 30572600226SYatharth Kochar if (rc == 0) { 3060f325c67SAntonio Nino Diaz rc = load_auth_image_internal(parent_id, image_data, 1); 30772600226SYatharth Kochar if (rc != 0) { 30872600226SYatharth Kochar return rc; 30972600226SYatharth Kochar } 31072600226SYatharth Kochar } 31172600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 31272600226SYatharth Kochar 31372600226SYatharth Kochar /* Load the image */ 31472600226SYatharth Kochar rc = load_image(image_id, image_data); 31572600226SYatharth Kochar if (rc != 0) { 31672600226SYatharth Kochar return rc; 31772600226SYatharth Kochar } 31872600226SYatharth Kochar 31972600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 32072600226SYatharth Kochar /* Authenticate it */ 32172600226SYatharth Kochar rc = auth_mod_verify_img(image_id, 32272600226SYatharth Kochar (void *)image_data->image_base, 32372600226SYatharth Kochar image_data->image_size); 32472600226SYatharth Kochar if (rc != 0) { 3250f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 326308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 32772600226SYatharth Kochar image_data->image_size); 32872600226SYatharth Kochar flush_dcache_range(image_data->image_base, 32972600226SYatharth Kochar image_data->image_size); 33072600226SYatharth Kochar return -EAUTH; 33172600226SYatharth Kochar } 33272600226SYatharth Kochar 33372600226SYatharth Kochar /* 33472600226SYatharth Kochar * File has been successfully loaded and authenticated. 33572600226SYatharth Kochar * Flush the image to main memory so that it can be executed later by 33672600226SYatharth Kochar * any CPU, regardless of cache and MMU state. 3370f325c67SAntonio Nino Diaz * Do it only for child images, not for the parents (certificates). 33872600226SYatharth Kochar */ 3390f325c67SAntonio Nino Diaz if (!is_parent_image) { 3400f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 3410f325c67SAntonio Nino Diaz image_data->image_size); 3420f325c67SAntonio Nino Diaz } 34372600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 34472600226SYatharth Kochar 34572600226SYatharth Kochar return 0; 34672600226SYatharth Kochar } 34772600226SYatharth Kochar 3480f325c67SAntonio Nino Diaz /******************************************************************************* 3490f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 3500f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 3510f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 3520f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 3530f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 3540f325c67SAntonio Nino Diaz ******************************************************************************/ 3550f325c67SAntonio Nino Diaz int load_auth_image(unsigned int image_id, image_info_t *image_data) 3560f325c67SAntonio Nino Diaz { 3570f325c67SAntonio Nino Diaz return load_auth_image_internal(image_id, image_data, 0); 3580f325c67SAntonio Nino Diaz } 3590f325c67SAntonio Nino Diaz 36072600226SYatharth Kochar #else /* LOAD_IMAGE_V2 */ 36172600226SYatharth Kochar 3624f6ad66aSAchin Gupta /******************************************************************************* 363a6b995fbSSandrine Bailleux * Generic function to load an image at a specific address given an image ID and 364a6b995fbSSandrine Bailleux * extents of free memory. 365a6b995fbSSandrine Bailleux * 366a6b995fbSSandrine Bailleux * If the load is successful then the image information is updated. 367a6b995fbSSandrine Bailleux * 368a6b995fbSSandrine Bailleux * If the entry_point_info argument is not NULL then this function also updates: 369a6b995fbSSandrine Bailleux * - the memory layout to mark the memory as reserved; 370a6b995fbSSandrine Bailleux * - the entry point information. 371a6b995fbSSandrine Bailleux * 372a6b995fbSSandrine Bailleux * The caller might pass a NULL pointer for the entry point if they are not 373a6b995fbSSandrine Bailleux * interested in this information. This is typically the case for non-executable 374a6b995fbSSandrine Bailleux * images (e.g. certificates) and executable images that won't ever be executed 375a6b995fbSSandrine Bailleux * on the application processor (e.g. additional microcontroller firmware). 376a6b995fbSSandrine Bailleux * 3778f55dfb4SSandrine Bailleux * Returns 0 on success, a negative error code otherwise. 3784f6ad66aSAchin Gupta ******************************************************************************/ 3794112bfa0SVikram Kanigiri int load_image(meminfo_t *mem_layout, 38016948ae1SJuan Castillo unsigned int image_id, 3811779ba6bSJuan Castillo uintptr_t image_base, 3824112bfa0SVikram Kanigiri image_info_t *image_data, 3834112bfa0SVikram Kanigiri entry_point_info_t *entry_point_info) 3844f6ad66aSAchin Gupta { 385625de1d4SDan Handley uintptr_t dev_handle; 386625de1d4SDan Handley uintptr_t image_handle; 387625de1d4SDan Handley uintptr_t image_spec; 3888f55dfb4SSandrine Bailleux size_t image_size; 3898f55dfb4SSandrine Bailleux size_t bytes_read; 39078460a05SJuan Castillo int io_result; 3914f6ad66aSAchin Gupta 3929d72b4eaSJames Morrissey assert(mem_layout != NULL); 3938f55dfb4SSandrine Bailleux assert(image_data != NULL); 39472600226SYatharth Kochar assert(image_data->h.version == VERSION_1); 3959d72b4eaSJames Morrissey 3969d72b4eaSJames Morrissey /* Obtain a reference to the image by querying the platform layer */ 39716948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 39878460a05SJuan Castillo if (io_result != 0) { 39916948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 40016948ae1SJuan Castillo image_id, io_result); 4014112bfa0SVikram Kanigiri return io_result; 4024f6ad66aSAchin Gupta } 4034f6ad66aSAchin Gupta 4049d72b4eaSJames Morrissey /* Attempt to access the image */ 4059d72b4eaSJames Morrissey io_result = io_open(dev_handle, image_spec, &image_handle); 40678460a05SJuan Castillo if (io_result != 0) { 40716948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 40816948ae1SJuan Castillo image_id, io_result); 4094112bfa0SVikram Kanigiri return io_result; 4104f6ad66aSAchin Gupta } 4114f6ad66aSAchin Gupta 412f0dd061aSAntonio Nino Diaz INFO("Loading image id=%u at address %p\n", image_id, 413f0dd061aSAntonio Nino Diaz (void *) image_base); 4148f55dfb4SSandrine Bailleux 4159d72b4eaSJames Morrissey /* Find the size of the image */ 4169d72b4eaSJames Morrissey io_result = io_size(image_handle, &image_size); 41778460a05SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 41816948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 41916948ae1SJuan Castillo image_id, io_result); 4204112bfa0SVikram Kanigiri goto exit; 4219d72b4eaSJames Morrissey } 4229d72b4eaSJames Morrissey 4238f55dfb4SSandrine Bailleux /* Check that the memory where the image will be loaded is free */ 4248f55dfb4SSandrine Bailleux if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, 4258f55dfb4SSandrine Bailleux image_base, image_size)) { 4267b6d330cSSandrine Bailleux WARN("Failed to reserve region [base = %p, size = 0x%zx]\n", 4277b6d330cSSandrine Bailleux (void *) image_base, image_size); 4289d72b4eaSJames Morrissey dump_load_info(image_base, image_size, mem_layout); 4294112bfa0SVikram Kanigiri io_result = -ENOMEM; 4304112bfa0SVikram Kanigiri goto exit; 4314f6ad66aSAchin Gupta } 4324f6ad66aSAchin Gupta 4334f6ad66aSAchin Gupta /* We have enough space so load the image now */ 4349d72b4eaSJames Morrissey /* TODO: Consider whether to try to recover/retry a partially successful read */ 435625de1d4SDan Handley io_result = io_read(image_handle, image_base, image_size, &bytes_read); 43678460a05SJuan Castillo if ((io_result != 0) || (bytes_read < image_size)) { 43716948ae1SJuan Castillo WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 4384112bfa0SVikram Kanigiri goto exit; 4394f6ad66aSAchin Gupta } 4404f6ad66aSAchin Gupta 441a6b995fbSSandrine Bailleux image_data->image_base = image_base; 442a6b995fbSSandrine Bailleux image_data->image_size = image_size; 443a6b995fbSSandrine Bailleux 4448f55dfb4SSandrine Bailleux /* 4458f55dfb4SSandrine Bailleux * Update the memory usage info. 4468f55dfb4SSandrine Bailleux * This is done after the actual loading so that it is not updated when 4478f55dfb4SSandrine Bailleux * the load is unsuccessful. 448c5fb47c3SJuan Castillo * If the caller does not provide an entry point, bypass the memory 449c5fb47c3SJuan Castillo * reservation. 4508f55dfb4SSandrine Bailleux */ 451c5fb47c3SJuan Castillo if (entry_point_info != NULL) { 4528f55dfb4SSandrine Bailleux reserve_mem(&mem_layout->free_base, &mem_layout->free_size, 4538f55dfb4SSandrine Bailleux image_base, image_size); 454a6b995fbSSandrine Bailleux entry_point_info->pc = image_base; 455c5fb47c3SJuan Castillo } else { 4567b6d330cSSandrine Bailleux INFO("Skip reserving region [base = %p, size = 0x%zx]\n", 4577b6d330cSSandrine Bailleux (void *) image_base, image_size); 458c5fb47c3SJuan Castillo } 4598f55dfb4SSandrine Bailleux 460ad4494dcSDan Handley #if !TRUSTED_BOARD_BOOT 4614f6ad66aSAchin Gupta /* 4628f55dfb4SSandrine Bailleux * File has been successfully loaded. 463ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 464ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 465ad4494dcSDan Handley * When TBB is enabled the image is flushed later, after image 466ad4494dcSDan Handley * authentication. 4674f6ad66aSAchin Gupta */ 4689d72b4eaSJames Morrissey flush_dcache_range(image_base, image_size); 469ad4494dcSDan Handley #endif /* TRUSTED_BOARD_BOOT */ 4704f6ad66aSAchin Gupta 4717b6d330cSSandrine Bailleux INFO("Image id=%u loaded at address %p, size = 0x%zx\n", image_id, 4727b6d330cSSandrine Bailleux (void *) image_base, image_size); 4739d72b4eaSJames Morrissey 4749d72b4eaSJames Morrissey exit: 4754112bfa0SVikram Kanigiri io_close(image_handle); 4769d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'close' */ 4779d72b4eaSJames Morrissey 4789d72b4eaSJames Morrissey /* TODO: Consider maintaining open device connection from this bootloader stage */ 4794112bfa0SVikram Kanigiri io_dev_close(dev_handle); 4809d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'dev_close' */ 4814f6ad66aSAchin Gupta 4824112bfa0SVikram Kanigiri return io_result; 4834f6ad66aSAchin Gupta } 4841779ba6bSJuan Castillo 4850f325c67SAntonio Nino Diaz static int load_auth_image_internal(meminfo_t *mem_layout, 4861779ba6bSJuan Castillo unsigned int image_id, 4871779ba6bSJuan Castillo uintptr_t image_base, 4881779ba6bSJuan Castillo image_info_t *image_data, 4890f325c67SAntonio Nino Diaz entry_point_info_t *entry_point_info, 4900f325c67SAntonio Nino Diaz int is_parent_image) 4911779ba6bSJuan Castillo { 4921779ba6bSJuan Castillo int rc; 4931779ba6bSJuan Castillo 4941779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 4951779ba6bSJuan Castillo unsigned int parent_id; 4961779ba6bSJuan Castillo 4971779ba6bSJuan Castillo /* Use recursion to authenticate parent images */ 4981779ba6bSJuan Castillo rc = auth_mod_get_parent_id(image_id, &parent_id); 4991779ba6bSJuan Castillo if (rc == 0) { 5000f325c67SAntonio Nino Diaz rc = load_auth_image_internal(mem_layout, parent_id, image_base, 5010f325c67SAntonio Nino Diaz image_data, NULL, 1); 50278460a05SJuan Castillo if (rc != 0) { 5031779ba6bSJuan Castillo return rc; 5041779ba6bSJuan Castillo } 5051779ba6bSJuan Castillo } 5061779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 5071779ba6bSJuan Castillo 5081779ba6bSJuan Castillo /* Load the image */ 5091779ba6bSJuan Castillo rc = load_image(mem_layout, image_id, image_base, image_data, 5101779ba6bSJuan Castillo entry_point_info); 51178460a05SJuan Castillo if (rc != 0) { 51278460a05SJuan Castillo return rc; 5131779ba6bSJuan Castillo } 5141779ba6bSJuan Castillo 5151779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 5161779ba6bSJuan Castillo /* Authenticate it */ 5171779ba6bSJuan Castillo rc = auth_mod_verify_img(image_id, 5181779ba6bSJuan Castillo (void *)image_data->image_base, 5191779ba6bSJuan Castillo image_data->image_size); 5201779ba6bSJuan Castillo if (rc != 0) { 5210f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 522308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 523fedbc049SJuan Castillo image_data->image_size); 524fedbc049SJuan Castillo flush_dcache_range(image_data->image_base, 525fedbc049SJuan Castillo image_data->image_size); 52678460a05SJuan Castillo return -EAUTH; 5271779ba6bSJuan Castillo } 528ad4494dcSDan Handley /* 529ad4494dcSDan Handley * File has been successfully loaded and authenticated. 530ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 531ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 5320f325c67SAntonio Nino Diaz * Do it only for child images, not for the parents (certificates). 533ad4494dcSDan Handley */ 5340f325c67SAntonio Nino Diaz if (!is_parent_image) { 5350f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 5360f325c67SAntonio Nino Diaz image_data->image_size); 5370f325c67SAntonio Nino Diaz } 5381779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 5391779ba6bSJuan Castillo 54078460a05SJuan Castillo return 0; 5411779ba6bSJuan Castillo } 54268a68c92SSandrine Bailleux 5430f325c67SAntonio Nino Diaz /******************************************************************************* 5440f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 5450f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 5460f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 5470f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 5480f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 5490f325c67SAntonio Nino Diaz ******************************************************************************/ 5500f325c67SAntonio Nino Diaz int load_auth_image(meminfo_t *mem_layout, 5510f325c67SAntonio Nino Diaz unsigned int image_id, 5520f325c67SAntonio Nino Diaz uintptr_t image_base, 5530f325c67SAntonio Nino Diaz image_info_t *image_data, 5540f325c67SAntonio Nino Diaz entry_point_info_t *entry_point_info) 5550f325c67SAntonio Nino Diaz { 5560f325c67SAntonio Nino Diaz return load_auth_image_internal(mem_layout, image_id, image_base, 5570f325c67SAntonio Nino Diaz image_data, entry_point_info, 0); 5580f325c67SAntonio Nino Diaz } 5590f325c67SAntonio Nino Diaz 56072600226SYatharth Kochar #endif /* LOAD_IMAGE_V2 */ 56172600226SYatharth Kochar 56268a68c92SSandrine Bailleux /******************************************************************************* 56368a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 56468a68c92SSandrine Bailleux ******************************************************************************/ 56568a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 56668a68c92SSandrine Bailleux { 5674c0d0390SSoby Mathew INFO("Entry point address = %p\n", (void *)ep_info->pc); 5684c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 56968a68c92SSandrine Bailleux 57068a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 57168a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 57268a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 57368a68c92SSandrine Bailleux 57468a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 57568a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 57668a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 57768a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 57851c79b73SSoby Mathew #ifndef AARCH32 57968a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 58068a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 58168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 58268a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 58351c79b73SSoby Mathew #endif 58468a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 58568a68c92SSandrine Bailleux } 586