diff options
Diffstat (limited to 'common/bl_common.c')
-rw-r--r-- | common/bl_common.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/common/bl_common.c b/common/bl_common.c new file mode 100644 index 0000000..8fce02f --- /dev/null +++ b/common/bl_common.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <string.h> + +#include <arch.h> +#include <arch_features.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/auth/auth_mod.h> +#include <drivers/io/io_storage.h> +#include <lib/utils.h> +#include <lib/xlat_tables/xlat_tables_defs.h> +#include <plat/common/platform.h> + +#if TRUSTED_BOARD_BOOT +# ifdef DYN_DISABLE_AUTH +static int disable_auth; + +/****************************************************************************** + * API to dynamically disable authentication. Only meant for development + * systems. This is only invoked if DYN_DISABLE_AUTH is defined. + *****************************************************************************/ +void dyn_disable_auth(void) +{ + INFO("Disabling authentication of images dynamically\n"); + disable_auth = 1; +} +# endif /* DYN_DISABLE_AUTH */ + +/****************************************************************************** + * Function to determine whether the authentication is disabled dynamically. + *****************************************************************************/ +static int dyn_is_auth_disabled(void) +{ +# ifdef DYN_DISABLE_AUTH + return disable_auth; +# else + return 0; +# endif +} +#endif /* TRUSTED_BOARD_BOOT */ + +uintptr_t page_align(uintptr_t value, unsigned dir) +{ + /* Round up the limit to the next page boundary */ + if ((value & PAGE_SIZE_MASK) != 0U) { + value &= ~PAGE_SIZE_MASK; + if (dir == UP) + value += PAGE_SIZE; + } + + return value; +} + +/******************************************************************************* + * Internal function to load an image at a specific address given + * an image ID and extents of free memory. + * + * If the load is successful then the image information is updated. + * + * Returns 0 on success, a negative error code otherwise. + ******************************************************************************/ +static int load_image(unsigned int image_id, image_info_t *image_data) +{ + uintptr_t dev_handle; + uintptr_t image_handle; + uintptr_t image_spec; + uintptr_t image_base; + size_t image_size; + size_t bytes_read; + int io_result; + + assert(image_data != NULL); + assert(image_data->h.version >= VERSION_2); + + image_base = image_data->image_base; + + /* Obtain a reference to the image by querying the platform layer */ + io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); + if (io_result != 0) { + WARN("Failed to obtain reference to image id=%u (%i)\n", + image_id, io_result); + return io_result; + } + + /* Attempt to access the image */ + io_result = io_open(dev_handle, image_spec, &image_handle); + if (io_result != 0) { + WARN("Failed to access image id=%u (%i)\n", + image_id, io_result); + return io_result; + } + + INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base); + + /* Find the size of the image */ + io_result = io_size(image_handle, &image_size); + if ((io_result != 0) || (image_size == 0U)) { + WARN("Failed to determine the size of the image id=%u (%i)\n", + image_id, io_result); + goto exit; + } + + /* Check that the image size to load is within limit */ + if (image_size > image_data->image_max_size) { + WARN("Image id=%u size out of bounds\n", image_id); + io_result = -EFBIG; + goto exit; + } + + /* + * image_data->image_max_size is a uint32_t so image_size will always + * fit in image_data->image_size. + */ + image_data->image_size = (uint32_t)image_size; + + /* We have enough space so load the image now */ + /* TODO: Consider whether to try to recover/retry a partially successful read */ + io_result = io_read(image_handle, image_base, image_size, &bytes_read); + if ((io_result != 0) || (bytes_read < image_size)) { + WARN("Failed to load image id=%u (%i)\n", image_id, io_result); + goto exit; + } + + INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base, + (uintptr_t)(image_base + image_size)); + +exit: + (void)io_close(image_handle); + /* Ignore improbable/unrecoverable error in 'close' */ + + /* TODO: Consider maintaining open device connection from this bootloader stage */ + (void)io_dev_close(dev_handle); + /* Ignore improbable/unrecoverable error in 'dev_close' */ + + return io_result; +} + +#if TRUSTED_BOARD_BOOT +/* + * This function uses recursion to authenticate the parent images up to the root + * of trust. + */ +static int load_auth_image_recursive(unsigned int image_id, + image_info_t *image_data, + int is_parent_image) +{ + int rc; + unsigned int parent_id; + + /* Use recursion to authenticate parent images */ + rc = auth_mod_get_parent_id(image_id, &parent_id); + if (rc == 0) { + rc = load_auth_image_recursive(parent_id, image_data, 1); + if (rc != 0) { + return rc; + } + } + + /* Load the image */ + rc = load_image(image_id, image_data); + if (rc != 0) { + return rc; + } + + /* Authenticate it */ + rc = auth_mod_verify_img(image_id, + (void *)image_data->image_base, + image_data->image_size); + if (rc != 0) { + /* Authentication error, zero memory and flush it right away. */ + zero_normalmem((void *)image_data->image_base, + image_data->image_size); + flush_dcache_range(image_data->image_base, + image_data->image_size); + return -EAUTH; + } + + return 0; +} +#endif /* TRUSTED_BOARD_BOOT */ + +static int load_auth_image_internal(unsigned int image_id, + image_info_t *image_data) +{ +#if TRUSTED_BOARD_BOOT + if (dyn_is_auth_disabled() == 0) { + return load_auth_image_recursive(image_id, image_data, 0); + } +#endif + + return load_image(image_id, image_data); +} + +/******************************************************************************* + * Generic function to load and authenticate an image. The image is actually + * loaded by calling the 'load_image()' function. Therefore, it returns the + * same error codes if the loading operation failed, or -EAUTH if the + * authentication failed. In addition, this function uses recursion to + * authenticate the parent images up to the root of trust (if TBB is enabled). + ******************************************************************************/ +int load_auth_image(unsigned int image_id, image_info_t *image_data) +{ + int err; + +/* + * All firmware banks should be part of the same non-volatile storage as per + * PSA FWU specification, hence don't check for any alternate boot source + * when PSA FWU is enabled. + */ +#if PSA_FWU_SUPPORT + err = load_auth_image_internal(image_id, image_data); +#else + do { + err = load_auth_image_internal(image_id, image_data); + } while ((err != 0) && (plat_try_next_boot_source() != 0)); +#endif /* PSA_FWU_SUPPORT */ + + if (err == 0) { + /* + * If loading of the image gets passed (along with its + * authentication in case of Trusted-Boot flow) then measure + * it (if MEASURED_BOOT flag is enabled). + */ + err = plat_mboot_measure_image(image_id, image_data); + if (err != 0) { + return err; + } + + /* + * Flush the image to main memory so that it can be executed + * later by any CPU, regardless of cache and MMU state. + */ + flush_dcache_range(image_data->image_base, + image_data->image_size); + } + + return err; +} + +/******************************************************************************* + * Print the content of an entry_point_info_t structure. + ******************************************************************************/ +void print_entry_point_info(const entry_point_info_t *ep_info) +{ + INFO("Entry point address = 0x%lx\n", ep_info->pc); + INFO("SPSR = 0x%x\n", ep_info->spsr); + +#define PRINT_IMAGE_ARG(n) \ + VERBOSE("Argument #" #n " = 0x%llx\n", \ + (unsigned long long) ep_info->args.arg##n) + + PRINT_IMAGE_ARG(0); + PRINT_IMAGE_ARG(1); + PRINT_IMAGE_ARG(2); + PRINT_IMAGE_ARG(3); +#ifdef __aarch64__ + PRINT_IMAGE_ARG(4); + PRINT_IMAGE_ARG(5); + PRINT_IMAGE_ARG(6); + PRINT_IMAGE_ARG(7); +#endif +#undef PRINT_IMAGE_ARG +} + +/* + * This function is for returning the TF-A version + */ +const char *get_version(void) +{ + extern const char version[]; + return version; +} |