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