1 /*
2 * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <stdint.h>
9 #include <stdbool.h>
10 #include <string.h>
11 #include "config_tfm.h"
12 #include "tfm_platform_api.h"
13 #include "tfm_bootloader_fwu_abstraction.h"
14 #include "psa/update.h"
15 #include "service_api.h"
16 #include "psa/service.h"
17 #include "psa_manifest/tfm_firmware_update.h"
18 #include "compiler_ext_defs.h"
19
20 #define COMPONENTS_ITER(x) \
21 for ((x) = 0; (x) < (FWU_COMPONENT_NUMBER); (x)++)
22
23 typedef struct tfm_fwu_ctx_s {
24 psa_status_t error;
25 uint8_t component_state;
26 bool in_use;
27 } tfm_fwu_ctx_t;
28
29 /**
30 * \brief The context of FWU service.
31 */
32 static tfm_fwu_ctx_t fwu_ctx[FWU_COMPONENT_NUMBER];
33
34 #if PSA_FRAMEWORK_HAS_MM_IOVEC != 1
35 static uint8_t block[TFM_FWU_BUF_SIZE] __aligned(4);
36 #endif
37
tfm_fwu_start(const psa_msg_t * msg)38 static psa_status_t tfm_fwu_start(const psa_msg_t *msg)
39 {
40 psa_fwu_component_t component;
41 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1 || TFM_CONFIG_FWU_MAX_MANIFEST_SIZE == 0
42 uint8_t *manifest = NULL;
43 #else
44 uint8_t manifest_data[TFM_CONFIG_FWU_MAX_MANIFEST_SIZE];
45 uint8_t *manifest = manifest_data;
46 #endif
47 size_t manifest_size;
48 psa_status_t status;
49 psa_fwu_component_info_t info;
50
51 /* Check input parameters. */
52 if (msg->in_size[0] != sizeof(component)) {
53 return PSA_ERROR_PROGRAMMER_ERROR;
54 }
55 if (msg->in_size[1] > TFM_CONFIG_FWU_MAX_MANIFEST_SIZE) {
56 return PSA_ERROR_NOT_SUPPORTED;
57 }
58 psa_read(msg->handle, 0, &component, sizeof(component));
59
60 if (component >= FWU_COMPONENT_NUMBER) {
61 return PSA_ERROR_DOES_NOT_EXIST;
62 }
63 manifest_size = msg->in_size[1];
64 if (manifest_size > 0) {
65 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
66 manifest = (uint8_t *)psa_map_invec(msg->handle, 1);
67 #else
68 psa_read(msg->handle, 1, manifest, manifest_size);
69 #endif
70 }
71
72 /* The component is in FWU process. */
73 if (fwu_ctx[component].in_use) {
74 if (fwu_ctx[component].component_state != PSA_FWU_READY) {
75 return PSA_ERROR_BAD_STATE;
76 }
77 } else {
78 /* Query the state of the component. */
79 status = fwu_bootloader_get_image_info(component, true, false, &info);
80 if (status != PSA_SUCCESS) {
81 return status;
82 }
83 if (info.state != PSA_FWU_READY) {
84 return PSA_ERROR_BAD_STATE;
85 }
86
87 /* The component is not in FWU process. Initialize the ctx for this component. */
88 status = fwu_bootloader_staging_area_init(component,
89 (const void *)manifest,
90 manifest_size);
91 if (status != PSA_SUCCESS) {
92 return status;
93 }
94 fwu_ctx[component].in_use = true;
95 fwu_ctx[component].component_state = PSA_FWU_WRITING;
96 }
97 return PSA_SUCCESS;
98 }
99
tfm_fwu_write(const psa_msg_t * msg)100 static psa_status_t tfm_fwu_write(const psa_msg_t *msg)
101 {
102 psa_fwu_component_t component;
103 size_t image_offset;
104 size_t block_size;
105 psa_status_t status = PSA_SUCCESS;
106 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
107 uint8_t *block;
108 #else
109 size_t write_size, num;
110 #endif
111
112 /* Check input parameters. */
113 if (msg->in_size[2] > PSA_FWU_MAX_WRITE_SIZE) {
114 return PSA_ERROR_INVALID_ARGUMENT;
115 }
116 block_size = msg->in_size[2];
117
118 if (msg->in_size[0] != sizeof(component) ||
119 msg->in_size[1] != sizeof(image_offset)) {
120 return PSA_ERROR_PROGRAMMER_ERROR;
121 }
122
123 psa_read(msg->handle, 0, &component, sizeof(component));
124 if (component >= FWU_COMPONENT_NUMBER) {
125 return PSA_ERROR_DOES_NOT_EXIST;
126 }
127
128 psa_read(msg->handle, 1, &image_offset, sizeof(image_offset));
129
130 /* Check the component state. */
131 if (!fwu_ctx[component].in_use ||
132 fwu_ctx[component].component_state != PSA_FWU_WRITING) {
133 return PSA_ERROR_BAD_STATE;
134 }
135 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
136 if (block_size > 0) {
137 block = (uint8_t *)psa_map_invec(msg->handle, 2);
138 status = fwu_bootloader_load_image(component,
139 image_offset,
140 block,
141 block_size);
142 }
143 #else
144 while (block_size > 0) {
145 write_size = sizeof(block) <= block_size ?
146 sizeof(block) : block_size;
147 num = psa_read(msg->handle, 2, block, write_size);
148 if (num != write_size) {
149 return PSA_ERROR_PROGRAMMER_ERROR;
150 }
151
152 status = fwu_bootloader_load_image(component,
153 image_offset,
154 block,
155 write_size);
156 if (status != PSA_SUCCESS) {
157 return status;
158 }
159 block_size -= write_size;
160 image_offset += write_size;
161 }
162 #endif
163 return status;
164 }
165
tfm_fwu_finish(const psa_msg_t * msg)166 static psa_status_t tfm_fwu_finish(const psa_msg_t *msg)
167 {
168 psa_fwu_component_t component;
169
170 /* Check input parameters. */
171 if (msg->in_size[0] != sizeof(component)) {
172 return PSA_ERROR_PROGRAMMER_ERROR;
173 }
174 psa_read(msg->handle, 0, &component, sizeof(component));
175 if (component >= FWU_COMPONENT_NUMBER) {
176 return PSA_ERROR_DOES_NOT_EXIST;
177 }
178
179 /* Check the component state. */
180 if (!fwu_ctx[component].in_use ||
181 fwu_ctx[component].component_state != PSA_FWU_WRITING) {
182 return PSA_ERROR_BAD_STATE;
183 }
184
185 /* Validity, authenticity and integrity of the image is deferred to system
186 * reboot.
187 */
188 fwu_ctx[component].component_state = PSA_FWU_CANDIDATE;
189 return PSA_SUCCESS;
190 }
191
tfm_fwu_install(void)192 static psa_status_t tfm_fwu_install(void)
193 {
194 psa_fwu_component_t component = 0;
195 psa_status_t status;
196 uint8_t candidate_number = 0, index;
197 psa_fwu_component_info_t info;
198 psa_fwu_component_t candidates[FWU_COMPONENT_NUMBER];
199
200 /* If at least one component is in STAGED, TRIAL or REJECTED state results
201 * PSA_ERROR_BAD_STATE error.
202 */
203 COMPONENTS_ITER(component) {
204 if (fwu_ctx[component].in_use) {
205 if (fwu_ctx[component].component_state == PSA_FWU_STAGED ||
206 fwu_ctx[component].component_state == PSA_FWU_REJECTED) {
207 return PSA_ERROR_BAD_STATE;
208 } else if (fwu_ctx[component].component_state == PSA_FWU_CANDIDATE) {
209 candidates[candidate_number++] = component;
210 }
211 } else {
212 status = fwu_bootloader_get_image_info(component, true, false, &info);
213 if (status != PSA_SUCCESS) {
214 return status;
215 }
216 if (info.state == PSA_FWU_TRIAL) {
217 return PSA_ERROR_BAD_STATE;
218 }
219 }
220 }
221
222 /* No components in CANDIDATE state. */
223 if (candidate_number == 0) {
224 return PSA_ERROR_BAD_STATE;
225 }
226
227 status = fwu_bootloader_install_image(candidates,
228 candidate_number);
229
230 if (status == PSA_ERROR_DEPENDENCY_NEEDED) {
231 /* No need to update the CANDIDATE components' state in this case. */
232 return status;
233 }
234
235 /* Update the CANDIDATE components' state and error context accordingly. */
236 for (index = 0; index < candidate_number; index++) {
237 component = candidates[index];
238 if (status == PSA_SUCCESS) {
239 /* Check TRIAL state is supported or not. */
240 #ifdef FWU_SUPPORT_TRIAL_STATE
241 fwu_ctx[component].component_state = PSA_FWU_TRIAL;
242 #else
243 fwu_ctx[component].component_state = PSA_FWU_UPDATED;
244 #endif
245 } else if (status != PSA_SUCCESS_REBOOT && status != PSA_SUCCESS_RESTART) {
246 /* Switch to FAILED state on other errors. */
247 fwu_ctx[component].component_state = PSA_FWU_FAILED;
248 fwu_ctx[component].error = status;
249 } else {
250 fwu_ctx[component].component_state = PSA_FWU_STAGED;
251 }
252 }
253 return status;
254 }
255
tfm_fwu_query(const psa_msg_t * msg)256 static psa_status_t tfm_fwu_query(const psa_msg_t *msg)
257 {
258 psa_fwu_component_t component = { 0 };
259 psa_fwu_component_info_t info;
260 psa_status_t result;
261 bool query_impl_info = false, query_state = true;
262
263 /* Check input parameters. */
264 if (msg->in_size[0] != sizeof(component) ||
265 msg->out_size[0] != sizeof(psa_fwu_component_info_t)) {
266 return PSA_ERROR_PROGRAMMER_ERROR;
267 }
268 psa_read(msg->handle, 0, &component, sizeof(component));
269 if (component >= FWU_COMPONENT_NUMBER) {
270 return PSA_ERROR_DOES_NOT_EXIST;
271 }
272
273 if (fwu_ctx[component].in_use) {
274 info.state = fwu_ctx[component].component_state;
275 query_state = false;
276 /* The psa_fwu_impl_info_t contains the digest of second image when
277 * store state is CANDIDATE. Calculate the digest when store state is
278 * CANDIDATE.
279 */
280 if (fwu_ctx[component].component_state == PSA_FWU_CANDIDATE) {
281 query_impl_info = true;
282 } else if (fwu_ctx[component].component_state == PSA_FWU_REJECTED ||
283 fwu_ctx[component].component_state == PSA_FWU_FAILED) {
284 info.error = fwu_ctx[component].error;
285 }
286 }
287
288 /* If there is no active ctx, the possible component states are READY and
289 * TRIAL.
290 */
291 result = fwu_bootloader_get_image_info(component, query_state,
292 query_impl_info, &info);
293 if (result == PSA_SUCCESS) {
294 psa_write(msg->handle, 0, &info, sizeof(info));
295 }
296
297 return result;
298 }
299
tfm_fwu_request_reboot(void)300 static psa_status_t tfm_fwu_request_reboot(void)
301 {
302 tfm_platform_system_reset();
303
304 return PSA_SUCCESS;
305 }
306
tfm_fwu_accept(void)307 static psa_status_t tfm_fwu_accept(void)
308 {
309 #ifdef FWU_SUPPORT_TRIAL_STATE
310 psa_fwu_component_t component = 0;
311 psa_status_t status = PSA_ERROR_BAD_STATE;
312 psa_fwu_component_info_t info;
313 psa_fwu_component_t trials[FWU_COMPONENT_NUMBER];
314 uint8_t trials_number = 0, index;
315
316 COMPONENTS_ITER(component) {
317 if (fwu_ctx[component].in_use) {
318 if (fwu_ctx[component].component_state == PSA_FWU_TRIAL) {
319 trials[trials_number++] = component;
320 }
321 } else {
322 status = fwu_bootloader_get_image_info(component, true, false, &info);
323 if (status != PSA_SUCCESS) {
324 return status;
325 }
326 if (info.state == PSA_FWU_TRIAL) {
327 trials[trials_number++] = component;
328 fwu_ctx[component].in_use = true;
329 fwu_ctx[component].component_state = PSA_FWU_TRIAL;
330 }
331 }
332 }
333
334 if (trials_number == 0) {
335 return PSA_ERROR_BAD_STATE;
336 }
337 status = fwu_bootloader_mark_image_accepted(trials, trials_number);
338 if (status != PSA_SUCCESS) {
339 /* Rebooting the system results in the image being automatically rejected.
340 * Keep the component in TRIAL state.
341 */
342 return status;
343 }
344
345 for (index = 0; index < trials_number; index++) {
346 component = trials[index];
347 fwu_ctx[component].component_state = PSA_FWU_UPDATED;
348 }
349 return status;
350 #else
351 return PSA_ERROR_NOT_SUPPORTED;
352 #endif
353 }
354
tfm_fwu_reject(const psa_msg_t * msg)355 psa_status_t tfm_fwu_reject(const psa_msg_t *msg)
356 {
357 psa_fwu_component_t component = 0;
358 psa_status_t status = PSA_SUCCESS, error;
359 psa_fwu_component_info_t info;
360 bool staged_trial_component_found = false, in_trial_state = false;
361 size_t num;
362
363 /* Check input parameters. */
364 if (msg->in_size[0] != sizeof(error)) {
365 return PSA_ERROR_PROGRAMMER_ERROR;
366 }
367 num = psa_read(msg->handle, 0, &error, sizeof(error));
368 if (num != sizeof(error)) {
369 return PSA_ERROR_PROGRAMMER_ERROR;
370 }
371
372 COMPONENTS_ITER(component) {
373 in_trial_state = false;
374 if (fwu_ctx[component].in_use) {
375 if (fwu_ctx[component].component_state == PSA_FWU_STAGED) {
376 /* If the installation state is STAGED, then the state of
377 * affected components changes to FAILED.
378 */
379 fwu_ctx[component].component_state = PSA_FWU_FAILED;
380 fwu_ctx[component].error = error;
381 staged_trial_component_found = true;
382 /* Reject the staged image. */
383 status = fwu_bootloader_reject_staged_image(component);
384 if (status != PSA_SUCCESS) {
385 return status;
386 }
387 } else if (fwu_ctx[component].component_state == PSA_FWU_TRIAL) {
388 staged_trial_component_found = true;
389 in_trial_state = true;
390 }
391 } else {
392 status = fwu_bootloader_get_image_info(component, true, false, &info);
393 if (status != PSA_SUCCESS) {
394 return status;
395 }
396
397 /* Reject the component if it is in TRIAL state. Reserve a ctx
398 * for the component to record its state.
399 */
400 if (info.state == PSA_FWU_TRIAL) {
401 fwu_ctx[component].in_use = true;
402 in_trial_state = true;
403 fwu_ctx[component].component_state = PSA_FWU_TRIAL;
404 staged_trial_component_found = true;
405 }
406 }
407 if (in_trial_state) {
408 /* Reject the running(trial) image. */
409 status = fwu_bootloader_reject_trial_image(component);
410 /* If a reboot is required, the state of affected components
411 * changes to REJECTED and PSA_SUCCESS_REBOOT is returned.
412 * If a component restart is required, the state of affected
413 * components changes to REJECTED and PSA_SUCCESS_RESTART is
414 * returned.
415 * If no reboot or component restart is required, the state
416 * of affected components changes to FAILED and PSA_SUCCESS
417 * is returned.
418 */
419 if (status == PSA_SUCCESS_REBOOT || status == PSA_SUCCESS_RESTART) {
420 fwu_ctx[component].component_state = PSA_FWU_REJECTED;
421 fwu_ctx[component].error = error;
422 } else if (status == PSA_SUCCESS) {
423 fwu_ctx[component].component_state = PSA_FWU_FAILED;
424 fwu_ctx[component].error = error;
425 } else {
426 return status;
427 }
428 }
429 }
430 if (!staged_trial_component_found) {
431 /* There are no components in the STAGED or TRIAL state. */
432 return PSA_ERROR_BAD_STATE;
433 }
434 return status;
435 }
436
tfm_fwu_cancel(const psa_msg_t * msg)437 static psa_status_t tfm_fwu_cancel(const psa_msg_t *msg)
438 {
439 psa_fwu_component_t component;
440
441 if (msg->in_size[0] != sizeof(component)) {
442 return PSA_ERROR_PROGRAMMER_ERROR;
443 }
444
445 psa_read(msg->handle, 0, &component, sizeof(component));
446 if (component >= FWU_COMPONENT_NUMBER) {
447 return PSA_ERROR_DOES_NOT_EXIST;
448 }
449
450 if (fwu_ctx[component].in_use) {
451 /* The component is in FWU process. */
452 if ((fwu_ctx[component].component_state == PSA_FWU_WRITING) ||
453 (fwu_ctx[component].component_state == PSA_FWU_CANDIDATE)) {
454 fwu_ctx[component].component_state = PSA_FWU_FAILED;
455 fwu_ctx[component].error = PSA_SUCCESS;
456 return PSA_SUCCESS;
457 } else {
458 /* If the image is in INSTALLED state or UNDEFINED, it should not in
459 * a FWU process.
460 */
461 return PSA_ERROR_BAD_STATE;
462 }
463 } else {
464 /* The component is not in WRITING or CANDIDATE state. */
465 return PSA_ERROR_BAD_STATE;
466 }
467 }
468
tfm_fwu_clean(const psa_msg_t * msg)469 static psa_status_t tfm_fwu_clean(const psa_msg_t *msg)
470 {
471 psa_fwu_component_t component;
472 psa_status_t status;
473
474 if (msg->in_size[0] != sizeof(component)) {
475 return PSA_ERROR_PROGRAMMER_ERROR;
476 }
477
478 psa_read(msg->handle, 0, &component, sizeof(component));
479 if (component >= FWU_COMPONENT_NUMBER) {
480 return PSA_ERROR_DOES_NOT_EXIST;
481 }
482
483 if (fwu_ctx[component].in_use) {
484 /* The component is in FWU process. */
485 if ((fwu_ctx[component].component_state == PSA_FWU_FAILED) ||
486 (fwu_ctx[component].component_state == PSA_FWU_UPDATED)) {
487 status = fwu_bootloader_clean_component(component);
488 if (status != PSA_SUCCESS) {
489 return status;
490 }
491 fwu_ctx[component].component_state = PSA_FWU_READY;
492 fwu_ctx[component].in_use = false;
493 return PSA_SUCCESS;
494 } else {
495 /* If the image is in INSTALLED state or UNDEFINED, it should not in
496 * a FWU process.
497 */
498 return PSA_ERROR_BAD_STATE;
499 }
500 } else {
501 /* The component is not in FAILED or UPDATED state. */
502 return PSA_ERROR_BAD_STATE;
503 }
504 }
505
tfm_firmware_update_service_sfn(const psa_msg_t * msg)506 psa_status_t tfm_firmware_update_service_sfn(const psa_msg_t *msg)
507 {
508 switch (msg->type) {
509 case TFM_FWU_START:
510 return tfm_fwu_start(msg);
511 case TFM_FWU_WRITE:
512 return tfm_fwu_write(msg);
513 case TFM_FWU_FINISH:
514 return tfm_fwu_finish(msg);
515 case TFM_FWU_INSTALL:
516 return tfm_fwu_install();
517 case TFM_FWU_CANCEL:
518 return tfm_fwu_cancel(msg);
519 case TFM_FWU_CLEAN:
520 return tfm_fwu_clean(msg);
521 case TFM_FWU_QUERY:
522 return tfm_fwu_query(msg);
523 case TFM_FWU_REQUEST_REBOOT:
524 return tfm_fwu_request_reboot();
525 case TFM_FWU_ACCEPT:
526 return tfm_fwu_accept();
527 case TFM_FWU_REJECT:
528 return tfm_fwu_reject(msg);
529 default:
530 return PSA_ERROR_NOT_SUPPORTED;
531 }
532 }
533
tfm_fwu_entry(void)534 psa_status_t tfm_fwu_entry(void)
535 {
536 if (fwu_bootloader_init() != 0) {
537 return PSA_ERROR_GENERIC_ERROR;
538 }
539 return PSA_SUCCESS;
540 }
541