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