bl_common.c 9.3 KB
Newer Older
1
/*
2
 * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
4
 * SPDX-License-Identifier: BSD-3-Clause
5
6
 */

7
#include <arch.h>
8
#include <arch_helpers.h>
9
#include <assert.h>
10
#include <auth_mod.h>
11
#include <bl_common.h>
12
#include <debug.h>
13
#include <errno.h>
14
15
#include <io_storage.h>
#include <platform.h>
16
#include <string.h>
17
#include <utils.h>
18
#include <xlat_tables_defs.h>
19

20
21
22
23
24
25
#if TRUSTED_BOARD_BOOT
# ifdef DYN_DISABLE_AUTH
static int disable_auth;

/******************************************************************************
 * API to dynamically disable authentication. Only meant for development
26
 * systems. This is only invoked if DYN_DISABLE_AUTH is defined.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 *****************************************************************************/
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 */

48
uintptr_t page_align(uintptr_t value, unsigned dir)
49
50
{
	/* Round up the limit to the next page boundary */
51
52
	if (value & (PAGE_SIZE - 1)) {
		value &= ~(PAGE_SIZE - 1);
53
		if (dir == UP)
54
			value += PAGE_SIZE;
55
56
57
58
59
	}

	return value;
}

60
61
62
/******************************************************************************
 * Determine whether the memory region delimited by 'addr' and 'size' is free,
 * given the extents of free memory.
63
64
 * Return 1 if it is free, 0 if it is not free or if the input values are
 * invalid.
65
 *****************************************************************************/
66
int is_mem_free(uintptr_t free_base, size_t free_size,
67
		uintptr_t addr, size_t size)
68
{
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
	uintptr_t free_end, requested_end;

	/*
	 * Handle corner cases first.
	 *
	 * The order of the 2 tests is important, because if there's no space
	 * left (i.e. free_size == 0) but we don't ask for any memory
	 * (i.e. size == 0) then we should report that the memory is free.
	 */
	if (size == 0)
		return 1;	/* A zero-byte region is always free */
	if (free_size == 0)
		return 0;

	/*
	 * Check that the end addresses don't overflow.
	 * If they do, consider that this memory region is not free, as this
	 * is an invalid scenario.
	 */
	if (check_uptr_overflow(free_base, free_size - 1))
		return 0;
	free_end = free_base + (free_size - 1);

	if (check_uptr_overflow(addr, size - 1))
		return 0;
	requested_end = addr + (size - 1);

	/*
	 * Finally, check that the requested memory region lies within the free
	 * region.
	 */
	return (addr >= free_base) && (requested_end <= free_end);
101
}
102

Ryan Harkin's avatar
Ryan Harkin committed
103
/* Generic function to return the size of an image */
Daniel Boulby's avatar
Daniel Boulby committed
104
size_t get_image_size(unsigned int image_id)
Ryan Harkin's avatar
Ryan Harkin committed
105
{
106
107
108
	uintptr_t dev_handle;
	uintptr_t image_handle;
	uintptr_t image_spec;
Ryan Harkin's avatar
Ryan Harkin committed
109
	size_t image_size = 0;
110
	int io_result;
Ryan Harkin's avatar
Ryan Harkin committed
111
112

	/* Obtain a reference to the image by querying the platform layer */
113
	io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
114
	if (io_result != 0) {
115
116
		WARN("Failed to obtain reference to image id=%u (%i)\n",
			image_id, io_result);
Ryan Harkin's avatar
Ryan Harkin committed
117
118
119
120
121
		return 0;
	}

	/* Attempt to access the image */
	io_result = io_open(dev_handle, image_spec, &image_handle);
122
	if (io_result != 0) {
123
124
		WARN("Failed to access image id=%u (%i)\n",
			image_id, io_result);
Ryan Harkin's avatar
Ryan Harkin committed
125
126
127
128
129
		return 0;
	}

	/* Find the size of the image */
	io_result = io_size(image_handle, &image_size);
130
	if ((io_result != 0) || (image_size == 0)) {
131
132
		WARN("Failed to determine the size of the image id=%u (%i)\n",
			image_id, io_result);
Ryan Harkin's avatar
Ryan Harkin committed
133
134
135
136
137
138
139
140
141
142
143
144
	}
	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;
}
145

146
/*******************************************************************************
147
 * Internal function to load an image at a specific address given
148
149
150
151
152
153
 * 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.
 ******************************************************************************/
154
static int load_image(unsigned int image_id, image_info_t *image_data)
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
{
	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;
	}

	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;
}

227
228
229
static int load_auth_image_internal(unsigned int image_id,
				    image_info_t *image_data,
				    int is_parent_image)
230
231
232
233
{
	int rc;

#if TRUSTED_BOARD_BOOT
234
235
236
237
238
239
240
241
242
243
	if (dyn_is_auth_disabled() == 0) {
		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_internal(parent_id, image_data, 1);
			if (rc != 0) {
				return rc;
			}
244
245
246
247
248
249
250
251
252
253
254
		}
	}
#endif /* TRUSTED_BOARD_BOOT */

	/* Load the image */
	rc = load_image(image_id, image_data);
	if (rc != 0) {
		return rc;
	}

#if TRUSTED_BOARD_BOOT
255
256
257
258
259
260
261
262
263
264
265
266
267
	if (dyn_is_auth_disabled() == 0) {
		/* 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;
		}
268
	}
269
#endif /* TRUSTED_BOARD_BOOT */
270
271
272

	/*
	 * Flush the image to main memory so that it can be executed later by
273
274
275
	 * any CPU, regardless of cache and MMU state. If TBB is enabled, then
	 * the file has been successfully loaded and authenticated and flush
	 * only for child images, not for the parents (certificates).
276
	 */
277
278
279
280
	if (!is_parent_image) {
		flush_dcache_range(image_data->image_base,
				   image_data->image_size);
	}
281

282
283
284
285

	return 0;
}

286
287
288
289
290
291
292
293
294
/*******************************************************************************
 * 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.
 ******************************************************************************/
int load_auth_image(unsigned int image_id, image_info_t *image_data)
{
295
296
297
298
299
300
301
	int err;

	do {
		err = load_auth_image_internal(image_id, image_data, 0);
	} while (err != 0 && plat_try_next_boot_source());

	return err;
302
303
}

304
305
306
307
308
/*******************************************************************************
 * Print the content of an entry_point_info_t structure.
 ******************************************************************************/
void print_entry_point_info(const entry_point_info_t *ep_info)
{
309
310
	INFO("Entry point address = %p\n", (void *)ep_info->pc);
	INFO("SPSR = 0x%x\n", ep_info->spsr);
311
312
313
314
315
316
317
318
319

#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);
320
#ifndef AARCH32
321
322
323
324
	PRINT_IMAGE_ARG(4);
	PRINT_IMAGE_ARG(5);
	PRINT_IMAGE_ARG(6);
	PRINT_IMAGE_ARG(7);
325
#endif
326
327
#undef PRINT_IMAGE_ARG
}