14f6ad66aSAchin Gupta /* 2209a60ccSSoby Mathew * Copyright (c) 2013-2018, 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 20209a60ccSSoby Mathew #if TRUSTED_BOARD_BOOT 21209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 22209a60ccSSoby Mathew static int disable_auth; 23209a60ccSSoby Mathew 24209a60ccSSoby Mathew /****************************************************************************** 25209a60ccSSoby Mathew * API to dynamically disable authentication. Only meant for development 26*ed51b51fSRoberto Vargas * systems. This is only invoked if DYN_DISABLE_AUTH is defined. 27209a60ccSSoby Mathew *****************************************************************************/ 28209a60ccSSoby Mathew void dyn_disable_auth(void) 29209a60ccSSoby Mathew { 30209a60ccSSoby Mathew INFO("Disabling authentication of images dynamically\n"); 31209a60ccSSoby Mathew disable_auth = 1; 32209a60ccSSoby Mathew } 33209a60ccSSoby Mathew # endif /* DYN_DISABLE_AUTH */ 34209a60ccSSoby Mathew 35209a60ccSSoby Mathew /****************************************************************************** 36209a60ccSSoby Mathew * Function to determine whether the authentication is disabled dynamically. 37209a60ccSSoby Mathew *****************************************************************************/ 38209a60ccSSoby Mathew static int dyn_is_auth_disabled(void) 39209a60ccSSoby Mathew { 40209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 41209a60ccSSoby Mathew return disable_auth; 42209a60ccSSoby Mathew # else 43209a60ccSSoby Mathew return 0; 44209a60ccSSoby Mathew # endif 45209a60ccSSoby Mathew } 46209a60ccSSoby Mathew #endif /* TRUSTED_BOARD_BOOT */ 47209a60ccSSoby Mathew 484c0d0390SSoby Mathew uintptr_t page_align(uintptr_t value, unsigned dir) 494f6ad66aSAchin Gupta { 504f6ad66aSAchin Gupta /* Round up the limit to the next page boundary */ 514c0d0390SSoby Mathew if (value & (PAGE_SIZE - 1)) { 524c0d0390SSoby Mathew value &= ~(PAGE_SIZE - 1); 534f6ad66aSAchin Gupta if (dir == UP) 544c0d0390SSoby Mathew value += PAGE_SIZE; 554f6ad66aSAchin Gupta } 564f6ad66aSAchin Gupta 574f6ad66aSAchin Gupta return value; 584f6ad66aSAchin Gupta } 594f6ad66aSAchin Gupta 608f55dfb4SSandrine Bailleux /****************************************************************************** 618f55dfb4SSandrine Bailleux * Determine whether the memory region delimited by 'addr' and 'size' is free, 628f55dfb4SSandrine Bailleux * given the extents of free memory. 637b6d330cSSandrine Bailleux * Return 1 if it is free, 0 if it is not free or if the input values are 647b6d330cSSandrine Bailleux * invalid. 658f55dfb4SSandrine Bailleux *****************************************************************************/ 6699c5ebafSSandrine Bailleux int is_mem_free(uintptr_t free_base, size_t free_size, 674c0d0390SSoby Mathew uintptr_t addr, size_t size) 684f6ad66aSAchin Gupta { 697b6d330cSSandrine Bailleux uintptr_t free_end, requested_end; 707b6d330cSSandrine Bailleux 717b6d330cSSandrine Bailleux /* 727b6d330cSSandrine Bailleux * Handle corner cases first. 737b6d330cSSandrine Bailleux * 747b6d330cSSandrine Bailleux * The order of the 2 tests is important, because if there's no space 757b6d330cSSandrine Bailleux * left (i.e. free_size == 0) but we don't ask for any memory 767b6d330cSSandrine Bailleux * (i.e. size == 0) then we should report that the memory is free. 777b6d330cSSandrine Bailleux */ 787b6d330cSSandrine Bailleux if (size == 0) 797b6d330cSSandrine Bailleux return 1; /* A zero-byte region is always free */ 807b6d330cSSandrine Bailleux if (free_size == 0) 817b6d330cSSandrine Bailleux return 0; 827b6d330cSSandrine Bailleux 837b6d330cSSandrine Bailleux /* 847b6d330cSSandrine Bailleux * Check that the end addresses don't overflow. 857b6d330cSSandrine Bailleux * If they do, consider that this memory region is not free, as this 867b6d330cSSandrine Bailleux * is an invalid scenario. 877b6d330cSSandrine Bailleux */ 887b6d330cSSandrine Bailleux if (check_uptr_overflow(free_base, free_size - 1)) 897b6d330cSSandrine Bailleux return 0; 907b6d330cSSandrine Bailleux free_end = free_base + (free_size - 1); 917b6d330cSSandrine Bailleux 927b6d330cSSandrine Bailleux if (check_uptr_overflow(addr, size - 1)) 937b6d330cSSandrine Bailleux return 0; 947b6d330cSSandrine Bailleux requested_end = addr + (size - 1); 957b6d330cSSandrine Bailleux 967b6d330cSSandrine Bailleux /* 977b6d330cSSandrine Bailleux * Finally, check that the requested memory region lies within the free 987b6d330cSSandrine Bailleux * region. 997b6d330cSSandrine Bailleux */ 1007b6d330cSSandrine Bailleux return (addr >= free_base) && (requested_end <= free_end); 1014f6ad66aSAchin Gupta } 1024f6ad66aSAchin Gupta 103ee9ad785SRyan Harkin /* Generic function to return the size of an image */ 104d3775d46SDaniel Boulby size_t get_image_size(unsigned int image_id) 105ee9ad785SRyan Harkin { 106625de1d4SDan Handley uintptr_t dev_handle; 107625de1d4SDan Handley uintptr_t image_handle; 108625de1d4SDan Handley uintptr_t image_spec; 109ee9ad785SRyan Harkin size_t image_size = 0; 110e098e244SJuan Castillo int io_result; 111ee9ad785SRyan Harkin 112ee9ad785SRyan Harkin /* Obtain a reference to the image by querying the platform layer */ 11316948ae1SJuan Castillo io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 114e098e244SJuan Castillo if (io_result != 0) { 11516948ae1SJuan Castillo WARN("Failed to obtain reference to image id=%u (%i)\n", 11616948ae1SJuan Castillo image_id, io_result); 117ee9ad785SRyan Harkin return 0; 118ee9ad785SRyan Harkin } 119ee9ad785SRyan Harkin 120ee9ad785SRyan Harkin /* Attempt to access the image */ 121ee9ad785SRyan Harkin io_result = io_open(dev_handle, image_spec, &image_handle); 122e098e244SJuan Castillo if (io_result != 0) { 12316948ae1SJuan Castillo WARN("Failed to access image id=%u (%i)\n", 12416948ae1SJuan Castillo image_id, io_result); 125ee9ad785SRyan Harkin return 0; 126ee9ad785SRyan Harkin } 127ee9ad785SRyan Harkin 128ee9ad785SRyan Harkin /* Find the size of the image */ 129ee9ad785SRyan Harkin io_result = io_size(image_handle, &image_size); 130e098e244SJuan Castillo if ((io_result != 0) || (image_size == 0)) { 13116948ae1SJuan Castillo WARN("Failed to determine the size of the image id=%u (%i)\n", 13216948ae1SJuan Castillo image_id, io_result); 133ee9ad785SRyan Harkin } 134ee9ad785SRyan Harkin io_result = io_close(image_handle); 135ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'close' */ 136ee9ad785SRyan Harkin 137ee9ad785SRyan Harkin /* TODO: Consider maintaining open device connection from this 138ee9ad785SRyan Harkin * bootloader stage 139ee9ad785SRyan Harkin */ 140ee9ad785SRyan Harkin io_result = io_dev_close(dev_handle); 141ee9ad785SRyan Harkin /* Ignore improbable/unrecoverable error in 'dev_close' */ 142ee9ad785SRyan Harkin 143ee9ad785SRyan Harkin return image_size; 144ee9ad785SRyan Harkin } 1458f55dfb4SSandrine Bailleux 14672600226SYatharth Kochar /******************************************************************************* 14776163b3aSSoby Mathew * Internal function to load an image at a specific address given 14872600226SYatharth Kochar * an image ID and extents of free memory. 14972600226SYatharth Kochar * 15072600226SYatharth Kochar * If the load is successful then the image information is updated. 15172600226SYatharth Kochar * 15272600226SYatharth Kochar * Returns 0 on success, a negative error code otherwise. 15372600226SYatharth Kochar ******************************************************************************/ 15476163b3aSSoby Mathew static int load_image(unsigned int image_id, image_info_t *image_data) 15572600226SYatharth Kochar { 15672600226SYatharth Kochar uintptr_t dev_handle; 15772600226SYatharth Kochar uintptr_t image_handle; 15872600226SYatharth Kochar uintptr_t image_spec; 15972600226SYatharth Kochar uintptr_t image_base; 16072600226SYatharth Kochar size_t image_size; 16172600226SYatharth Kochar size_t bytes_read; 16272600226SYatharth Kochar int io_result; 16372600226SYatharth Kochar 16472600226SYatharth Kochar assert(image_data != NULL); 16572600226SYatharth Kochar assert(image_data->h.version >= VERSION_2); 16672600226SYatharth Kochar 16772600226SYatharth Kochar image_base = image_data->image_base; 16872600226SYatharth Kochar 16972600226SYatharth Kochar /* Obtain a reference to the image by querying the platform layer */ 17072600226SYatharth Kochar io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 17172600226SYatharth Kochar if (io_result != 0) { 17272600226SYatharth Kochar WARN("Failed to obtain reference to image id=%u (%i)\n", 17372600226SYatharth Kochar image_id, io_result); 17472600226SYatharth Kochar return io_result; 17572600226SYatharth Kochar } 17672600226SYatharth Kochar 17772600226SYatharth Kochar /* Attempt to access the image */ 17872600226SYatharth Kochar io_result = io_open(dev_handle, image_spec, &image_handle); 17972600226SYatharth Kochar if (io_result != 0) { 18072600226SYatharth Kochar WARN("Failed to access image id=%u (%i)\n", 18172600226SYatharth Kochar image_id, io_result); 18272600226SYatharth Kochar return io_result; 18372600226SYatharth Kochar } 18472600226SYatharth Kochar 18572600226SYatharth Kochar INFO("Loading image id=%u at address %p\n", image_id, 18672600226SYatharth Kochar (void *) image_base); 18772600226SYatharth Kochar 18872600226SYatharth Kochar /* Find the size of the image */ 18972600226SYatharth Kochar io_result = io_size(image_handle, &image_size); 19072600226SYatharth Kochar if ((io_result != 0) || (image_size == 0)) { 19172600226SYatharth Kochar WARN("Failed to determine the size of the image id=%u (%i)\n", 19272600226SYatharth Kochar image_id, io_result); 19372600226SYatharth Kochar goto exit; 19472600226SYatharth Kochar } 19572600226SYatharth Kochar 19672600226SYatharth Kochar /* Check that the image size to load is within limit */ 19772600226SYatharth Kochar if (image_size > image_data->image_max_size) { 19872600226SYatharth Kochar WARN("Image id=%u size out of bounds\n", image_id); 19972600226SYatharth Kochar io_result = -EFBIG; 20072600226SYatharth Kochar goto exit; 20172600226SYatharth Kochar } 20272600226SYatharth Kochar 20372600226SYatharth Kochar image_data->image_size = image_size; 20472600226SYatharth Kochar 20572600226SYatharth Kochar /* We have enough space so load the image now */ 20672600226SYatharth Kochar /* TODO: Consider whether to try to recover/retry a partially successful read */ 20772600226SYatharth Kochar io_result = io_read(image_handle, image_base, image_size, &bytes_read); 20872600226SYatharth Kochar if ((io_result != 0) || (bytes_read < image_size)) { 20972600226SYatharth Kochar WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 21072600226SYatharth Kochar goto exit; 21172600226SYatharth Kochar } 21272600226SYatharth Kochar 21372600226SYatharth Kochar INFO("Image id=%u loaded: %p - %p\n", image_id, (void *) image_base, 21472600226SYatharth Kochar (void *) (image_base + image_size)); 21572600226SYatharth Kochar 21672600226SYatharth Kochar exit: 21772600226SYatharth Kochar io_close(image_handle); 21872600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'close' */ 21972600226SYatharth Kochar 22072600226SYatharth Kochar /* TODO: Consider maintaining open device connection from this bootloader stage */ 22172600226SYatharth Kochar io_dev_close(dev_handle); 22272600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'dev_close' */ 22372600226SYatharth Kochar 22472600226SYatharth Kochar return io_result; 22572600226SYatharth Kochar } 22672600226SYatharth Kochar 2270f325c67SAntonio Nino Diaz static int load_auth_image_internal(unsigned int image_id, 2280f325c67SAntonio Nino Diaz image_info_t *image_data, 2290f325c67SAntonio Nino Diaz int is_parent_image) 23072600226SYatharth Kochar { 23172600226SYatharth Kochar int rc; 23272600226SYatharth Kochar 23372600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 234209a60ccSSoby Mathew if (dyn_is_auth_disabled() == 0) { 23572600226SYatharth Kochar unsigned int parent_id; 23672600226SYatharth Kochar 23772600226SYatharth Kochar /* Use recursion to authenticate parent images */ 23872600226SYatharth Kochar rc = auth_mod_get_parent_id(image_id, &parent_id); 23972600226SYatharth Kochar if (rc == 0) { 2400f325c67SAntonio Nino Diaz rc = load_auth_image_internal(parent_id, image_data, 1); 24172600226SYatharth Kochar if (rc != 0) { 24272600226SYatharth Kochar return rc; 24372600226SYatharth Kochar } 24472600226SYatharth Kochar } 245209a60ccSSoby Mathew } 24672600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 24772600226SYatharth Kochar 24872600226SYatharth Kochar /* Load the image */ 24972600226SYatharth Kochar rc = load_image(image_id, image_data); 25072600226SYatharth Kochar if (rc != 0) { 25172600226SYatharth Kochar return rc; 25272600226SYatharth Kochar } 25372600226SYatharth Kochar 25472600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 255209a60ccSSoby Mathew if (dyn_is_auth_disabled() == 0) { 25672600226SYatharth Kochar /* Authenticate it */ 25772600226SYatharth Kochar rc = auth_mod_verify_img(image_id, 25872600226SYatharth Kochar (void *)image_data->image_base, 25972600226SYatharth Kochar image_data->image_size); 26072600226SYatharth Kochar if (rc != 0) { 2610f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 262308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 26372600226SYatharth Kochar image_data->image_size); 26472600226SYatharth Kochar flush_dcache_range(image_data->image_base, 26572600226SYatharth Kochar image_data->image_size); 26672600226SYatharth Kochar return -EAUTH; 26772600226SYatharth Kochar } 268209a60ccSSoby Mathew } 26976163b3aSSoby Mathew #endif /* TRUSTED_BOARD_BOOT */ 27072600226SYatharth Kochar 27172600226SYatharth Kochar /* 27272600226SYatharth Kochar * Flush the image to main memory so that it can be executed later by 27376163b3aSSoby Mathew * any CPU, regardless of cache and MMU state. If TBB is enabled, then 27476163b3aSSoby Mathew * the file has been successfully loaded and authenticated and flush 27576163b3aSSoby Mathew * only for child images, not for the parents (certificates). 27672600226SYatharth Kochar */ 2770f325c67SAntonio Nino Diaz if (!is_parent_image) { 2780f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 2790f325c67SAntonio Nino Diaz image_data->image_size); 2800f325c67SAntonio Nino Diaz } 28176163b3aSSoby Mathew 28272600226SYatharth Kochar 28372600226SYatharth Kochar return 0; 28472600226SYatharth Kochar } 28572600226SYatharth Kochar 2860f325c67SAntonio Nino Diaz /******************************************************************************* 2870f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 2880f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 2890f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 2900f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 2910f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 2920f325c67SAntonio Nino Diaz ******************************************************************************/ 2930f325c67SAntonio Nino Diaz int load_auth_image(unsigned int image_id, image_info_t *image_data) 2940f325c67SAntonio Nino Diaz { 29501f62b6dSRoberto Vargas int err; 29601f62b6dSRoberto Vargas 29701f62b6dSRoberto Vargas do { 29801f62b6dSRoberto Vargas err = load_auth_image_internal(image_id, image_data, 0); 29901f62b6dSRoberto Vargas } while (err != 0 && plat_try_next_boot_source()); 30001f62b6dSRoberto Vargas 30101f62b6dSRoberto Vargas return err; 3020f325c67SAntonio Nino Diaz } 3030f325c67SAntonio Nino Diaz 30468a68c92SSandrine Bailleux /******************************************************************************* 30568a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 30668a68c92SSandrine Bailleux ******************************************************************************/ 30768a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 30868a68c92SSandrine Bailleux { 3094c0d0390SSoby Mathew INFO("Entry point address = %p\n", (void *)ep_info->pc); 3104c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 31168a68c92SSandrine Bailleux 31268a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 31368a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 31468a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 31568a68c92SSandrine Bailleux 31668a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 31768a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 31868a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 31968a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 32051c79b73SSoby Mathew #ifndef AARCH32 32168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 32268a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 32368a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 32468a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 32551c79b73SSoby Mathew #endif 32668a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 32768a68c92SSandrine Bailleux } 328