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