xref: /rk3399_ARM-atf/common/bl_common.c (revision ed51b51f7a9163a7fc48289c5ed97a3fe4fe504f)
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