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