Esempio n. 1
0
/******************************************************************************
 * Reserve the memory region delimited by 'addr' and 'size'. The extents of free
 * memory are passed in 'free_base' and 'free_size' and they will be updated to
 * reflect the memory usage.
 * The caller must ensure the memory to reserve is free.
 *****************************************************************************/
void reserve_mem(uint64_t *free_base, size_t *free_size,
		 uint64_t addr, size_t size)
{
	size_t discard_size;
	size_t reserved_size;
	unsigned int pos;

	assert(free_base != NULL);
	assert(free_size != NULL);
	assert(is_mem_free(*free_base, *free_size, addr, size));

	pos = choose_mem_pos(*free_base, *free_base + *free_size,
			     addr, addr + size,
			     &discard_size);

	reserved_size = size + discard_size;
	*free_size -= reserved_size;

	if (pos == BOTTOM)
		*free_base = addr + size;

	VERBOSE("Reserved 0x%lx bytes (discarded 0x%lx bytes %s)\n",
	     reserved_size, discard_size,
	     pos == TOP ? "above" : "below");
}
Esempio n. 2
0
/******************************************************************************
 * Reserve the memory region delimited by 'addr' and 'size'. The extents of free
 * memory are passed in 'free_base' and 'free_size' and they will be updated to
 * reflect the memory usage.
 * The caller must ensure the memory to reserve is free and that the addresses
 * and sizes passed in arguments are sane.
 *****************************************************************************/
void reserve_mem(uintptr_t *free_base, size_t *free_size,
		 uintptr_t addr, size_t size)
{
	size_t discard_size;
	size_t reserved_size;
	unsigned int pos;

	assert(free_base != NULL);
	assert(free_size != NULL);
	assert(is_mem_free(*free_base, *free_size, addr, size));

	if (size == 0) {
		WARN("Nothing to allocate, requested size is zero\n");
		return;
	}

	pos = choose_mem_pos(*free_base, *free_base + (*free_size - 1),
			     addr, addr + (size - 1),
			     &discard_size);

	reserved_size = size + discard_size;
	*free_size -= reserved_size;

	if (pos == BOTTOM)
		*free_base = addr + size;

	VERBOSE("Reserved 0x%zx bytes (discarded 0x%zx bytes %s)\n",
	     reserved_size, discard_size,
	     pos == TOP ? "above" : "below");
}
Esempio n. 3
0
/*******************************************************************************
 * OPTEE Dispatcher setup. The OPTEED finds out the OPTEE entrypoint and type
 * (aarch32/aarch64) if not already known and initialises the context for entry
 * into OPTEE for its initialization.
 ******************************************************************************/
int32_t opteed_setup(void)
{
	entry_point_info_t *ep_info;
	struct optee_header *header;
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id;
	uintptr_t init_load_addr;
	size_t init_size;
	size_t init_mem_usage;
	uintptr_t payload_addr;
	uintptr_t mem_limit;
	uintptr_t paged_part;
	uintptr_t paged_size;

	linear_id = platform_get_core_pos(mpidr);

	/*
	 * Get information about the Secure Payload (BL32) image. Its
	 * absence is a critical failure.  TODO: Add support to
	 * conditionally include the SPD service
	 */
	ep_info = bl31_plat_get_next_image_ep_info(SECURE);
	if (!ep_info) {
		WARN("No OPTEE provided by BL2 boot loader.\n");
		goto err;
	}

	header = (struct optee_header *)ep_info->pc;

	if (header->magic != OPTEE_MAGIC || header->version != OPTEE_VERSION) {
		WARN("Invalid OPTEE header.\n");
		goto err;
	}

	if (header->arch == OPTEE_ARCH_ARM32)
		opteed_rw = OPTEE_AARCH32;
	else if (header->arch == OPTEE_ARCH_ARM64)
		opteed_rw = OPTEE_AARCH64;
	else {
		WARN("Invalid OPTEE architecture (%d)\n", header->arch);
		goto err;
	}

	init_load_addr = ((uint64_t)header->init_load_addr_hi << 32) |
				header->init_load_addr_lo;
	init_size = header->init_size;
	init_mem_usage = header->init_mem_usage;
	payload_addr = (uintptr_t)(header + 1);
	paged_size = header->paged_size;

	/*
	 * Move OPTEE binary to the required location in memory.
	 *
	 * There's two ways OPTEE can be running in memory:
	 * 1. A memory large enough to keep the entire OPTEE binary
	 *    (DRAM currently)
	 * 2. A part of OPTEE in a smaller (and more secure) memory
	 *    (SRAM currently). This is achieved with demand paging
	 *    of read-only data/code against a backing store in some
	 *    larger memory (DRAM currently).
	 *
	 * In either case dictates init_load_addr in the OPTEE
	 * header the address where what's after the header
	 * (payload) should be residing when started. init_size in
	 * the header tells how much of the payload that need to be
	 * copied. init_mem_usage tells how much runtime memory in
	 * total is needed by OPTEE.
	 *
	 * In alternative 2 there's additional data after
	 * init_size, this is the rest of OPTEE which is demand
	 * paged into memory.  A pointer to that data is supplied
	 * to OPTEE when initializing.
	 *
	 * Alternative 1 only uses DRAM when executing OPTEE while
	 * alternative 2 uses both SRAM and DRAM to execute.
	 *
	 * All data written which is later read by OPTEE must be flushed
	 * out to memory since OPTEE starts with MMU turned off and caches
	 * disabled.
	 */
	if (is_mem_free(BL32_SRAM_BASE,
			 BL32_SRAM_LIMIT - BL32_SRAM_BASE,
			 init_load_addr, init_mem_usage)) {
		/* Running in SRAM, paging some code against DRAM */
		memcpy((void *)init_load_addr, (void *)payload_addr,
		       init_size);
		flush_dcache_range(init_load_addr, init_size);
		paged_part = payload_addr + init_size;
		mem_limit = BL32_SRAM_LIMIT;
	} else if (is_mem_free(BL32_DRAM_BASE,
			       BL32_DRAM_LIMIT - BL32_DRAM_BASE,
			       init_load_addr, init_mem_usage)) {
		/*
		 * Running in DRAM.
		 *
		 * The paged part normally empty, but if it isn't,
		 * move it to the end of DRAM before moving the
		 * init part in place.
		 */
		paged_part = BL32_DRAM_LIMIT - paged_size;
		if (paged_size) {
			if (!is_mem_free(BL32_DRAM_BASE,
					 BL32_DRAM_LIMIT - BL32_DRAM_BASE,
					 init_load_addr,
					 init_mem_usage + paged_size)) {
				WARN("Failed to reserve memory 0x%lx - 0x%lx\n",
				      init_load_addr,
				      init_load_addr + init_mem_usage +
					paged_size);
				goto err;
			}

			memcpy((void *)paged_part,
				(void *)(payload_addr + init_size),
				paged_size);
			flush_dcache_range(paged_part, paged_size);
		}

		memmove((void *)init_load_addr, (void *)payload_addr,
			init_size);
		flush_dcache_range(init_load_addr, init_size);
		mem_limit = BL32_DRAM_LIMIT;
	} else {
		WARN("Failed to reserve memory 0x%lx - 0x%lx\n",
			init_load_addr, init_load_addr + init_mem_usage);
		goto err;
	}


	opteed_init_optee_ep_state(ep_info, opteed_rw, init_load_addr,
				   paged_part, mem_limit,
				   &opteed_sp_context[linear_id]);

	/*
	 * All OPTEED initialization done. Now register our init function with
	 * BL31 for deferred invocation
	 */
	bl31_register_bl32_init(&opteed_init);

	return 0;

err:
	WARN("Booting device without OPTEE initialization.\n");
	WARN("SMC`s destined for OPTEE will return SMC_UNK\n");
	return 1;
}
Esempio n. 4
0
/*******************************************************************************
 * 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;
}
Esempio n. 5
0
/*******************************************************************************
 * 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;
}