14f6ad66aSAchin Gupta /* 2b86048c4SAntonio Nino Diaz * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. 34f6ad66aSAchin Gupta * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 54f6ad66aSAchin Gupta */ 64f6ad66aSAchin Gupta 709d40e0eSAntonio Nino Diaz #include <assert.h> 809d40e0eSAntonio Nino Diaz #include <errno.h> 909d40e0eSAntonio Nino Diaz #include <string.h> 1009d40e0eSAntonio Nino Diaz 1197043ac9SDan Handley #include <arch.h> 12b86048c4SAntonio Nino Diaz #include <arch_features.h> 134f6ad66aSAchin Gupta #include <arch_helpers.h> 1409d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 1509d40e0eSAntonio Nino Diaz #include <common/debug.h> 1609d40e0eSAntonio Nino Diaz #include <drivers/auth/auth_mod.h> 1709d40e0eSAntonio Nino Diaz #include <drivers/io/io_storage.h> 1809d40e0eSAntonio Nino Diaz #include <lib/utils.h> 1909d40e0eSAntonio Nino Diaz #include <lib/xlat_tables/xlat_tables_defs.h> 2009d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 214f6ad66aSAchin Gupta 22209a60ccSSoby Mathew #if TRUSTED_BOARD_BOOT 23209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 24209a60ccSSoby Mathew static int disable_auth; 25209a60ccSSoby Mathew 26209a60ccSSoby Mathew /****************************************************************************** 27209a60ccSSoby Mathew * API to dynamically disable authentication. Only meant for development 28ed51b51fSRoberto Vargas * systems. This is only invoked if DYN_DISABLE_AUTH is defined. 29209a60ccSSoby Mathew *****************************************************************************/ 30209a60ccSSoby Mathew void dyn_disable_auth(void) 31209a60ccSSoby Mathew { 32209a60ccSSoby Mathew INFO("Disabling authentication of images dynamically\n"); 33209a60ccSSoby Mathew disable_auth = 1; 34209a60ccSSoby Mathew } 35209a60ccSSoby Mathew # endif /* DYN_DISABLE_AUTH */ 36209a60ccSSoby Mathew 37209a60ccSSoby Mathew /****************************************************************************** 38209a60ccSSoby Mathew * Function to determine whether the authentication is disabled dynamically. 39209a60ccSSoby Mathew *****************************************************************************/ 40209a60ccSSoby Mathew static int dyn_is_auth_disabled(void) 41209a60ccSSoby Mathew { 42209a60ccSSoby Mathew # ifdef DYN_DISABLE_AUTH 43209a60ccSSoby Mathew return disable_auth; 44209a60ccSSoby Mathew # else 45209a60ccSSoby Mathew return 0; 46209a60ccSSoby Mathew # endif 47209a60ccSSoby Mathew } 48209a60ccSSoby Mathew #endif /* TRUSTED_BOARD_BOOT */ 49209a60ccSSoby Mathew 504c0d0390SSoby Mathew uintptr_t page_align(uintptr_t value, unsigned dir) 514f6ad66aSAchin Gupta { 524f6ad66aSAchin Gupta /* Round up the limit to the next page boundary */ 5381542c00SAntonio Nino Diaz if ((value & (PAGE_SIZE - 1U)) != 0U) { 5481542c00SAntonio Nino Diaz value &= ~(PAGE_SIZE - 1U); 554f6ad66aSAchin Gupta if (dir == UP) 564c0d0390SSoby Mathew value += PAGE_SIZE; 574f6ad66aSAchin Gupta } 584f6ad66aSAchin Gupta 594f6ad66aSAchin Gupta return value; 604f6ad66aSAchin Gupta } 614f6ad66aSAchin Gupta 6272600226SYatharth Kochar /******************************************************************************* 6376163b3aSSoby Mathew * Internal function to load an image at a specific address given 6472600226SYatharth Kochar * an image ID and extents of free memory. 6572600226SYatharth Kochar * 6672600226SYatharth Kochar * If the load is successful then the image information is updated. 6772600226SYatharth Kochar * 6872600226SYatharth Kochar * Returns 0 on success, a negative error code otherwise. 6972600226SYatharth Kochar ******************************************************************************/ 7076163b3aSSoby Mathew static int load_image(unsigned int image_id, image_info_t *image_data) 7172600226SYatharth Kochar { 7272600226SYatharth Kochar uintptr_t dev_handle; 7372600226SYatharth Kochar uintptr_t image_handle; 7472600226SYatharth Kochar uintptr_t image_spec; 7572600226SYatharth Kochar uintptr_t image_base; 7672600226SYatharth Kochar size_t image_size; 7772600226SYatharth Kochar size_t bytes_read; 7872600226SYatharth Kochar int io_result; 7972600226SYatharth Kochar 8072600226SYatharth Kochar assert(image_data != NULL); 8172600226SYatharth Kochar assert(image_data->h.version >= VERSION_2); 8272600226SYatharth Kochar 8372600226SYatharth Kochar image_base = image_data->image_base; 8472600226SYatharth Kochar 8572600226SYatharth Kochar /* Obtain a reference to the image by querying the platform layer */ 8672600226SYatharth Kochar io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); 8772600226SYatharth Kochar if (io_result != 0) { 8872600226SYatharth Kochar WARN("Failed to obtain reference to image id=%u (%i)\n", 8972600226SYatharth Kochar image_id, io_result); 9072600226SYatharth Kochar return io_result; 9172600226SYatharth Kochar } 9272600226SYatharth Kochar 9372600226SYatharth Kochar /* Attempt to access the image */ 9472600226SYatharth Kochar io_result = io_open(dev_handle, image_spec, &image_handle); 9572600226SYatharth Kochar if (io_result != 0) { 9672600226SYatharth Kochar WARN("Failed to access image id=%u (%i)\n", 9772600226SYatharth Kochar image_id, io_result); 9872600226SYatharth Kochar return io_result; 9972600226SYatharth Kochar } 10072600226SYatharth Kochar 10181542c00SAntonio Nino Diaz INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base); 10272600226SYatharth Kochar 10372600226SYatharth Kochar /* Find the size of the image */ 10472600226SYatharth Kochar io_result = io_size(image_handle, &image_size); 10581542c00SAntonio Nino Diaz if ((io_result != 0) || (image_size == 0U)) { 10672600226SYatharth Kochar WARN("Failed to determine the size of the image id=%u (%i)\n", 10772600226SYatharth Kochar image_id, io_result); 10872600226SYatharth Kochar goto exit; 10972600226SYatharth Kochar } 11072600226SYatharth Kochar 11172600226SYatharth Kochar /* Check that the image size to load is within limit */ 11272600226SYatharth Kochar if (image_size > image_data->image_max_size) { 11372600226SYatharth Kochar WARN("Image id=%u size out of bounds\n", image_id); 11472600226SYatharth Kochar io_result = -EFBIG; 11572600226SYatharth Kochar goto exit; 11672600226SYatharth Kochar } 11772600226SYatharth Kochar 11881542c00SAntonio Nino Diaz /* 11981542c00SAntonio Nino Diaz * image_data->image_max_size is a uint32_t so image_size will always 12081542c00SAntonio Nino Diaz * fit in image_data->image_size. 12181542c00SAntonio Nino Diaz */ 12281542c00SAntonio Nino Diaz image_data->image_size = (uint32_t)image_size; 12372600226SYatharth Kochar 12472600226SYatharth Kochar /* We have enough space so load the image now */ 12572600226SYatharth Kochar /* TODO: Consider whether to try to recover/retry a partially successful read */ 12672600226SYatharth Kochar io_result = io_read(image_handle, image_base, image_size, &bytes_read); 12772600226SYatharth Kochar if ((io_result != 0) || (bytes_read < image_size)) { 12872600226SYatharth Kochar WARN("Failed to load image id=%u (%i)\n", image_id, io_result); 12972600226SYatharth Kochar goto exit; 13072600226SYatharth Kochar } 13172600226SYatharth Kochar 13281542c00SAntonio Nino Diaz INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base, 13381542c00SAntonio Nino Diaz (uintptr_t)(image_base + image_size)); 13472600226SYatharth Kochar 13572600226SYatharth Kochar exit: 13681542c00SAntonio Nino Diaz (void)io_close(image_handle); 13772600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'close' */ 13872600226SYatharth Kochar 13972600226SYatharth Kochar /* TODO: Consider maintaining open device connection from this bootloader stage */ 14081542c00SAntonio Nino Diaz (void)io_dev_close(dev_handle); 14172600226SYatharth Kochar /* Ignore improbable/unrecoverable error in 'dev_close' */ 14272600226SYatharth Kochar 14372600226SYatharth Kochar return io_result; 14472600226SYatharth Kochar } 14572600226SYatharth Kochar 1460f325c67SAntonio Nino Diaz static int load_auth_image_internal(unsigned int image_id, 1470f325c67SAntonio Nino Diaz image_info_t *image_data, 1480f325c67SAntonio Nino Diaz int is_parent_image) 14972600226SYatharth Kochar { 15072600226SYatharth Kochar int rc; 15172600226SYatharth Kochar 15272600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 153209a60ccSSoby Mathew if (dyn_is_auth_disabled() == 0) { 15472600226SYatharth Kochar unsigned int parent_id; 15572600226SYatharth Kochar 15672600226SYatharth Kochar /* Use recursion to authenticate parent images */ 15772600226SYatharth Kochar rc = auth_mod_get_parent_id(image_id, &parent_id); 15872600226SYatharth Kochar if (rc == 0) { 1590f325c67SAntonio Nino Diaz rc = load_auth_image_internal(parent_id, image_data, 1); 16072600226SYatharth Kochar if (rc != 0) { 16172600226SYatharth Kochar return rc; 16272600226SYatharth Kochar } 16372600226SYatharth Kochar } 164209a60ccSSoby Mathew } 16572600226SYatharth Kochar #endif /* TRUSTED_BOARD_BOOT */ 16672600226SYatharth Kochar 16772600226SYatharth Kochar /* Load the image */ 16872600226SYatharth Kochar rc = load_image(image_id, image_data); 16972600226SYatharth Kochar if (rc != 0) { 17072600226SYatharth Kochar return rc; 17172600226SYatharth Kochar } 17272600226SYatharth Kochar 17372600226SYatharth Kochar #if TRUSTED_BOARD_BOOT 174209a60ccSSoby Mathew if (dyn_is_auth_disabled() == 0) { 17572600226SYatharth Kochar /* Authenticate it */ 17672600226SYatharth Kochar rc = auth_mod_verify_img(image_id, 17772600226SYatharth Kochar (void *)image_data->image_base, 17872600226SYatharth Kochar image_data->image_size); 17972600226SYatharth Kochar if (rc != 0) { 1800f325c67SAntonio Nino Diaz /* Authentication error, zero memory and flush it right away. */ 181308d359bSDouglas Raillard zero_normalmem((void *)image_data->image_base, 18272600226SYatharth Kochar image_data->image_size); 18372600226SYatharth Kochar flush_dcache_range(image_data->image_base, 18472600226SYatharth Kochar image_data->image_size); 18572600226SYatharth Kochar return -EAUTH; 18672600226SYatharth Kochar } 187209a60ccSSoby Mathew } 18876163b3aSSoby Mathew #endif /* TRUSTED_BOARD_BOOT */ 18972600226SYatharth Kochar 19072600226SYatharth Kochar /* 19172600226SYatharth Kochar * Flush the image to main memory so that it can be executed later by 19276163b3aSSoby Mathew * any CPU, regardless of cache and MMU state. If TBB is enabled, then 19376163b3aSSoby Mathew * the file has been successfully loaded and authenticated and flush 19476163b3aSSoby Mathew * only for child images, not for the parents (certificates). 19572600226SYatharth Kochar */ 19681542c00SAntonio Nino Diaz if (is_parent_image == 0) { 1970f325c67SAntonio Nino Diaz flush_dcache_range(image_data->image_base, 1980f325c67SAntonio Nino Diaz image_data->image_size); 1990f325c67SAntonio Nino Diaz } 20076163b3aSSoby Mathew 20172600226SYatharth Kochar 20272600226SYatharth Kochar return 0; 20372600226SYatharth Kochar } 20472600226SYatharth Kochar 2050f325c67SAntonio Nino Diaz /******************************************************************************* 2060f325c67SAntonio Nino Diaz * Generic function to load and authenticate an image. The image is actually 2070f325c67SAntonio Nino Diaz * loaded by calling the 'load_image()' function. Therefore, it returns the 2080f325c67SAntonio Nino Diaz * same error codes if the loading operation failed, or -EAUTH if the 2090f325c67SAntonio Nino Diaz * authentication failed. In addition, this function uses recursion to 2100f325c67SAntonio Nino Diaz * authenticate the parent images up to the root of trust. 2110f325c67SAntonio Nino Diaz ******************************************************************************/ 2120f325c67SAntonio Nino Diaz int load_auth_image(unsigned int image_id, image_info_t *image_data) 2130f325c67SAntonio Nino Diaz { 21401f62b6dSRoberto Vargas int err; 21501f62b6dSRoberto Vargas 21601f62b6dSRoberto Vargas do { 21701f62b6dSRoberto Vargas err = load_auth_image_internal(image_id, image_data, 0); 21881542c00SAntonio Nino Diaz } while ((err != 0) && (plat_try_next_boot_source() != 0)); 21901f62b6dSRoberto Vargas 22001f62b6dSRoberto Vargas return err; 2210f325c67SAntonio Nino Diaz } 2220f325c67SAntonio Nino Diaz 22368a68c92SSandrine Bailleux /******************************************************************************* 22468a68c92SSandrine Bailleux * Print the content of an entry_point_info_t structure. 22568a68c92SSandrine Bailleux ******************************************************************************/ 22668a68c92SSandrine Bailleux void print_entry_point_info(const entry_point_info_t *ep_info) 22768a68c92SSandrine Bailleux { 22881542c00SAntonio Nino Diaz INFO("Entry point address = 0x%lx\n", ep_info->pc); 2294c0d0390SSoby Mathew INFO("SPSR = 0x%x\n", ep_info->spsr); 23068a68c92SSandrine Bailleux 23168a68c92SSandrine Bailleux #define PRINT_IMAGE_ARG(n) \ 23268a68c92SSandrine Bailleux VERBOSE("Argument #" #n " = 0x%llx\n", \ 23368a68c92SSandrine Bailleux (unsigned long long) ep_info->args.arg##n) 23468a68c92SSandrine Bailleux 23568a68c92SSandrine Bailleux PRINT_IMAGE_ARG(0); 23668a68c92SSandrine Bailleux PRINT_IMAGE_ARG(1); 23768a68c92SSandrine Bailleux PRINT_IMAGE_ARG(2); 23868a68c92SSandrine Bailleux PRINT_IMAGE_ARG(3); 239*402b3cf8SJulius Werner #ifdef __aarch64__ 24068a68c92SSandrine Bailleux PRINT_IMAGE_ARG(4); 24168a68c92SSandrine Bailleux PRINT_IMAGE_ARG(5); 24268a68c92SSandrine Bailleux PRINT_IMAGE_ARG(6); 24368a68c92SSandrine Bailleux PRINT_IMAGE_ARG(7); 24451c79b73SSoby Mathew #endif 24568a68c92SSandrine Bailleux #undef PRINT_IMAGE_ARG 24668a68c92SSandrine Bailleux } 247b86048c4SAntonio Nino Diaz 248*402b3cf8SJulius Werner #ifdef __aarch64__ 249b86048c4SAntonio Nino Diaz /******************************************************************************* 250b86048c4SAntonio Nino Diaz * Handle all possible cases regarding ARMv8.3-PAuth. 251b86048c4SAntonio Nino Diaz ******************************************************************************/ 252b86048c4SAntonio Nino Diaz void bl_handle_pauth(void) 253b86048c4SAntonio Nino Diaz { 254b86048c4SAntonio Nino Diaz #if ENABLE_PAUTH 255b86048c4SAntonio Nino Diaz /* 256b86048c4SAntonio Nino Diaz * ENABLE_PAUTH = 1 && CTX_INCLUDE_PAUTH_REGS = 1 257b86048c4SAntonio Nino Diaz * 258b86048c4SAntonio Nino Diaz * Check that the system supports address authentication to avoid 259b86048c4SAntonio Nino Diaz * getting an access fault when accessing the registers. This is all 260b86048c4SAntonio Nino Diaz * that is needed to check. If any of the authentication mechanisms is 261b86048c4SAntonio Nino Diaz * supported, the system knows about ARMv8.3-PAuth, so all the registers 262b86048c4SAntonio Nino Diaz * are available and accessing them won't generate a fault. 263b86048c4SAntonio Nino Diaz * 264b86048c4SAntonio Nino Diaz * Obtain 128-bit instruction key A from the platform and save it to the 265b86048c4SAntonio Nino Diaz * system registers. Pointer authentication can't be enabled here or the 266b86048c4SAntonio Nino Diaz * authentication will fail when returning from this function. 267b86048c4SAntonio Nino Diaz */ 268b6fd4183SAntonio Nino Diaz assert(is_armv8_3_pauth_apa_api_present()); 269b86048c4SAntonio Nino Diaz 270b86048c4SAntonio Nino Diaz uint64_t *apiakey = plat_init_apiakey(); 271b86048c4SAntonio Nino Diaz 272b86048c4SAntonio Nino Diaz write_apiakeylo_el1(apiakey[0]); 273b86048c4SAntonio Nino Diaz write_apiakeyhi_el1(apiakey[1]); 274b86048c4SAntonio Nino Diaz #else /* if !ENABLE_PAUTH */ 275b86048c4SAntonio Nino Diaz 276b86048c4SAntonio Nino Diaz # if CTX_INCLUDE_PAUTH_REGS 277b86048c4SAntonio Nino Diaz /* 278b86048c4SAntonio Nino Diaz * ENABLE_PAUTH = 0 && CTX_INCLUDE_PAUTH_REGS = 1 279b86048c4SAntonio Nino Diaz * 280b86048c4SAntonio Nino Diaz * Assert that the ARMv8.3-PAuth registers are present or an access 281b86048c4SAntonio Nino Diaz * fault will be triggered when they are being saved or restored. 282b86048c4SAntonio Nino Diaz */ 283b86048c4SAntonio Nino Diaz assert(is_armv8_3_pauth_present()); 284b86048c4SAntonio Nino Diaz # else 285b86048c4SAntonio Nino Diaz /* 286b86048c4SAntonio Nino Diaz * ENABLE_PAUTH = 0 && CTX_INCLUDE_PAUTH_REGS = 0 287b86048c4SAntonio Nino Diaz * 288b86048c4SAntonio Nino Diaz * Pointer authentication is allowed in the Non-secure world, but 289b86048c4SAntonio Nino Diaz * prohibited in the Secure world. The Trusted Firmware doesn't save the 290b86048c4SAntonio Nino Diaz * registers during a world switch. No check needed. 291b86048c4SAntonio Nino Diaz */ 292b86048c4SAntonio Nino Diaz # endif /* CTX_INCLUDE_PAUTH_REGS */ 293b86048c4SAntonio Nino Diaz 294b86048c4SAntonio Nino Diaz #endif /* ENABLE_PAUTH */ 295b86048c4SAntonio Nino Diaz } 296*402b3cf8SJulius Werner #endif /* __aarch64__ */ 297