/* Do some basic package checks. */ static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) { int result; unsigned int image_id = (unsigned int)init_params; uintptr_t backend_handle; fip_toc_header_t header; size_t bytes_read; /* Obtain a reference to the image by querying the platform layer */ result = plat_get_image_source(image_id, &backend_dev_handle, &backend_image_spec); if (result != 0) { WARN("Failed to obtain reference to image id=%u (%i)\n", image_id, result); result = -ENOENT; goto fip_dev_init_exit; } /* Attempt to access the FIP image */ result = io_open(backend_dev_handle, backend_image_spec, &backend_handle); if (result != 0) { WARN("Failed to access image id=%u (%i)\n", image_id, result); result = -ENOENT; goto fip_dev_init_exit; } result = io_read(backend_handle, (uintptr_t)&header, sizeof(header), &bytes_read); if (result == 0) { if (!is_valid_header(&header)) { WARN("Firmware Image Package header check failed.\n"); result = -ENOENT; } else { VERBOSE("FIP header looks OK.\n"); } } io_close(backend_handle); fip_dev_init_exit: return result; }
/* Generic function to return the size of an image */ unsigned long image_size(const char *image_name) { uintptr_t dev_handle; uintptr_t image_handle; uintptr_t image_spec; size_t image_size = 0; int io_result = IO_FAIL; assert(image_name != NULL); /* Obtain a reference to the image by querying the platform layer */ io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); if (io_result != IO_SUCCESS) { WARN("Failed to obtain reference to image '%s' (%i)\n", image_name, io_result); return 0; } /* Attempt to access the image */ io_result = io_open(dev_handle, image_spec, &image_handle); if (io_result != IO_SUCCESS) { WARN("Failed to access image '%s' (%i)\n", image_name, io_result); return 0; } /* Find the size of the image */ io_result = io_size(image_handle, &image_size); if ((io_result != IO_SUCCESS) || (image_size == 0)) { WARN("Failed to determine the size of the image '%s' file (%i)\n", image_name, io_result); } io_result = io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this * bootloader stage */ io_result = io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return image_size; }
/* Do some basic package checks. */ static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) { int result = IO_FAIL; char *image_name = (char *)init_params; uintptr_t backend_handle; fip_toc_header_t header; size_t bytes_read; /* Obtain a reference to the image by querying the platform layer */ result = plat_get_image_source(image_name, &backend_dev_handle, &backend_image_spec); if (result != IO_SUCCESS) { WARN("Failed to obtain reference to image '%s' (%i)\n", image_name, result); result = IO_FAIL; goto fip_dev_init_exit; } /* Attempt to access the FIP image */ result = io_open(backend_dev_handle, backend_image_spec, &backend_handle); if (result != IO_SUCCESS) { WARN("Failed to access image '%s' (%i)\n", image_name, result); result = IO_FAIL; goto fip_dev_init_exit; } result = io_read(backend_handle, (uintptr_t)&header, sizeof(header), &bytes_read); if (result == IO_SUCCESS) { if (!is_valid_header(&header)) { WARN("Firmware Image Package header check failed.\n"); result = IO_FAIL; } else { INFO("FIP header looks OK.\n"); } } io_close(backend_handle); fip_dev_init_exit: return result; }
/* Generic function to return the size of an image */ size_t get_image_size(unsigned int image_id) { uintptr_t dev_handle; uintptr_t image_handle; uintptr_t image_spec; size_t image_size = 0U; int io_result; /* 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 0; } /* 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 0; } /* 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); } io_result = io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this * bootloader stage */ io_result = io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return image_size; }
int load_partition_table(unsigned int image_id) { uintptr_t dev_handle, image_handle, image_spec = 0; mbr_entry_t mbr_entry; int result; result = plat_get_image_source(image_id, &dev_handle, &image_spec); if (result != 0) { WARN("Failed to obtain reference to image id=%u (%i)\n", image_id, result); return result; } result = io_open(dev_handle, image_spec, &image_handle); if (result != 0) { WARN("Failed to access image id=%u (%i)\n", image_id, result); return result; } result = load_mbr_header(image_handle, &mbr_entry); if (result != 0) { WARN("Failed to access image id=%u (%i)\n", image_id, result); return result; } if (mbr_entry.type == PARTITION_TYPE_GPT) { result = load_gpt_header(image_handle); assert(result == 0); result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); assert(result == 0); result = verify_partition_gpt(image_handle); } else { /* MBR type isn't supported yet. */ result = -EINVAL; goto exit; } exit: io_close(image_handle); return result; }
/******************************************************************************* * Generic function to load an image into the trusted RAM, * given a name, extents of free memory & whether the image should be loaded at * the bottom or top of the free memory. It updates the memory layout if the * load is successful. ******************************************************************************/ unsigned long load_image(meminfo *mem_layout, const char *image_name, unsigned int load_type, unsigned long fixed_addr) { io_dev_handle dev_handle; io_handle image_handle; void *image_spec; unsigned long temp_image_base = 0; unsigned long image_base = 0; long offset = 0; size_t image_size = 0; size_t bytes_read = 0; int io_result = IO_FAIL; assert(mem_layout != NULL); assert(image_name != NULL); /* Obtain a reference to the image by querying the platform layer */ io_result = plat_get_image_source(image_name, &dev_handle, &image_spec); if (io_result != IO_SUCCESS) { WARN("Failed to obtain reference to image '%s' (%i)\n", image_name, io_result); return 0; } /* Attempt to access the image */ io_result = io_open(dev_handle, image_spec, &image_handle); if (io_result != IO_SUCCESS) { WARN("Failed to access image '%s' (%i)\n", image_name, io_result); return 0; } /* Find the size of the image */ io_result = io_size(image_handle, &image_size); if ((io_result != IO_SUCCESS) || (image_size == 0)) { WARN("Failed to determine the size of the image '%s' file (%i)\n", image_name, io_result); goto fail; } /* See if we have enough space */ if (image_size > mem_layout->free_size) { WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(0, image_size, mem_layout); goto fail; } switch (load_type) { case TOP_LOAD: /* Load the image in the top of free memory */ temp_image_base = mem_layout->free_base + mem_layout->free_size; temp_image_base -= image_size; /* Page align base address and check whether the image still fits */ image_base = page_align(temp_image_base, DOWN); assert(image_base <= temp_image_base); if (image_base < mem_layout->free_base) { WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(image_base, image_size, mem_layout); goto fail; } /* Calculate the amount of extra memory used due to alignment */ offset = temp_image_base - image_base; break; case BOT_LOAD: /* Load the BL2 image in the bottom of free memory */ temp_image_base = mem_layout->free_base; image_base = page_align(temp_image_base, UP); assert(image_base >= temp_image_base); /* Page align base address and check whether the image still fits */ if (image_base + image_size > mem_layout->free_base + mem_layout->free_size) { WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(image_base, image_size, mem_layout); goto fail; } /* Calculate the amount of extra memory used due to alignment */ offset = image_base - temp_image_base; break; default: assert(0); } /* * Some images must be loaded at a fixed address, not a dynamic one. * * This has been implemented as a hack on top of the existing dynamic * loading mechanism, for the time being. If the 'fixed_addr' function * argument is different from zero, then it will force the load address. * So we still have this principle of top/bottom loading but the code * determining the load address is bypassed and the load address is * forced to the fixed one. * * This can result in quite a lot of wasted space because we still use * 1 sole meminfo structure to represent the extents of free memory, * where we should use some sort of linked list. * * E.g. we want to load BL2 at address 0x04020000, the resulting memory * layout should look as follows: * ------------ 0x04040000 * | | <- Free space (1) * |----------| * | BL2 | * |----------| 0x04020000 * | | <- Free space (2) * |----------| * | BL1 | * ------------ 0x04000000 * * But in the current hacky implementation, we'll need to specify * whether BL2 is loaded at the top or bottom of the free memory. * E.g. if BL2 is considered as top-loaded, the meminfo structure * will give the following view of the memory, hiding the chunk of * free memory above BL2: * ------------ 0x04040000 * | | * | | * | BL2 | * |----------| 0x04020000 * | | <- Free space (2) * |----------| * | BL1 | * ------------ 0x04000000 */ if (fixed_addr != 0) { /* Load the image at the given address. */ image_base = fixed_addr; /* Check whether the image fits. */ if ((image_base < mem_layout->free_base) || (image_base + image_size > mem_layout->free_base + mem_layout->free_size)) { WARN("Cannot load '%s' file: Not enough space.\n", image_name); dump_load_info(image_base, image_size, mem_layout); goto fail; } /* Check whether the fixed load address is page-aligned. */ if (!is_page_aligned(image_base)) { WARN("Cannot load '%s' file at unaligned address 0x%lx\n", image_name, fixed_addr); goto fail; } /* * Calculate the amount of extra memory used due to fixed * loading. */ if (load_type == TOP_LOAD) { unsigned long max_addr, space_used; /* * ------------ max_addr * | /wasted/ | | offset * |..........|.............................. * | image | | image_flen * |----------| fixed_addr * | | * | | * ------------ total_base */ max_addr = mem_layout->total_base + mem_layout->total_size; /* * Compute the amount of memory used by the image. * Corresponds to all space above the image load * address. */ space_used = max_addr - fixed_addr; /* * Calculate the amount of wasted memory within the * amount of memory used by the image. */ offset = space_used - image_size; } else /* BOT_LOAD */ /* * ------------ * | | * | | * |----------| * | image | * |..........| fixed_addr * | /wasted/ | | offset * ------------ total_base */ offset = fixed_addr - mem_layout->total_base; } /* 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, (void *)image_base, image_size, &bytes_read); if ((io_result != IO_SUCCESS) || (bytes_read < image_size)) { WARN("Failed to load '%s' file (%i)\n", image_name, io_result); goto fail; } /* * File has been successfully loaded. Update the free memory * data structure & flush the contents of the TZRAM so that * the next EL can see it. */ /* Update the memory contents */ flush_dcache_range(image_base, image_size); mem_layout->free_size -= image_size + offset; /* Update the base of free memory since its moved up */ if (load_type == BOT_LOAD) mem_layout->free_base += offset + image_size; exit: io_result = io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ io_result = io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return image_base; fail: image_base = 0; goto exit; }
/******************************************************************************* * Generic function to load an image at a specific address given a name and * extents of free memory. It updates the memory layout if the load is * successful, as well as the image information and the entry point information. * The caller might pass a NULL pointer for the entry point if it is not * interested in this information, e.g. because the image just needs to be * loaded in memory but won't ever be executed. * Returns 0 on success, a negative error code otherwise. ******************************************************************************/ int load_image(meminfo_t *mem_layout, unsigned int image_id, uintptr_t image_base, image_info_t *image_data, entry_point_info_t *entry_point_info) { uintptr_t dev_handle; uintptr_t image_handle; uintptr_t image_spec; size_t image_size; size_t bytes_read; int io_result = IO_FAIL; assert(mem_layout != NULL); assert(image_data != NULL); assert(image_data->h.version >= VERSION_1); /* 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 != IO_SUCCESS) { 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 != IO_SUCCESS) { 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 != IO_SUCCESS) || (image_size == 0)) { WARN("Failed to determine the size of the image id=%u (%i)\n", image_id, io_result); goto exit; } /* Check that the memory where the image will be loaded is free */ if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, image_base, image_size)) { WARN("Failed to reserve memory: 0x%lx - 0x%lx\n", image_base, image_base + image_size); dump_load_info(image_base, image_size, mem_layout); io_result = -ENOMEM; goto exit; } /* 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 != IO_SUCCESS) || (bytes_read < image_size)) { WARN("Failed to load image id=%u (%i)\n", image_id, io_result); goto exit; } /* * Update the memory usage info. * This is done after the actual loading so that it is not updated when * the load is unsuccessful. * If the caller does not provide an entry point, bypass the memory * reservation. */ if (entry_point_info != NULL) { reserve_mem(&mem_layout->free_base, &mem_layout->free_size, image_base, image_size); } else { INFO("Skip reserving memory: 0x%lx - 0x%lx\n", image_base, image_base + image_size); } image_data->image_base = image_base; image_data->image_size = image_size; if (entry_point_info != NULL) entry_point_info->pc = image_base; /* * File has been successfully loaded. * Flush the image in TZRAM so that the next EL can see it. */ flush_dcache_range(image_base, image_size); INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base, image_base + image_size); exit: io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return io_result; }
/******************************************************************************* * Generic 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. * * If the entry_point_info argument is not NULL then this function also updates: * - the memory layout to mark the memory as reserved; * - the entry point information. * * The caller might pass a NULL pointer for the entry point if they are not * interested in this information. This is typically the case for non-executable * images (e.g. certificates) and executable images that won't ever be executed * on the application processor (e.g. additional microcontroller firmware). * * Returns 0 on success, a negative error code otherwise. ******************************************************************************/ int load_image(meminfo_t *mem_layout, unsigned int image_id, uintptr_t image_base, image_info_t *image_data, entry_point_info_t *entry_point_info) { uintptr_t dev_handle; uintptr_t image_handle; uintptr_t image_spec; size_t image_size; size_t bytes_read; int io_result; assert(mem_layout != NULL); assert(image_data != NULL); assert(image_data->h.version == VERSION_1); /* 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 %p\n", image_id, (void *) image_base); /* Find the size of the image */ io_result = io_size(image_handle, &image_size); if ((io_result != 0) || (image_size == 0)) { WARN("Failed to determine the size of the image id=%u (%i)\n", image_id, io_result); goto exit; } /* Check that the memory where the image will be loaded is free */ if (!is_mem_free(mem_layout->free_base, mem_layout->free_size, image_base, image_size)) { WARN("Failed to reserve region [base = %p, size = 0x%zx]\n", (void *) image_base, image_size); dump_load_info(image_base, image_size, mem_layout); io_result = -ENOMEM; goto exit; } /* 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; } image_data->image_base = image_base; image_data->image_size = image_size; /* * Update the memory usage info. * This is done after the actual loading so that it is not updated when * the load is unsuccessful. * If the caller does not provide an entry point, bypass the memory * reservation. */ if (entry_point_info != NULL) { reserve_mem(&mem_layout->free_base, &mem_layout->free_size, image_base, image_size); entry_point_info->pc = image_base; } else { INFO("Skip reserving region [base = %p, size = 0x%zx]\n", (void *) image_base, image_size); } #if !TRUSTED_BOARD_BOOT /* * File has been successfully loaded. * Flush the image to main memory so that it can be executed later by * any CPU, regardless of cache and MMU state. * When TBB is enabled the image is flushed later, after image * authentication. */ flush_dcache_range(image_base, image_size); #endif /* TRUSTED_BOARD_BOOT */ INFO("Image id=%u loaded at address %p, size = 0x%zx\n", image_id, (void *) image_base, image_size); exit: io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return io_result; }
/******************************************************************************* * Generic 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. ******************************************************************************/ 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 %p\n", image_id, (void *) image_base); /* Find the size of the image */ io_result = io_size(image_handle, &image_size); if ((io_result != 0) || (image_size == 0)) { 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_size = 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; } #if !TRUSTED_BOARD_BOOT /* * File has been successfully loaded. * Flush the image to main memory so that it can be executed later by * any CPU, regardless of cache and MMU state. * When TBB is enabled the image is flushed later, after image * authentication. */ flush_dcache_range(image_base, image_size); #endif /* TRUSTED_BOARD_BOOT */ INFO("Image id=%u loaded: %p - %p\n", image_id, (void *) image_base, (void *) (image_base + image_size)); exit: io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return io_result; }
/******************************************************************************* * 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; }