blob: b0985320e7fbc0eff2a5853559f75fc003d4c3ed [file] [log] [blame]
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +01001/*
Douglas Raillard21362a92016-12-02 13:51:54 +00002 * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +01005 */
6
7#include <assert.h>
8#include <arch_helpers.h>
9#include <auth_mod.h>
10#include <bl1.h>
11#include <bl_common.h>
12#include <context.h>
13#include <context_mgmt.h>
14#include <debug.h>
15#include <errno.h>
16#include <platform.h>
17#include <platform_def.h>
18#include <smcc_helpers.h>
19#include <string.h>
Sandrine Bailleuxb39d75f2016-11-11 16:44:37 +000020#include <utils.h>
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +010021#include "bl1_private.h"
22
23/*
24 * Function declarations.
25 */
26static int bl1_fwu_image_copy(unsigned int image_id,
27 uintptr_t image_addr,
28 unsigned int block_size,
29 unsigned int image_size,
30 unsigned int flags);
31static int bl1_fwu_image_auth(unsigned int image_id,
32 uintptr_t image_addr,
33 unsigned int image_size,
34 unsigned int flags);
35static int bl1_fwu_image_execute(unsigned int image_id,
36 void **handle,
37 unsigned int flags);
Dan Handley8ec76522015-12-15 10:52:33 +000038static register_t bl1_fwu_image_resume(register_t image_param,
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +010039 void **handle,
40 unsigned int flags);
41static int bl1_fwu_sec_image_done(void **handle,
42 unsigned int flags);
Dan Handley89f8f332015-12-15 14:28:24 +000043__dead2 static void bl1_fwu_done(void *client_cookie, void *reserved);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +010044
45/*
46 * This keeps track of last executed secure image id.
47 */
48static unsigned int sec_exec_image_id = INVALID_IMAGE_ID;
49
50/*******************************************************************************
51 * Top level handler for servicing FWU SMCs.
52 ******************************************************************************/
53register_t bl1_fwu_smc_handler(unsigned int smc_fid,
54 register_t x1,
55 register_t x2,
56 register_t x3,
57 register_t x4,
58 void *cookie,
59 void *handle,
60 unsigned int flags)
61{
62
63 switch (smc_fid) {
64 case FWU_SMC_IMAGE_COPY:
65 SMC_RET1(handle, bl1_fwu_image_copy(x1, x2, x3, x4, flags));
66
67 case FWU_SMC_IMAGE_AUTH:
68 SMC_RET1(handle, bl1_fwu_image_auth(x1, x2, x3, flags));
69
70 case FWU_SMC_IMAGE_EXECUTE:
71 SMC_RET1(handle, bl1_fwu_image_execute(x1, &handle, flags));
72
73 case FWU_SMC_IMAGE_RESUME:
Dan Handley8ec76522015-12-15 10:52:33 +000074 SMC_RET1(handle, bl1_fwu_image_resume(x1, &handle, flags));
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +010075
76 case FWU_SMC_SEC_IMAGE_DONE:
77 SMC_RET1(handle, bl1_fwu_sec_image_done(&handle, flags));
78
79 case FWU_SMC_UPDATE_DONE:
Dan Handley89f8f332015-12-15 14:28:24 +000080 bl1_fwu_done((void *)x1, NULL);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +010081 /* We should never return from bl1_fwu_done() */
82
83 default:
84 assert(0);
85 break;
86 }
87
Antonio Nino Diazacb29142017-04-04 17:08:32 +010088 SMC_RET1(handle, SMC_UNK);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +010089}
90
91/*******************************************************************************
92 * This function is responsible for copying secure images in AP Secure RAM.
93 ******************************************************************************/
94static int bl1_fwu_image_copy(unsigned int image_id,
95 uintptr_t image_src,
96 unsigned int block_size,
97 unsigned int image_size,
98 unsigned int flags)
99{
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000100 uintptr_t dest_addr;
Sandrine Bailleux953488e2016-11-14 14:56:51 +0000101 unsigned int remaining;
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100102
103 /* Get the image descriptor. */
104 image_desc_t *image_desc = bl1_plat_get_image_desc(image_id);
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000105 if (!image_desc) {
106 WARN("BL1-FWU: Invalid image ID %u\n", image_id);
107 return -EPERM;
108 }
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100109
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000110 /*
111 * The request must originate from a non-secure caller and target a
112 * secure image. Any other scenario is invalid.
113 */
114 if (GET_SECURITY_STATE(flags) == SECURE) {
115 WARN("BL1-FWU: Copy not allowed from secure world.\n");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100116 return -EPERM;
117 }
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000118 if (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == NON_SECURE) {
119 WARN("BL1-FWU: Copy not allowed for non-secure images.\n");
120 return -EPERM;
121 }
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100122
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000123 /* Check whether the FWU state machine is in the correct state. */
124 if ((image_desc->state != IMAGE_STATE_RESET) &&
125 (image_desc->state != IMAGE_STATE_COPYING)) {
126 WARN("BL1-FWU: Copy not allowed at this point of the FWU"
127 " process.\n");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100128 return -EPERM;
129 }
130
Sandrine Bailleuxb39d75f2016-11-11 16:44:37 +0000131 if ((!image_src) || (!block_size) ||
132 check_uptr_overflow(image_src, block_size - 1)) {
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100133 WARN("BL1-FWU: Copy not allowed due to invalid image source"
134 " or block size\n");
135 return -ENOMEM;
136 }
137
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100138 if (image_desc->state == IMAGE_STATE_COPYING) {
Sandrine Bailleuxbbc08222016-11-14 14:58:05 +0000139 /*
140 * There must have been at least 1 copy operation for this image
141 * previously.
142 */
143 assert(image_desc->copied_size != 0);
144 /*
145 * The image size must have been recorded in the 1st copy
146 * operation.
147 */
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000148 image_size = image_desc->image_info.image_size;
Sandrine Bailleuxbbc08222016-11-14 14:58:05 +0000149 assert(image_size != 0);
150 assert(image_desc->copied_size < image_size);
151
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100152 INFO("BL1-FWU: Continuing image copy in blocks\n");
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000153 } else { /* image_desc->state == IMAGE_STATE_RESET */
154 INFO("BL1-FWU: Initial call to copy an image\n");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100155
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000156 /*
157 * image_size is relevant only for the 1st copy request, it is
158 * then ignored for subsequent calls for this image.
159 */
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100160 if (!image_size) {
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000161 WARN("BL1-FWU: Copy not allowed due to invalid image"
162 " size\n");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100163 return -ENOMEM;
164 }
165
Yatharth Kochar8c0177f2016-11-11 13:57:50 +0000166#if LOAD_IMAGE_V2
167 /* Check that the image size to load is within limit */
168 if (image_size > image_desc->image_info.image_max_size) {
169 WARN("BL1-FWU: Image size out of bounds\n");
170 return -ENOMEM;
171 }
172#else
Sandrine Bailleuxb39d75f2016-11-11 16:44:37 +0000173 /*
174 * Check the image will fit into the free trusted RAM after BL1
175 * load.
176 */
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000177 const meminfo_t *mem_layout = bl1_plat_sec_mem_layout();
Sandrine Bailleuxb39d75f2016-11-11 16:44:37 +0000178 if (!is_mem_free(mem_layout->free_base, mem_layout->free_size,
179 image_desc->image_info.image_base,
180 image_size)) {
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000181 WARN("BL1-FWU: Copy not allowed due to insufficient"
182 " resources.\n");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100183 return -ENOMEM;
184 }
Yatharth Kochar8c0177f2016-11-11 13:57:50 +0000185#endif
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100186
Sandrine Bailleux5ebc21e2016-11-11 15:56:20 +0000187 /* Save the given image size. */
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100188 image_desc->image_info.image_size = image_size;
189
Sandrine Bailleux953488e2016-11-14 14:56:51 +0000190 /*
191 * copied_size must be explicitly initialized here because the
192 * FWU code doesn't necessarily do it when it resets the state
193 * machine.
194 */
195 image_desc->copied_size = 0;
196 }
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100197
Sandrine Bailleux953488e2016-11-14 14:56:51 +0000198 /*
199 * If the given block size is more than the total image size
200 * then clip the former to the latter.
201 */
202 remaining = image_size - image_desc->copied_size;
203 if (block_size > remaining) {
204 WARN("BL1-FWU: Block size is too big, clipping it.\n");
205 block_size = remaining;
206 }
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100207
Sandrine Bailleux953488e2016-11-14 14:56:51 +0000208 /* Make sure the source image is mapped in memory. */
209 if (bl1_plat_mem_check(image_src, block_size, flags)) {
210 WARN("BL1-FWU: Source image is not mapped.\n");
211 return -ENOMEM;
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100212 }
213
Sandrine Bailleux953488e2016-11-14 14:56:51 +0000214 /* Everything looks sane. Go ahead and copy the block of data. */
215 dest_addr = image_desc->image_info.image_base + image_desc->copied_size;
216 memcpy((void *) dest_addr, (const void *) image_src, block_size);
217 flush_dcache_range(dest_addr, block_size);
218
219 image_desc->copied_size += block_size;
220 image_desc->state = (block_size == remaining) ?
221 IMAGE_STATE_COPIED : IMAGE_STATE_COPYING;
222
223 INFO("BL1-FWU: Copy operation successful.\n");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100224 return 0;
225}
226
227/*******************************************************************************
228 * This function is responsible for authenticating Normal/Secure images.
229 ******************************************************************************/
230static int bl1_fwu_image_auth(unsigned int image_id,
231 uintptr_t image_src,
232 unsigned int image_size,
233 unsigned int flags)
234{
235 int result;
236 uintptr_t base_addr;
237 unsigned int total_size;
238
239 /* Get the image descriptor. */
240 image_desc_t *image_desc = bl1_plat_get_image_desc(image_id);
241 if (!image_desc)
242 return -EPERM;
243
Yatharth Kocharf11b29a2016-02-01 11:04:46 +0000244 if (GET_SECURITY_STATE(flags) == SECURE) {
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100245 if (image_desc->state != IMAGE_STATE_RESET) {
246 WARN("BL1-FWU: Authentication from secure world "
247 "while in invalid state\n");
248 return -EPERM;
249 }
250 } else {
Yatharth Kocharf11b29a2016-02-01 11:04:46 +0000251 if (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE) {
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100252 if (image_desc->state != IMAGE_STATE_COPIED) {
253 WARN("BL1-FWU: Authentication of secure image "
254 "from non-secure world while not in copied state\n");
255 return -EPERM;
256 }
257 } else {
258 if (image_desc->state != IMAGE_STATE_RESET) {
259 WARN("BL1-FWU: Authentication of non-secure image "
260 "from non-secure world while in invalid state\n");
261 return -EPERM;
262 }
263 }
264 }
265
266 if (image_desc->state == IMAGE_STATE_COPIED) {
267 /*
268 * Image is in COPIED state.
269 * Use the stored address and size.
270 */
271 base_addr = image_desc->image_info.image_base;
272 total_size = image_desc->image_info.image_size;
273 } else {
Sandrine Bailleuxb39d75f2016-11-11 16:44:37 +0000274 if ((!image_src) || (!image_size) ||
275 check_uptr_overflow(image_src, image_size - 1)) {
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100276 WARN("BL1-FWU: Auth not allowed due to invalid"
277 " image source/size\n");
278 return -ENOMEM;
279 }
280
281 /*
282 * Image is in RESET state.
283 * Check the parameters and authenticate the source image in place.
284 */
Dan Handley35e5f692015-12-14 16:26:43 +0000285 if (bl1_plat_mem_check(image_src, image_size, \
286 image_desc->ep_info.h.attr)) {
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100287 WARN("BL1-FWU: Authentication arguments source/size not mapped\n");
288 return -ENOMEM;
289 }
290
291 base_addr = image_src;
292 total_size = image_size;
293
294 /* Update the image size in the descriptor. */
295 image_desc->image_info.image_size = total_size;
296 }
297
298 /*
299 * Authenticate the image.
300 */
301 INFO("BL1-FWU: Authenticating image_id:%d\n", image_id);
302 result = auth_mod_verify_img(image_id, (void *)base_addr, total_size);
303 if (result != 0) {
304 WARN("BL1-FWU: Authentication Failed err=%d\n", result);
305
306 /*
307 * Authentication has failed.
308 * Clear the memory if the image was copied.
309 * This is to prevent an attack where this contains
310 * some malicious code that can somehow be executed later.
311 */
312 if (image_desc->state == IMAGE_STATE_COPIED) {
313 /* Clear the memory.*/
Douglas Raillard21362a92016-12-02 13:51:54 +0000314 zero_normalmem((void *)base_addr, total_size);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100315 flush_dcache_range(base_addr, total_size);
316
317 /* Indicate that image can be copied again*/
318 image_desc->state = IMAGE_STATE_RESET;
319 }
320 return -EAUTH;
321 }
322
323 /* Indicate that image is in authenticated state. */
324 image_desc->state = IMAGE_STATE_AUTHENTICATED;
325
326 /*
327 * Flush image_info to memory so that other
328 * secure world images can see changes.
329 */
330 flush_dcache_range((unsigned long)&image_desc->image_info,
331 sizeof(image_info_t));
332
333 INFO("BL1-FWU: Authentication was successful\n");
334
335 return 0;
336}
337
338/*******************************************************************************
339 * This function is responsible for executing Secure images.
340 ******************************************************************************/
341static int bl1_fwu_image_execute(unsigned int image_id,
342 void **handle,
343 unsigned int flags)
344{
345 /* Get the image descriptor. */
346 image_desc_t *image_desc = bl1_plat_get_image_desc(image_id);
347
348 /*
349 * Execution is NOT allowed if:
Dan Handley8ec76522015-12-15 10:52:33 +0000350 * image_id is invalid OR
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100351 * Caller is from Secure world OR
352 * Image is Non-Secure OR
353 * Image is Non-Executable OR
354 * Image is NOT in AUTHENTICATED state.
355 */
356 if ((!image_desc) ||
Yatharth Kocharf11b29a2016-02-01 11:04:46 +0000357 (GET_SECURITY_STATE(flags) == SECURE) ||
358 (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == NON_SECURE) ||
359 (EP_GET_EXE(image_desc->ep_info.h.attr) == NON_EXECUTABLE) ||
360 (image_desc->state != IMAGE_STATE_AUTHENTICATED)) {
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100361 WARN("BL1-FWU: Execution not allowed due to invalid state/args\n");
362 return -EPERM;
363 }
364
365 INFO("BL1-FWU: Executing Secure image\n");
366
367 /* Save NS-EL1 system registers. */
368 cm_el1_sysregs_context_save(NON_SECURE);
369
370 /* Prepare the image for execution. */
371 bl1_prepare_next_image(image_id);
372
373 /* Update the secure image id. */
374 sec_exec_image_id = image_id;
375
376 *handle = cm_get_context(SECURE);
377 return 0;
378}
379
380/*******************************************************************************
Dan Handley8ec76522015-12-15 10:52:33 +0000381 * This function is responsible for resuming execution in the other security
382 * world
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100383 ******************************************************************************/
Dan Handley8ec76522015-12-15 10:52:33 +0000384static register_t bl1_fwu_image_resume(register_t image_param,
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100385 void **handle,
386 unsigned int flags)
387{
388 image_desc_t *image_desc;
389 unsigned int resume_sec_state;
Yatharth Kocharf11b29a2016-02-01 11:04:46 +0000390 unsigned int caller_sec_state = GET_SECURITY_STATE(flags);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100391
Dan Handley8ec76522015-12-15 10:52:33 +0000392 /* Get the image descriptor for last executed secure image id. */
393 image_desc = bl1_plat_get_image_desc(sec_exec_image_id);
394 if (caller_sec_state == NON_SECURE) {
395 if (!image_desc) {
396 WARN("BL1-FWU: Resume not allowed due to no available"
397 "secure image\n");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100398 return -EPERM;
399 }
Dan Handley8ec76522015-12-15 10:52:33 +0000400 } else {
401 /* image_desc must be valid for secure world callers */
402 assert(image_desc);
403 }
404
Yatharth Kocharf11b29a2016-02-01 11:04:46 +0000405 assert(GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE);
406 assert(EP_GET_EXE(image_desc->ep_info.h.attr) == EXECUTABLE);
Dan Handley8ec76522015-12-15 10:52:33 +0000407
408 if (caller_sec_state == SECURE) {
409 assert(image_desc->state == IMAGE_STATE_EXECUTED);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100410
411 /* Update the flags. */
412 image_desc->state = IMAGE_STATE_INTERRUPTED;
413 resume_sec_state = NON_SECURE;
414 } else {
Dan Handley8ec76522015-12-15 10:52:33 +0000415 assert(image_desc->state == IMAGE_STATE_INTERRUPTED);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100416
417 /* Update the flags. */
418 image_desc->state = IMAGE_STATE_EXECUTED;
419 resume_sec_state = SECURE;
420 }
421
422 /* Save the EL1 system registers of calling world. */
Dan Handley8ec76522015-12-15 10:52:33 +0000423 cm_el1_sysregs_context_save(caller_sec_state);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100424
425 /* Restore the EL1 system registers of resuming world. */
426 cm_el1_sysregs_context_restore(resume_sec_state);
427
428 /* Update the next context. */
429 cm_set_next_eret_context(resume_sec_state);
430
431 INFO("BL1-FWU: Resuming %s world context\n",
Dan Handley8ec76522015-12-15 10:52:33 +0000432 (resume_sec_state == SECURE) ? "secure" : "normal");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100433
434 *handle = cm_get_context(resume_sec_state);
435 return image_param;
436}
437
438/*******************************************************************************
439 * This function is responsible for resuming normal world context.
440 ******************************************************************************/
441static int bl1_fwu_sec_image_done(void **handle, unsigned int flags)
442{
Dan Handley8ec76522015-12-15 10:52:33 +0000443 image_desc_t *image_desc;
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100444
Dan Handley8ec76522015-12-15 10:52:33 +0000445 /* Make sure caller is from the secure world */
Yatharth Kocharf11b29a2016-02-01 11:04:46 +0000446 if (GET_SECURITY_STATE(flags) == NON_SECURE) {
Dan Handley8ec76522015-12-15 10:52:33 +0000447 WARN("BL1-FWU: Image done not allowed from normal world\n");
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100448 return -EPERM;
449 }
450
Dan Handley8ec76522015-12-15 10:52:33 +0000451 /* Get the image descriptor for last executed secure image id */
452 image_desc = bl1_plat_get_image_desc(sec_exec_image_id);
453
454 /* image_desc must correspond to a valid secure executing image */
455 assert(image_desc);
Yatharth Kocharf11b29a2016-02-01 11:04:46 +0000456 assert(GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE);
457 assert(EP_GET_EXE(image_desc->ep_info.h.attr) == EXECUTABLE);
Dan Handley8ec76522015-12-15 10:52:33 +0000458 assert(image_desc->state == IMAGE_STATE_EXECUTED);
459
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100460 /* Update the flags. */
461 image_desc->state = IMAGE_STATE_RESET;
462 sec_exec_image_id = INVALID_IMAGE_ID;
463
464 /*
465 * Secure world is done so no need to save the context.
466 * Just restore the Non-Secure context.
467 */
468 cm_el1_sysregs_context_restore(NON_SECURE);
469
470 /* Update the next context. */
471 cm_set_next_eret_context(NON_SECURE);
472
473 INFO("BL1-FWU: Resuming Normal world context\n");
474
475 *handle = cm_get_context(NON_SECURE);
476 return 0;
477}
478
479/*******************************************************************************
480 * This function provides the opportunity for users to perform any
481 * platform specific handling after the Firmware update is done.
482 ******************************************************************************/
Dan Handley89f8f332015-12-15 14:28:24 +0000483__dead2 static void bl1_fwu_done(void *client_cookie, void *reserved)
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100484{
485 NOTICE("BL1-FWU: *******FWU Process Completed*******\n");
486
487 /*
488 * Call platform done function.
489 */
Dan Handley89f8f332015-12-15 14:28:24 +0000490 bl1_plat_fwu_done(client_cookie, reserved);
Yatharth Kochar71c9a5e2015-10-10 19:06:53 +0100491 assert(0);
492}