• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10 
11 #include <arch.h>
12 #include <arch_features.h>
13 #include <arch_helpers.h>
14 #include <common/bl_common.h>
15 #include <common/debug.h>
16 #include <drivers/auth/auth_mod.h>
17 #include <drivers/io/io_storage.h>
18 #include <lib/utils.h>
19 #include <lib/xlat_tables/xlat_tables_defs.h>
20 #include <plat/common/platform.h>
21 
22 #if TRUSTED_BOARD_BOOT
23 # ifdef DYN_DISABLE_AUTH
24 static int disable_auth;
25 
26 /******************************************************************************
27  * API to dynamically disable authentication. Only meant for development
28  * systems. This is only invoked if DYN_DISABLE_AUTH is defined.
29  *****************************************************************************/
dyn_disable_auth(void)30 void dyn_disable_auth(void)
31 {
32 	INFO("Disabling authentication of images dynamically\n");
33 	disable_auth = 1;
34 }
35 # endif /* DYN_DISABLE_AUTH */
36 
37 /******************************************************************************
38  * Function to determine whether the authentication is disabled dynamically.
39  *****************************************************************************/
dyn_is_auth_disabled(void)40 static int dyn_is_auth_disabled(void)
41 {
42 # ifdef DYN_DISABLE_AUTH
43 	return disable_auth;
44 # else
45 	return 0;
46 # endif
47 }
48 #endif /* TRUSTED_BOARD_BOOT */
49 
page_align(uintptr_t value,unsigned dir)50 uintptr_t page_align(uintptr_t value, unsigned dir)
51 {
52 	/* Round up the limit to the next page boundary */
53 	if ((value & PAGE_SIZE_MASK) != 0U) {
54 		value &= ~PAGE_SIZE_MASK;
55 		if (dir == UP)
56 			value += PAGE_SIZE;
57 	}
58 
59 	return value;
60 }
61 
62 /*******************************************************************************
63  * Internal function to load an image at a specific address given
64  * an image ID and extents of free memory.
65  *
66  * If the load is successful then the image information is updated.
67  *
68  * Returns 0 on success, a negative error code otherwise.
69  ******************************************************************************/
load_image(unsigned int image_id,image_info_t * image_data)70 static int load_image(unsigned int image_id, image_info_t *image_data)
71 {
72 	uintptr_t dev_handle;
73 	uintptr_t image_handle;
74 	uintptr_t image_spec;
75 	uintptr_t image_base;
76 	size_t image_size;
77 	size_t bytes_read;
78 	int io_result;
79 
80 	assert(image_data != NULL);
81 	assert(image_data->h.version >= VERSION_2);
82 
83 	image_base = image_data->image_base;
84 
85 	/* Obtain a reference to the image by querying the platform layer */
86 	io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
87 	if (io_result != 0) {
88 		WARN("Failed to obtain reference to image id=%u (%i)\n",
89 			image_id, io_result);
90 		return io_result;
91 	}
92 
93 	/* Attempt to access the image */
94 	io_result = io_open(dev_handle, image_spec, &image_handle);
95 	if (io_result != 0) {
96 		WARN("Failed to access image id=%u (%i)\n",
97 			image_id, io_result);
98 		return io_result;
99 	}
100 
101 	INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base);
102 
103 	/* Find the size of the image */
104 	io_result = io_size(image_handle, &image_size);
105 	if ((io_result != 0) || (image_size == 0U)) {
106 		WARN("Failed to determine the size of the image id=%u (%i)\n",
107 			image_id, io_result);
108 		goto exit;
109 	}
110 
111 	/* Check that the image size to load is within limit */
112 	if (image_size > image_data->image_max_size) {
113 		WARN("Image id=%u size out of bounds\n", image_id);
114 		io_result = -EFBIG;
115 		goto exit;
116 	}
117 
118 	/*
119 	 * image_data->image_max_size is a uint32_t so image_size will always
120 	 * fit in image_data->image_size.
121 	 */
122 	image_data->image_size = (uint32_t)image_size;
123 
124 	/* We have enough space so load the image now */
125 	/* TODO: Consider whether to try to recover/retry a partially successful read */
126 	io_result = io_read(image_handle, image_base, image_size, &bytes_read);
127 	if ((io_result != 0) || (bytes_read < image_size)) {
128 		WARN("Failed to load image id=%u (%i)\n", image_id, io_result);
129 		goto exit;
130 	}
131 
132 	INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base,
133 	     (uintptr_t)(image_base + image_size));
134 
135 exit:
136 	(void)io_close(image_handle);
137 	/* Ignore improbable/unrecoverable error in 'close' */
138 
139 	/* TODO: Consider maintaining open device connection from this bootloader stage */
140 	(void)io_dev_close(dev_handle);
141 	/* Ignore improbable/unrecoverable error in 'dev_close' */
142 
143 	return io_result;
144 }
145 
146 /*
147  * Load an image and flush it out to main memory so that it can be executed
148  * later by any CPU, regardless of cache and MMU state.
149  */
load_image_flush(unsigned int image_id,image_info_t * image_data)150 static int load_image_flush(unsigned int image_id,
151 			    image_info_t *image_data)
152 {
153 	int rc;
154 
155 	rc = load_image(image_id, image_data);
156 	if (rc == 0) {
157 		flush_dcache_range(image_data->image_base,
158 				   image_data->image_size);
159 	}
160 
161 	return rc;
162 }
163 
164 
165 #if TRUSTED_BOARD_BOOT
166 /*
167  * This function uses recursion to authenticate the parent images up to the root
168  * of trust.
169  */
load_auth_image_recursive(unsigned int image_id,image_info_t * image_data,int is_parent_image)170 static int load_auth_image_recursive(unsigned int image_id,
171 				    image_info_t *image_data,
172 				    int is_parent_image)
173 {
174 	int rc;
175 	unsigned int parent_id;
176 
177 	/* Use recursion to authenticate parent images */
178 	rc = auth_mod_get_parent_id(image_id, &parent_id);
179 	if (rc == 0) {
180 		rc = load_auth_image_recursive(parent_id, image_data, 1);
181 		if (rc != 0) {
182 			return rc;
183 		}
184 	}
185 
186 	/* Load the image */
187 	rc = load_image(image_id, image_data);
188 	if (rc != 0) {
189 		return rc;
190 	}
191 
192 	/* Authenticate it */
193 	rc = auth_mod_verify_img(image_id,
194 				 (void *)image_data->image_base,
195 				 image_data->image_size);
196 	if (rc != 0) {
197 		/* Authentication error, zero memory and flush it right away. */
198 		zero_normalmem((void *)image_data->image_base,
199 			       image_data->image_size);
200 		flush_dcache_range(image_data->image_base,
201 				   image_data->image_size);
202 		return -EAUTH;
203 	}
204 
205 	if (is_parent_image == 0) {
206 		/*
207 		 * Measure the image.
208 		 * We do not measure its parents because these only play a role
209 		 * in authentication, which is orthogonal to measured boot.
210 		 *
211 		 * TODO: Change this code if we change our minds about measuring
212 		 * certificates.
213 		 */
214 		rc = plat_mboot_measure_image(image_id, image_data);
215 		if (rc != 0) {
216 			return rc;
217 		}
218 
219 		/*
220 		 * Flush the image to main memory so that it can be executed
221 		 * later by any CPU, regardless of cache and MMU state. This
222 		 * is only needed for child images, not for the parents
223 		 * (certificates).
224 		 */
225 		flush_dcache_range(image_data->image_base,
226 				   image_data->image_size);
227 	}
228 
229 	return 0;
230 }
231 #endif /* TRUSTED_BOARD_BOOT */
232 
load_auth_image_internal(unsigned int image_id,image_info_t * image_data)233 static int load_auth_image_internal(unsigned int image_id,
234 				    image_info_t *image_data)
235 {
236 #if TRUSTED_BOARD_BOOT
237 	if (dyn_is_auth_disabled() == 0) {
238 		return load_auth_image_recursive(image_id, image_data, 0);
239 	}
240 #endif
241 
242 	return load_image_flush(image_id, image_data);
243 }
244 
245 /*******************************************************************************
246  * Generic function to load and authenticate an image. The image is actually
247  * loaded by calling the 'load_image()' function. Therefore, it returns the
248  * same error codes if the loading operation failed, or -EAUTH if the
249  * authentication failed. In addition, this function uses recursion to
250  * authenticate the parent images up to the root of trust (if TBB is enabled).
251  ******************************************************************************/
load_auth_image(unsigned int image_id,image_info_t * image_data)252 int load_auth_image(unsigned int image_id, image_info_t *image_data)
253 {
254 	int err;
255 
256 /*
257  * All firmware banks should be part of the same non-volatile storage as per
258  * PSA FWU specification, hence don't check for any alternate boot source
259  * when PSA FWU is enabled.
260  */
261 #if PSA_FWU_SUPPORT
262 	err = load_auth_image_internal(image_id, image_data);
263 #else
264 	do {
265 		err = load_auth_image_internal(image_id, image_data);
266 	} while ((err != 0) && (plat_try_next_boot_source() != 0));
267 #endif /* PSA_FWU_SUPPORT */
268 
269 	return err;
270 }
271 
272 /*******************************************************************************
273  * Print the content of an entry_point_info_t structure.
274  ******************************************************************************/
print_entry_point_info(const entry_point_info_t * ep_info)275 void print_entry_point_info(const entry_point_info_t *ep_info)
276 {
277 	INFO("Entry point address = 0x%lx\n", ep_info->pc);
278 	INFO("SPSR = 0x%x\n", ep_info->spsr);
279 
280 #define PRINT_IMAGE_ARG(n)					\
281 	VERBOSE("Argument #" #n " = 0x%llx\n",			\
282 		(unsigned long long) ep_info->args.arg##n)
283 
284 	PRINT_IMAGE_ARG(0);
285 	PRINT_IMAGE_ARG(1);
286 	PRINT_IMAGE_ARG(2);
287 	PRINT_IMAGE_ARG(3);
288 #ifdef __aarch64__
289 	PRINT_IMAGE_ARG(4);
290 	PRINT_IMAGE_ARG(5);
291 	PRINT_IMAGE_ARG(6);
292 	PRINT_IMAGE_ARG(7);
293 #endif
294 #undef PRINT_IMAGE_ARG
295 }
296