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