14f6ad66aSAchin Gupta /* 2308d359bSDouglas Raillard * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. 34f6ad66aSAchin Gupta * 482cb2c1aSdp-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 { 357*01f62b6dSRoberto Vargas int err; 358*01f62b6dSRoberto Vargas 359*01f62b6dSRoberto Vargas do { 360*01f62b6dSRoberto Vargas err = load_auth_image_internal(image_id, image_data, 0); 361*01f62b6dSRoberto Vargas } while (err != 0 && plat_try_next_boot_source()); 362*01f62b6dSRoberto Vargas 363*01f62b6dSRoberto Vargas return err; 3640f325c67SAntonio Nino Diaz } 3650f325c67SAntonio Nino Diaz 36672600226SYatharth Kochar #else /* LOAD_IMAGE_V2 */ 36772600226SYatharth Kochar 3684f6ad66aSAchin Gupta /******************************************************************************* 369a6b995fbSSandrine Bailleux * Generic function to load an image at a specific address given an image ID and 370a6b995fbSSandrine Bailleux * extents of free memory. 371a6b995fbSSandrine Bailleux * 372a6b995fbSSandrine Bailleux * If the load is successful then the image information is updated. 373a6b995fbSSandrine Bailleux * 374a6b995fbSSandrine Bailleux * If the entry_point_info argument is not NULL then this function also updates: 375a6b995fbSSandrine Bailleux * - the memory layout to mark the memory as reserved; 376a6b995fbSSandrine Bailleux * - the entry point information. 377a6b995fbSSandrine Bailleux * 378a6b995fbSSandrine Bailleux * The caller might pass a NULL pointer for the entry point if they are not 379a6b995fbSSandrine Bailleux * interested in this information. This is typically the case for non-executable 380a6b995fbSSandrine Bailleux * images (e.g. certificates) and executable images that won't ever be executed 381a6b995fbSSandrine Bailleux * on the application processor (e.g. additional microcontroller firmware). 382a6b995fbSSandrine Bailleux * 3838f55dfb4SSandrine Bailleux * Returns 0 on success, a negative error code otherwise. 3844f6ad66aSAchin Gupta ******************************************************************************/ 3854112bfa0SVikram Kanigiri int load_image(meminfo_t *mem_layout, 38616948ae1SJuan Castillo unsigned int image_id, 3871779ba6bSJuan Castillo uintptr_t image_base, 3884112bfa0SVikram Kanigiri image_info_t *image_data, 3894112bfa0SVikram Kanigiri entry_point_info_t *entry_point_info) 3904f6ad66aSAchin Gupta { 391625de1d4SDan Handley uintptr_t dev_handle; 392625de1d4SDan Handley uintptr_t image_handle; 393625de1d4SDan Handley uintptr_t image_spec; 3948f55dfb4SSandrine Bailleux size_t image_size; 3958f55dfb4SSandrine Bailleux size_t bytes_read; 39678460a05SJuan Castillo int io_result; 3974f6ad66aSAchin Gupta 3989d72b4eaSJames Morrissey assert(mem_layout != NULL); 3998f55dfb4SSandrine Bailleux assert(image_data != NULL); 40072600226SYatharth Kochar assert(image_data->h.version == VERSION_1); 4019d72b4eaSJames Morrissey 4029d72b4eaSJames Morrissey /* Obtain a reference to the image by querying the platform layer */ 40316948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 40478460a05SJuan Castillo if (io_result != 0) { 40516948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 40616948ae1SJuan Castillo image_id, io_result); 4074112bfa0SVikram Kanigiri return io_result; 4084f6ad66aSAchin Gupta } 4094f6ad66aSAchin Gupta 4109d72b4eaSJames Morrissey /* Attempt to access the image */ 4119d72b4eaSJames Morrissey io_result = io_open(dev_handle, image_spec, &image_handle); 41278460a05SJuan Castillo if (io_result != 0) { 41316948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 41416948ae1SJuan Castillo image_id, io_result); 4154112bfa0SVikram Kanigiri return io_result; 4164f6ad66aSAchin Gupta } 4174f6ad66aSAchin Gupta 418f0dd061aSAntonio Nino Diaz INFO("Loading image id=%u at address %p\n", image_id, 419f0dd061aSAntonio Nino Diaz (void *) image_base); 4208f55dfb4SSandrine Bailleux 4219d72b4eaSJames Morrissey /* Find the size of the image */ 4229d72b4eaSJames Morrissey io_result = io_size(image_handle, &image_size); 42378460a05SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 42416948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 42516948ae1SJuan Castillo image_id, io_result); 4264112bfa0SVikram Kanigiri goto exit; 4279d72b4eaSJames Morrissey } 4289d72b4eaSJames Morrissey 4298f55dfb4SSandrine Bailleux /* Check that the memory where the image will be loaded is free */ 4308f55dfb4SSandrine Bailleux if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, 4318f55dfb4SSandrine Bailleux image_base, image_size)) { 4327b6d330cSSandrine Bailleux WARN("Failed to reserve region [base = %p, size = 0x%zx]\n", 4337b6d330cSSandrine Bailleux (void *) image_base, image_size); 4349d72b4eaSJames Morrissey dump_load_info(image_base, image_size, mem_layout); 4354112bfa0SVikram Kanigiri io_result = -ENOMEM; 4364112bfa0SVikram Kanigiri goto exit; 4374f6ad66aSAchin Gupta } 4384f6ad66aSAchin Gupta 4394f6ad66aSAchin Gupta /* We have enough space so load the image now */ 4409d72b4eaSJames Morrissey /* TODO: Consider whether to try to recover/retry a partially successful read */ 441625de1d4SDan Handley io_result = io_read(image_handle, image_base, image_size, &bytes_read); 44278460a05SJuan Castillo if ((io_result != 0) || (bytes_read < image_size)) { 44316948ae1SJuan Castillo WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 4444112bfa0SVikram Kanigiri goto exit; 4454f6ad66aSAchin Gupta } 4464f6ad66aSAchin Gupta 447a6b995fbSSandrine Bailleux image_data->image_base = image_base; 448a6b995fbSSandrine Bailleux image_data->image_size = image_size; 449a6b995fbSSandrine Bailleux 4508f55dfb4SSandrine Bailleux /* 4518f55dfb4SSandrine Bailleux * Update the memory usage info. 4528f55dfb4SSandrine Bailleux * This is done after the actual loading so that it is not updated when 4538f55dfb4SSandrine Bailleux * the load is unsuccessful. 454c5fb47c3SJuan Castillo * If the caller does not provide an entry point, bypass the memory 455c5fb47c3SJuan Castillo * reservation. 4568f55dfb4SSandrine Bailleux */ 457c5fb47c3SJuan Castillo if (entry_point_info != NULL) { 4588f55dfb4SSandrine Bailleux reserve_mem(&mem_layout->free_base, &mem_layout->free_size, 4598f55dfb4SSandrine Bailleux image_base, image_size); 460a6b995fbSSandrine Bailleux entry_point_info->pc = image_base; 461c5fb47c3SJuan Castillo } else { 4627b6d330cSSandrine Bailleux INFO("Skip reserving region [base = %p, size = 0x%zx]\n", 4637b6d330cSSandrine Bailleux (void *) image_base, image_size); 464c5fb47c3SJuan Castillo } 4658f55dfb4SSandrine Bailleux 466ad4494dcSDan Handley #if !TRUSTED_BOARD_BOOT 4674f6ad66aSAchin Gupta /* 4688f55dfb4SSandrine Bailleux * File has been successfully loaded. 469ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 470ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 471ad4494dcSDan Handley * When TBB is enabled the image is flushed later, after image 472ad4494dcSDan Handley * authentication. 4734f6ad66aSAchin Gupta */ 4749d72b4eaSJames Morrissey flush_dcache_range(image_base, image_size); 475ad4494dcSDan Handley #endif /* TRUSTED_BOARD_BOOT */ 4764f6ad66aSAchin Gupta 4777b6d330cSSandrine Bailleux INFO("Image id=%u loaded at address %p, size = 0x%zx\n", image_id, 4787b6d330cSSandrine Bailleux (void *) image_base, image_size); 4799d72b4eaSJames Morrissey 4809d72b4eaSJames Morrissey exit: 4814112bfa0SVikram Kanigiri io_close(image_handle); 4829d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'close' */ 4839d72b4eaSJames Morrissey 4849d72b4eaSJames Morrissey /* TODO: Consider maintaining open device connection from this bootloader stage */ 4854112bfa0SVikram Kanigiri io_dev_close(dev_handle); 4869d72b4eaSJames Morrissey /* Ignore improbable/unrecoverable error in 'dev_close' */ 4874f6ad66aSAchin Gupta 4884112bfa0SVikram Kanigiri return io_result; 4894f6ad66aSAchin Gupta } 4901779ba6bSJuan Castillo 4910f325c67SAntonio Nino Diaz static int load_auth_image_internal(meminfo_t *mem_layout, 4921779ba6bSJuan Castillo unsigned int image_id, 4931779ba6bSJuan Castillo uintptr_t image_base, 4941779ba6bSJuan Castillo image_info_t *image_data, 4950f325c67SAntonio Nino Diaz entry_point_info_t *entry_point_info, 4960f325c67SAntonio Nino Diaz int is_parent_image) 4971779ba6bSJuan Castillo { 4981779ba6bSJuan Castillo int rc; 4991779ba6bSJuan Castillo 5001779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 5011779ba6bSJuan Castillo unsigned int parent_id; 5021779ba6bSJuan Castillo 5031779ba6bSJuan Castillo /* Use recursion to authenticate parent images */ 5041779ba6bSJuan Castillo rc = auth_mod_get_parent_id(image_id, &parent_id); 5051779ba6bSJuan Castillo if (rc == 0) { 5060f325c67SAntonio Nino Diaz rc = load_auth_image_internal(mem_layout, parent_id, image_base, 5070f325c67SAntonio Nino Diaz image_data, NULL, 1); 50878460a05SJuan Castillo if (rc != 0) { 5091779ba6bSJuan Castillo return rc; 5101779ba6bSJuan Castillo } 5111779ba6bSJuan Castillo } 5121779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 5131779ba6bSJuan Castillo 5141779ba6bSJuan Castillo /* Load the image */ 5151779ba6bSJuan Castillo rc = load_image(mem_layout, image_id, image_base, image_data, 5161779ba6bSJuan Castillo entry_point_info); 51778460a05SJuan Castillo if (rc != 0) { 51878460a05SJuan Castillo return rc; 5191779ba6bSJuan Castillo } 5201779ba6bSJuan Castillo 5211779ba6bSJuan Castillo #if TRUSTED_BOARD_BOOT 5221779ba6bSJuan Castillo /* Authenticate it */ 5231779ba6bSJuan Castillo rc = auth_mod_verify_img(image_id, 5241779ba6bSJuan Castillo (void *)image_data->image_base, 5251779ba6bSJuan Castillo image_data->image_size); 5261779ba6bSJuan Castillo if (rc != 0) { 5270f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 528308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 529fedbc049SJuan Castillo image_data->image_size); 530fedbc049SJuan Castillo flush_dcache_range(image_data->image_base, 531fedbc049SJuan Castillo image_data->image_size); 53278460a05SJuan Castillo return -EAUTH; 5331779ba6bSJuan Castillo } 534ad4494dcSDan Handley /* 535ad4494dcSDan Handley * File has been successfully loaded and authenticated. 536ad4494dcSDan Handley * Flush the image to main memory so that it can be executed later by 537ad4494dcSDan Handley * any CPU, regardless of cache and MMU state. 5380f325c67SAntonio Nino Diaz * Do it only for child images, not for the parents (certificates). 539ad4494dcSDan Handley */ 5400f325c67SAntonio Nino Diaz if (!is_parent_image) { 5410f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 5420f325c67SAntonio Nino Diaz image_data->image_size); 5430f325c67SAntonio Nino Diaz } 5441779ba6bSJuan Castillo #endif /* TRUSTED_BOARD_BOOT */ 5451779ba6bSJuan Castillo 54678460a05SJuan Castillo return 0; 5471779ba6bSJuan Castillo } 54868a68c92SSandrine Bailleux 5490f325c67SAntonio Nino Diaz /******************************************************************************* 5500f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 5510f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 5520f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 5530f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 5540f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 5550f325c67SAntonio Nino Diaz ******************************************************************************/ 5560f325c67SAntonio Nino Diaz int load_auth_image(meminfo_t *mem_layout, 5570f325c67SAntonio Nino Diaz unsigned int image_id, 5580f325c67SAntonio Nino Diaz uintptr_t image_base, 5590f325c67SAntonio Nino Diaz image_info_t *image_data, 5600f325c67SAntonio Nino Diaz entry_point_info_t *entry_point_info) 5610f325c67SAntonio Nino Diaz { 562*01f62b6dSRoberto Vargas int err; 563*01f62b6dSRoberto Vargas 564*01f62b6dSRoberto Vargas do { 565*01f62b6dSRoberto Vargas err = load_auth_image_internal(mem_layout, image_id, image_base, 5660f325c67SAntonio Nino Diaz image_data, entry_point_info, 0); 567*01f62b6dSRoberto Vargas } while (err != 0 && plat_try_next_boot_source()); 568*01f62b6dSRoberto Vargas 569*01f62b6dSRoberto Vargas return err; 5700f325c67SAntonio Nino Diaz } 5710f325c67SAntonio Nino Diaz 57272600226SYatharth Kochar #endif /* LOAD_IMAGE_V2 */ 57372600226SYatharth Kochar 57468a68c92SSandrine Bailleux /******************************************************************************* 57568a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 57668a68c92SSandrine Bailleux ******************************************************************************/ 57768a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 57868a68c92SSandrine Bailleux { 5794c0d0390SSoby Mathew INFO("Entry point address = %p\n", (void *)ep_info->pc); 5804c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 58168a68c92SSandrine Bailleux 58268a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 58368a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 58468a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 58568a68c92SSandrine Bailleux 58668a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 58768a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 58868a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 58968a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 59051c79b73SSoby Mathew #ifndef AARCH32 59168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 59268a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 59368a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 59468a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 59551c79b73SSoby Mathew #endif 59668a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 59768a68c92SSandrine Bailleux } 598