bl_common.c 8.71 KB
Newer Older
1
/*
2
 * Copyright (c) 2013-2019, 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 <assert.h>
8
#include <errno.h>
9
#include <string.h>
10
11

#include <arch.h>
12
#include <arch_features.h>
13
14
15
16
17
18
19
20
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/io/io_storage.h>
#include <lib/utils.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
#include <plat/common/platform.h>
21

22
23
24
25
26
27
#if TRUSTED_BOARD_BOOT
# ifdef DYN_DISABLE_AUTH
static int disable_auth;

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

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

	return value;
}

62
/*******************************************************************************
63
 * Internal function to load an image at a specific address given
64
65
66
67
68
69
 * 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.
 ******************************************************************************/
70
static int load_image(unsigned int image_id, image_info_t *image_data)
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 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;
	}

101
	INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base);
102
103
104

	/* Find the size of the image */
	io_result = io_size(image_handle, &image_size);
105
	if ((io_result != 0) || (image_size == 0U)) {
106
107
108
109
110
111
112
113
114
115
116
117
		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;
	}

118
119
120
121
122
	/*
	 * 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;
123
124
125
126
127
128
129
130
131

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

132
133
	INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base,
	     (uintptr_t)(image_base + image_size));
134
135

exit:
136
	(void)io_close(image_handle);
137
138
139
	/* Ignore improbable/unrecoverable error in 'close' */

	/* TODO: Consider maintaining open device connection from this bootloader stage */
140
	(void)io_dev_close(dev_handle);
141
142
143
144
145
	/* Ignore improbable/unrecoverable error in 'dev_close' */

	return io_result;
}

146
147
148
static int load_auth_image_internal(unsigned int image_id,
				    image_info_t *image_data,
				    int is_parent_image)
149
150
151
152
{
	int rc;

#if TRUSTED_BOARD_BOOT
153
154
155
156
157
158
159
160
161
162
	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;
			}
163
164
165
166
167
168
169
170
171
172
173
		}
	}
#endif /* TRUSTED_BOARD_BOOT */

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

#if TRUSTED_BOARD_BOOT
174
175
176
177
178
179
180
181
182
183
184
185
186
	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;
		}
187
	}
188
#endif /* TRUSTED_BOARD_BOOT */
189
190
191

	/*
	 * Flush the image to main memory so that it can be executed later by
192
193
194
	 * 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).
195
	 */
196
	if (is_parent_image == 0) {
197
198
199
		flush_dcache_range(image_data->image_base,
				   image_data->image_size);
	}
200

201
202
203
204

	return 0;
}

205
206
207
208
209
210
211
212
213
/*******************************************************************************
 * 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)
{
214
215
216
217
	int err;

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

	return err;
221
222
}

223
224
225
226
227
/*******************************************************************************
 * Print the content of an entry_point_info_t structure.
 ******************************************************************************/
void print_entry_point_info(const entry_point_info_t *ep_info)
{
228
	INFO("Entry point address = 0x%lx\n", ep_info->pc);
229
	INFO("SPSR = 0x%x\n", ep_info->spsr);
230
231
232
233
234
235
236
237
238

#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);
239
#ifndef AARCH32
240
241
242
243
	PRINT_IMAGE_ARG(4);
	PRINT_IMAGE_ARG(5);
	PRINT_IMAGE_ARG(6);
	PRINT_IMAGE_ARG(7);
244
#endif
245
246
#undef PRINT_IMAGE_ARG
}
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296

#ifdef AARCH64
/*******************************************************************************
 * Handle all possible cases regarding ARMv8.3-PAuth.
 ******************************************************************************/
void bl_handle_pauth(void)
{
#if ENABLE_PAUTH
	/*
	 * ENABLE_PAUTH = 1 && CTX_INCLUDE_PAUTH_REGS = 1
	 *
	 * Check that the system supports address authentication to avoid
	 * getting an access fault when accessing the registers. This is all
	 * that is needed to check. If any of the authentication mechanisms is
	 * supported, the system knows about ARMv8.3-PAuth, so all the registers
	 * are available and accessing them won't generate a fault.
	 *
	 * Obtain 128-bit instruction key A from the platform and save it to the
	 * system registers. Pointer authentication can't be enabled here or the
	 * authentication will fail when returning from this function.
	 */
	assert(is_armv8_3_pauth_api_present());

	uint64_t *apiakey = plat_init_apiakey();

	write_apiakeylo_el1(apiakey[0]);
	write_apiakeyhi_el1(apiakey[1]);
#else /* if !ENABLE_PAUTH */

# if CTX_INCLUDE_PAUTH_REGS
	/*
	 * ENABLE_PAUTH = 0 && CTX_INCLUDE_PAUTH_REGS = 1
	 *
	 * Assert that the ARMv8.3-PAuth registers are present or an access
	 * fault will be triggered when they are being saved or restored.
	 */
	assert(is_armv8_3_pauth_present());
# else
	/*
	 * ENABLE_PAUTH = 0 && CTX_INCLUDE_PAUTH_REGS = 0
	 *
	 * Pointer authentication is allowed in the Non-secure world, but
	 * prohibited in the Secure world. The Trusted Firmware doesn't save the
	 * registers during a world switch. No check needed.
	 */
# endif /* CTX_INCLUDE_PAUTH_REGS */

#endif /* ENABLE_PAUTH */
}
#endif /* AARCH64 */