1 /*
2  * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <string.h>
9 
10 #include "config_tfm.h"
11 #include "its_flash_fs_mblock.h"
12 #include "psa/storage_common.h"
13 
14 #ifndef ITS_MAX_BLOCK_DATA_COPY
15 #define ITS_MAX_BLOCK_DATA_COPY 256
16 #endif
17 
18 /* Physical ID of the two metadata blocks */
19 /* NOTE: the earmarked area may not always start at block number 0.
20  *       However, the flash interface can always add the required offset.
21  */
22 #define ITS_METADATA_BLOCK0  0
23 #define ITS_METADATA_BLOCK1  1
24 
25 /*!
26  * \def ITS_OTHER_META_BLOCK
27  *
28  * \brief Macro to get the the swap metadata block.
29  */
30 #define ITS_OTHER_META_BLOCK(metablock) \
31 (((metablock) == ITS_METADATA_BLOCK0) ? \
32 (ITS_METADATA_BLOCK1) : (ITS_METADATA_BLOCK0))
33 
34 #define ITS_BLOCK_META_HEADER_SIZE  sizeof(struct its_metadata_block_header_t)
35 #define ITS_BLOCK_METADATA_SIZE     sizeof(struct its_block_meta_t)
36 #define ITS_FILE_METADATA_SIZE      sizeof(struct its_file_meta_t)
37 
38 /* FIXME: Precompute these for each context */
39 /**
40  * \brief Gets the physical block ID of the initial position of the scratch
41  *        data block, for the current context.
42  *
43  * \param[in,out] fs_ctx  Filesystem context
44  *
45  * \return The physical block ID
46  */
47 __attribute__((always_inline))
its_init_scratch_dblock(struct its_flash_fs_ctx_t * fs_ctx)48 static inline uint32_t its_init_scratch_dblock(
49                                               struct its_flash_fs_ctx_t *fs_ctx)
50 {
51     /* When there are two blocks, the initial position of the scratch data block
52      * is the scratch metadata block. Otherwise, the initial position of scratch
53      * data block is immediately after the metadata blocks.
54      */
55     return fs_ctx->cfg->num_blocks == 2 ? 1 : 2;
56 }
57 
58 /**
59  * \brief Gets the physical block ID of the start position of the data blocks,
60  *        for the current context.
61  *
62  * \param[in,out] fs_ctx  Filesystem context
63  *
64  * \return The physical block ID
65  */
66 __attribute__((always_inline))
its_init_dblock_start(struct its_flash_fs_ctx_t * fs_ctx)67 static inline uint32_t its_init_dblock_start(struct its_flash_fs_ctx_t *fs_ctx)
68 {
69     /* Metadata and data are always stored in the same block with two blocks.
70      * Otherwise, one metadata block and two scratch blocks are reserved. One
71      * scratch block for metadata operations and the other for data operations.
72      */
73     return fs_ctx->cfg->num_blocks == 2 ? 0 : 3;
74 }
75 
76 /**
77  * \brief Gets the number of blocks that are dedicated wholely for data, for the
78  *        current context.
79  *
80  * \param[in,out] fs_ctx  Filesystem context
81  *
82  * \return The number of dedicated datablocks
83  */
its_num_dedicated_dblocks(struct its_flash_fs_ctx_t * fs_ctx)84 static uint32_t its_num_dedicated_dblocks(struct its_flash_fs_ctx_t *fs_ctx)
85 {
86     /* There are no dedicated data blocks when only two blocks are available.
87      * Otherwise, the number of blocks dedicated just for data is the number of
88      * blocks available beyond the initial datablock start index.
89      */
90      return fs_ctx->cfg->num_blocks == 2 ? 0 :
91             fs_ctx->cfg->num_blocks - its_init_dblock_start(fs_ctx);
92 }
93 
94 /**
95  * \brief Gets the number of active data blocks, for the current context.
96  *
97  * \param[in,out] fs_ctx  Filesystem context
98  *
99  * \return The number of active datablocks
100  */
101 __attribute__((always_inline))
its_num_active_dblocks(struct its_flash_fs_ctx_t * fs_ctx)102 static inline uint32_t its_num_active_dblocks(struct its_flash_fs_ctx_t *fs_ctx)
103 {
104     /* Total number of data blocks is the number of dedicated data blocks plus
105      * logical data block 0 stored in the metadata block.
106      */
107     return its_num_dedicated_dblocks(fs_ctx) + 1;
108 }
109 
110 /**
111  * \brief Gets offset of a logical block's metadata in metadata block.
112  *
113  * \param[in] lblock  Logical block number
114  *
115  * \return Return offset value in metadata block
116  */
its_mblock_block_meta_offset(uint32_t lblock)117 static size_t its_mblock_block_meta_offset(uint32_t lblock)
118 {
119     return ITS_BLOCK_META_HEADER_SIZE + (lblock * ITS_BLOCK_METADATA_SIZE);
120 }
121 
122 /**
123  * \brief Gets offset of an file metadata in metadata block.
124  *
125  * \param[in,out] fs_ctx  Filesystem context
126  * \param[in]     idx     File metadata entry index
127  *
128  * \return Return offset value in metadata block
129  */
its_mblock_file_meta_offset(struct its_flash_fs_ctx_t * fs_ctx,uint32_t idx)130 static size_t its_mblock_file_meta_offset(struct its_flash_fs_ctx_t *fs_ctx,
131                                           uint32_t idx)
132 {
133     return ITS_BLOCK_META_HEADER_SIZE
134            + (its_num_active_dblocks(fs_ctx) * ITS_BLOCK_METADATA_SIZE)
135            + (idx * ITS_FILE_METADATA_SIZE);
136 }
137 
138 /**
139  * \brief Swaps metablocks. Scratch becomes active and active becomes scratch.
140  *
141  * \param[in,out] fs_ctx  Filesystem context
142  */
its_mblock_swap_metablocks(struct its_flash_fs_ctx_t * fs_ctx)143 static void its_mblock_swap_metablocks(struct its_flash_fs_ctx_t *fs_ctx)
144 {
145     uint32_t tmp_block;
146 
147     tmp_block = fs_ctx->scratch_metablock;
148     fs_ctx->scratch_metablock = fs_ctx->active_metablock;
149     fs_ctx->active_metablock = tmp_block;
150 }
151 
152 /**
153  * \brief Finds the potential most recent valid metablock.
154  *
155  * \param[in,out] fs_ctx   Filesystem context
156  * \param[in]     h_meta0  Header metadata of meta block 0
157  * \param[in]     h_meta1  Header metadata of meta block 1
158  *
159  * \return most recent metablock
160  */
its_mblock_latest_meta_block(struct its_flash_fs_ctx_t * fs_ctx,const struct its_metadata_block_header_t * h_meta0,const struct its_metadata_block_header_t * h_meta1)161 static uint8_t its_mblock_latest_meta_block(
162                               struct its_flash_fs_ctx_t *fs_ctx,
163                               const struct its_metadata_block_header_t *h_meta0,
164                               const struct its_metadata_block_header_t *h_meta1)
165 {
166     uint8_t rollover_val;
167     uint8_t cur_meta;
168     uint8_t meta0_swap_count = h_meta0->active_swap_count;
169     uint8_t meta1_swap_count = h_meta1->active_swap_count;
170 
171     /* If the flash erase value is 0x00, then a swap count of 0 is skipped and
172      * so the rollover value becomes 1 instead of 0.
173      */
174     if (fs_ctx->cfg->erase_val == 0x00U) {
175         rollover_val = 1;
176     } else {
177         rollover_val = 0;
178     }
179 
180     /* Logic: if the swap count is 0, then it has rolled over. The metadata
181      * block with a swap count of 0 is the latest one, unless the other block
182      * has a swap count of 1, in which case the roll over occurred in the
183      * previous update. In all other cases, the block with the highest swap
184      * count is the latest one.
185      */
186     if ((meta1_swap_count == rollover_val) &&
187         (meta0_swap_count != (rollover_val + 1))) {
188         /* Metadata block 1 swap count has rolled over and metadata block 0
189          * swap count has not, so block 1 is the latest.
190          */
191         cur_meta = ITS_METADATA_BLOCK1;
192 
193     } else if ((meta0_swap_count == rollover_val) &&
194                (meta1_swap_count != (rollover_val + 1))) {
195         /* Metadata block 0 swap count has rolled over and metadata block 1
196          * swap count has not, so block 0 is the latest.
197          */
198         cur_meta = ITS_METADATA_BLOCK0;
199 
200     } else if (meta1_swap_count > meta0_swap_count) {
201         /* Neither swap count has just rolled over and metadata block 1 has a
202          * higher swap count, so block 1 is the latest.
203          */
204         cur_meta = ITS_METADATA_BLOCK1;
205 
206     } else {
207         /* Neither swap count has just rolled over and metadata block 0 has a
208          * higher or equal swap count, so block 0 is the latest.
209          */
210         cur_meta = ITS_METADATA_BLOCK0;
211     }
212 
213     return cur_meta;
214 }
215 
216 #if ITS_VALIDATE_METADATA_FROM_FLASH
217 /**
218  * \brief Validates file metadata in order to guarantee that a corruption or
219  *        malicious change in stored metadata doesn't result in an invalid
220  *        access.
221  *
222  * \param[in,out] fs_ctx     Filesystem context
223  * \param[in]     file_meta  Pointer to file meta structure
224  *
225  * \return Returns error code as specified in \ref psa_status_t
226  */
its_mblock_validate_file_meta(struct its_flash_fs_ctx_t * fs_ctx,const struct its_file_meta_t * file_meta)227 static psa_status_t its_mblock_validate_file_meta(
228                                         struct its_flash_fs_ctx_t *fs_ctx,
229                                         const struct its_file_meta_t *file_meta)
230 {
231     psa_status_t err;
232 
233     /* Logical block ID can not be bigger or equal than number of
234      * active blocks.
235      */
236     if (file_meta->lblock >= its_num_active_dblocks(fs_ctx)) {
237         return PSA_ERROR_DATA_CORRUPT;
238     }
239 
240     /* meta->id can be 0 if the file is not in use. If it is in
241      * use, check the metadata.
242      */
243     if (its_utils_validate_fid(file_meta->id) == PSA_SUCCESS) {
244         /* validate files values if file is in use */
245         if (file_meta->max_size > fs_ctx->cfg->max_file_size) {
246             return PSA_ERROR_DATA_CORRUPT;
247         }
248 
249         /* The current file data size must be smaller or equal than
250          * file data max size.
251          */
252         if (file_meta->cur_size > file_meta->max_size) {
253             return PSA_ERROR_DATA_CORRUPT;
254         }
255 
256         if (file_meta->lblock == ITS_LOGICAL_DBLOCK0) {
257             /* In block 0, data index must be located after the metadata */
258             if (file_meta->data_idx <
259                 its_mblock_file_meta_offset(fs_ctx,
260                                             fs_ctx->cfg->max_num_files)) {
261                 return PSA_ERROR_DATA_CORRUPT;
262             }
263         }
264 
265         /* Boundary check the incoming request */
266         err = its_utils_check_contained_in(fs_ctx->cfg->block_size,
267                                            file_meta->data_idx,
268                                            file_meta->max_size);
269         if (err != PSA_SUCCESS) {
270             return PSA_ERROR_DATA_CORRUPT;
271         }
272     }
273 
274     return PSA_SUCCESS;
275 }
276 
277 /**
278  * \brief Validates block metadata in order to guarantee that a corruption or
279  *        malicious change in stored metadata doesn't result in an invalid
280  *        access.
281  *
282  * \param[in,out] fs_ctx      Filesystem context
283  * \param[in]     block_meta  Pointer to block meta structure
284  *
285  * \return Returns error code as specified in \ref psa_status_t
286  */
its_mblock_validate_block_meta(struct its_flash_fs_ctx_t * fs_ctx,const struct its_block_meta_t * block_meta)287 static psa_status_t its_mblock_validate_block_meta(
288                                       struct its_flash_fs_ctx_t *fs_ctx,
289                                       const struct its_block_meta_t *block_meta)
290 {
291     psa_status_t err;
292     /* Data block's data start at position 0 */
293     size_t valid_data_start_value = 0;
294 
295     if (block_meta->phy_id >= fs_ctx->cfg->num_blocks) {
296         return PSA_ERROR_DATA_CORRUPT;
297     }
298 
299     /* Boundary check: block data start + free size can not be bigger
300      * than max block size.
301      */
302     err = its_utils_check_contained_in(fs_ctx->cfg->block_size,
303                                        block_meta->data_start,
304                                        block_meta->free_size);
305     if (err != PSA_SUCCESS) {
306         return PSA_ERROR_DATA_CORRUPT;
307     }
308 
309     if (block_meta->phy_id == ITS_METADATA_BLOCK0 ||
310         block_meta->phy_id == ITS_METADATA_BLOCK1) {
311 
312         /* For metadata + data block, data index must start after the
313          * metadata area.
314          */
315         valid_data_start_value =
316             its_mblock_file_meta_offset(fs_ctx, fs_ctx->cfg->max_num_files);
317     }
318 
319     if (block_meta->data_start != valid_data_start_value) {
320         return PSA_ERROR_DATA_CORRUPT;
321     }
322 
323     return PSA_SUCCESS;
324 }
325 
326 /*
327  * \brief Validates block metadata based on the backward compatible file system.
328  *
329  * \param[in,out] fs_ctx      Filesystem context
330  * \param[in]     block_meta  Pointer to block meta structure
331  *
332  * \return Returns error code as specified in \ref psa_status_t
333  */
its_mblock_validate_block_meta_comp(struct its_flash_fs_ctx_t * fs_ctx,const struct its_block_meta_t * block_meta)334 static psa_status_t its_mblock_validate_block_meta_comp(
335                                       struct its_flash_fs_ctx_t *fs_ctx,
336                                       const struct its_block_meta_t *block_meta)
337 {
338     psa_status_t err;
339     /* Data block's data start at position 0 */
340     size_t valid_data_start_value = 0;
341 
342     if (block_meta->phy_id >= fs_ctx->cfg->num_blocks) {
343         return PSA_ERROR_DATA_CORRUPT;
344     }
345 
346     /* Boundary check: block data start + free size can not be bigger
347      * than max block size.
348      */
349     err = its_utils_check_contained_in(fs_ctx->cfg->block_size,
350                                        block_meta->data_start,
351                                        block_meta->free_size);
352     if (err != PSA_SUCCESS) {
353         return PSA_ERROR_DATA_CORRUPT;
354     }
355 
356     if (block_meta->phy_id == ITS_METADATA_BLOCK0 ||
357         block_meta->phy_id == ITS_METADATA_BLOCK1) {
358 
359         /* For metadata + data block, data index must start after the
360          * metadata area.
361          */
362         valid_data_start_value =
363             sizeof(struct its_metadata_block_header_comp_t)
364             + (its_num_active_dblocks(fs_ctx) * ITS_BLOCK_METADATA_SIZE)
365             + (fs_ctx->cfg->max_num_files * ITS_FILE_METADATA_SIZE);
366     }
367 
368     if (block_meta->data_start != valid_data_start_value) {
369         return PSA_ERROR_DATA_CORRUPT;
370     }
371 
372     return PSA_SUCCESS;
373 }
374 
375 /**
376  * \brief Calculates the XOR on the whole metadata(not including the
377  *        metadata block header) in the scratch metadata block.
378  *
379  * \param[in,out] fs_ctx      Filesystem context
380  * \param[in] block_id        Metadata block ID
381  *
382  * \param[out] xor_value      XOR value based on all the medata in the block
383  *
384  * \return Returns error code as specified in \ref psa_status_t
385  */
its_mblock_calculate_metadata_xor(struct its_flash_fs_ctx_t * fs_ctx,uint32_t block_id,uint8_t * xor_value)386 static psa_status_t its_mblock_calculate_metadata_xor(
387                                               struct its_flash_fs_ctx_t *fs_ctx,
388                                               uint32_t block_id,
389                                               uint8_t *xor_value)
390 {
391     uint32_t i, j;
392     psa_status_t err;
393     uint8_t metadata[ITS_UTILS_MAX(ITS_BLOCK_METADATA_SIZE,
394                                    ITS_FILE_METADATA_SIZE)];
395     uint8_t xor_value_temp = 0;
396 
397     if ((block_id != ITS_METADATA_BLOCK0 && block_id != ITS_METADATA_BLOCK1) ||
398        (xor_value == NULL)) {
399         return PSA_ERROR_INVALID_ARGUMENT;
400     }
401 
402     /* Calculate the XOR value based on the block metadata. */
403     for (i = 0; i < its_num_active_dblocks(fs_ctx); i++) {
404         err = fs_ctx->ops->read(fs_ctx->cfg, block_id,
405                                 metadata,
406                                 its_mblock_block_meta_offset(i),
407                                 ITS_BLOCK_METADATA_SIZE);
408         if (err != PSA_SUCCESS) {
409             return err;
410         }
411 
412         /* Update the XOR value. */
413         for (j = 0; j < ITS_BLOCK_METADATA_SIZE; j++) {
414             xor_value_temp ^= metadata[j];
415         }
416     }
417 
418     /* Calculate the XOR value based on the file metadata. */
419     for (i = 0; i < fs_ctx->cfg->max_num_files; i++) {
420         err = fs_ctx->ops->read(fs_ctx->cfg, block_id,
421                                 metadata,
422                                 its_mblock_file_meta_offset(fs_ctx, i),
423                                 ITS_FILE_METADATA_SIZE);
424         if (err != PSA_SUCCESS) {
425             return err;
426         }
427 
428         /* Update the XOR value. */
429         for (j = 0; j < ITS_FILE_METADATA_SIZE; j++) {
430             xor_value_temp ^= metadata[j];
431         }
432     }
433     *xor_value = xor_value_temp;
434     return PSA_SUCCESS;
435 }
436 
437 /**
438  * \brief Checks the validity of metadata XOR.
439  *
440  * \param[in,out] fs_ctx      Filesystem context
441  * \param[in]     h_meta      Pointer to metadata block header
442  *
443  * \param[in] block_id        Metadata block ID
444  *
445  * \return Returns error code as specified in \ref psa_status_t
446  */
its_mblock_validate_metadata_xor(struct its_flash_fs_ctx_t * fs_ctx,const struct its_metadata_block_header_t * h_meta,uint32_t block_id)447 static psa_status_t its_mblock_validate_metadata_xor(
448                                struct its_flash_fs_ctx_t *fs_ctx,
449                                const struct its_metadata_block_header_t *h_meta,
450                                uint32_t block_id)
451 {
452     psa_status_t err;
453     uint8_t xor_value;
454 
455     err = its_mblock_calculate_metadata_xor(fs_ctx, block_id, &xor_value);
456     if (err != PSA_SUCCESS) {
457         return err;
458     }
459 
460     if (xor_value != h_meta->metadata_xor) {
461         return PSA_ERROR_STORAGE_FAILURE;
462     }
463     return PSA_SUCCESS;
464 }
465 #endif /* ITS_VALIDATE_METADATA_FROM_FLASH */
466 
467 /**
468  * \brief Gets a free file metadata table entry.
469  *
470  * \param[in,out] fs_ctx     Filesystem context
471  * \param[in]     use_spare  If true then the spare file index will be used,
472  *                           otherwise at least one file index will be left free
473  *
474  * \return Return index of a free file meta entry
475  */
its_get_free_file_index(struct its_flash_fs_ctx_t * fs_ctx,bool use_spare)476 static uint32_t its_get_free_file_index(struct its_flash_fs_ctx_t *fs_ctx,
477                                         bool use_spare)
478 {
479     psa_status_t err;
480     uint32_t i;
481     struct its_file_meta_t tmp_metadata;
482 
483     for (i = 0; i < fs_ctx->cfg->max_num_files; i++) {
484         err = its_flash_fs_mblock_read_file_meta(fs_ctx, i, &tmp_metadata);
485         if (err != PSA_SUCCESS) {
486             return ITS_METADATA_INVALID_INDEX;
487         }
488 
489         /* Check if this entry is free by checking if ID values is an
490          * invalid ID.
491          */
492         if (its_utils_validate_fid(tmp_metadata.id) != PSA_SUCCESS) {
493             if (!use_spare) {
494                 /* Keep the first free file index as a spare, indicate that the
495                  * next free file index should be used and continue searching.
496                  */
497                 use_spare = true;
498                 continue;
499             }
500             /* Found */
501             return i;
502         }
503     }
504 
505     return ITS_METADATA_INVALID_INDEX;
506 }
507 
508 /**
509  * \brief Erases data and meta scratch blocks.
510  *
511  * \param[in,out] fs_ctx  Filesystem context
512  *
513  * \return Returns error code as specified in \ref psa_status_t
514  */
its_mblock_erase_scratch_blocks(struct its_flash_fs_ctx_t * fs_ctx)515 static psa_status_t its_mblock_erase_scratch_blocks(
516                                               struct its_flash_fs_ctx_t *fs_ctx)
517 {
518     psa_status_t err;
519     uint32_t scratch_datablock;
520 
521     /* For the atomicity of the data update process
522      * and power-failure-safe operation, it is necessary that
523      * metadata scratch block is erased before data block.
524      */
525     err = fs_ctx->ops->erase(fs_ctx->cfg, fs_ctx->scratch_metablock);
526     if (err != PSA_SUCCESS) {
527         return err;
528     }
529 
530     /* If the number of blocks is bigger than 2, the code needs to erase the
531      * scratch block used to process any change in the data block which contains
532      * only data. Otherwise, if the number of blocks is equal to 2, it means
533      * that all data is stored in the metadata block.
534      */
535     if (fs_ctx->cfg->num_blocks > 2) {
536         scratch_datablock =
537             its_flash_fs_mblock_cur_data_scratch_id(fs_ctx,
538                                                     (ITS_LOGICAL_DBLOCK0 + 1));
539         err = fs_ctx->ops->erase(fs_ctx->cfg, scratch_datablock);
540     }
541 
542     return err;
543 }
544 
545 /**
546  * \brief Updates scratch block meta.
547  *
548  * \param[in,out] fs_ctx      Filesystem context
549  * \param[in]     lblock      Logical block number
550  * \param[in]     block_meta  Pointer to the block metadata data to write in the
551  *                            scratch block
552  *
553  * \return Returns error code as specified in \ref psa_status_t
554  */
its_mblock_update_scratch_block_meta(struct its_flash_fs_ctx_t * fs_ctx,uint32_t lblock,const struct its_block_meta_t * block_meta)555 static psa_status_t its_mblock_update_scratch_block_meta(
556                                       struct its_flash_fs_ctx_t *fs_ctx,
557                                       uint32_t lblock,
558                                       const struct its_block_meta_t *block_meta)
559 {
560     size_t pos;
561 
562     /* Calculate the position */
563     pos = its_mblock_block_meta_offset(lblock);
564     return fs_ctx->ops->write(fs_ctx->cfg, fs_ctx->scratch_metablock,
565                               (const uint8_t *)block_meta, pos,
566                               ITS_BLOCK_METADATA_SIZE);
567 }
568 
569 /**
570  * \brief Copies rest of the block metadata.
571  *
572  * \param[in,out] fs_ctx  Filesystem context
573  * \param[in]     lblock  Logical block number to skip
574  *
575  * \return Returns error code as specified in \ref psa_status_t
576  */
its_mblock_copy_remaining_block_meta(struct its_flash_fs_ctx_t * fs_ctx,uint32_t lblock)577 static psa_status_t its_mblock_copy_remaining_block_meta(
578                                               struct its_flash_fs_ctx_t *fs_ctx,
579                                               uint32_t lblock)
580 {
581     struct its_block_meta_t block_meta;
582     psa_status_t err;
583     uint32_t meta_block;
584     size_t pos;
585     uint32_t scratch_block;
586     size_t size;
587 
588     scratch_block = fs_ctx->scratch_metablock;
589     meta_block = fs_ctx->active_metablock;
590 
591     if (lblock != ITS_LOGICAL_DBLOCK0) {
592         /* The file data in the logical block 0 is stored in same physical
593          * block where the metadata is stored. A change in the metadata requires
594          * a swap of physical blocks. So, the physical block ID of logical block
595          * 0 needs to be updated to reflect this change, if the file processed
596          * is not located in logical block 0. If it is located in block 0,
597          * the physical block ID has been updated while processing the file
598          * data.
599          */
600         err = its_flash_fs_mblock_read_block_metadata(fs_ctx,
601                                                       ITS_LOGICAL_DBLOCK0,
602                                                       &block_meta);
603         if (err != PSA_SUCCESS) {
604             return PSA_ERROR_GENERIC_ERROR;
605         }
606 
607         /* Update physical ID for logical block 0 to match with the
608          * metadata block physical ID.
609          */
610         block_meta.phy_id = scratch_block;
611         err = its_mblock_update_scratch_block_meta(fs_ctx, ITS_LOGICAL_DBLOCK0,
612                                                    &block_meta);
613         if (err != PSA_SUCCESS) {
614             return PSA_ERROR_GENERIC_ERROR;
615         }
616 
617         /* Copy the rest of metadata blocks between logical block 0 and
618          * the logical block provided in the function.
619          */
620         if (lblock > 1) {
621             pos = its_mblock_block_meta_offset(ITS_LOGICAL_DBLOCK0 + 1);
622 
623             size = its_mblock_block_meta_offset(lblock) - pos;
624 
625             /* Copy rest of the block data from previous block */
626             /* Data before updated content */
627             err = its_flash_fs_block_to_block_move(fs_ctx, scratch_block, pos,
628                                                    meta_block, pos, size);
629             if (err != PSA_SUCCESS) {
630                 return err;
631             }
632         }
633     }
634 
635     /* Move meta blocks data after updated content */
636     pos = its_mblock_block_meta_offset(lblock+1);
637 
638     size = its_mblock_file_meta_offset(fs_ctx, 0) - pos;
639 
640     return its_flash_fs_block_to_block_move(fs_ctx, scratch_block, pos,
641                                             meta_block, pos, size);
642 }
643 
644 /**
645  * \brief Checks the validity of the metadata block's swap count.
646  *
647  * \param[in,out] fs_ctx      Filesystem context
648  * \param[in]     swap_count  Swap count to validate
649  *
650  * \return Returns error code as specified in \ref psa_status_t
651  */
652 __attribute__((always_inline))
its_mblock_validate_swap_count(struct its_flash_fs_ctx_t * fs_ctx,uint8_t swap_count)653 static inline psa_status_t its_mblock_validate_swap_count(
654                                               struct its_flash_fs_ctx_t *fs_ctx,
655                                               uint8_t swap_count)
656 {
657     /* When a flash block is erased, the default value
658      * is usually 0xFF (i.e. all 1s). Since the swap count
659      * is updated last (when encryption is disabled), it is
660      * possible that due to a power failure, the swap count
661      * value in metadata header is 0xFFFF..., which mean
662      * it will appear to be most recent block. Which isn't
663      * a problem in itself, as the rest of the metadata is fully
664      * valid (as it would have been written before swap count).
665      * However, this also means that previous update process
666      * wasn't complete. So, if the value is 0xFF..., revert
667      * back to previous metablock instead.
668      */
669     return (swap_count == fs_ctx->cfg->erase_val)
670            ? PSA_ERROR_GENERIC_ERROR
671            : PSA_SUCCESS;
672 }
673 
674 /**
675  * \brief Checks the validity of FS version.
676  *
677  * \param[in] fs_version  File system version.
678  *
679  * \param[out] backward_comp compatible with a backward version.
680  *
681  * \return Returns error code as specified in \ref psa_status_t
682  */
683 __attribute__((always_inline))
its_mblock_validate_fs_version(uint8_t fs_version,bool * backward_comp)684 static inline psa_status_t its_mblock_validate_fs_version(uint8_t fs_version,
685                                                           bool *backward_comp)
686 {
687     /* Looks for exact version number and the backward compatible version. */
688     if (fs_version == ITS_BACKWARD_SUPPORTED_VERSION) {
689         *backward_comp = true;
690         return PSA_SUCCESS;
691     } else if (fs_version == ITS_SUPPORTED_VERSION) {
692         *backward_comp = false;
693         return PSA_SUCCESS;
694     } else {
695         return PSA_ERROR_GENERIC_ERROR;
696     }
697 }
698 
699 /**
700  * \brief Validates header metadata in order to guarantee that a corruption or
701  *        malicious change in stored metadata doesn't result in an invalid
702  *        access and the header version is correct.
703  *
704  * \param[in,out] fs_ctx  Filesystem context
705  * \param[in]     h_meta  Pointer to metadata block header
706  *
707  * \param[in] block_id    Metadata block ID
708  *
709  * \return Returns error code as specified in \ref psa_status_t
710  */
its_mblock_validate_header_meta(struct its_flash_fs_ctx_t * fs_ctx,const struct its_metadata_block_header_t * h_meta,uint32_t block_id)711 static psa_status_t its_mblock_validate_header_meta(
712                                struct its_flash_fs_ctx_t *fs_ctx,
713                                const struct its_metadata_block_header_t *h_meta,
714                                uint32_t block_id)
715 {
716     psa_status_t err;
717     bool backward_compatible = false;
718 
719     err = its_mblock_validate_fs_version(h_meta->fs_version,
720                                          &backward_compatible);
721     if (err != PSA_SUCCESS) {
722         return err;
723     }
724 
725     if (backward_compatible) {
726         err = its_mblock_validate_swap_count(fs_ctx,
727         ((struct its_metadata_block_header_comp_t *)h_meta)->active_swap_count);
728     } else {
729         err = its_mblock_validate_swap_count(fs_ctx, h_meta->active_swap_count);
730         if (err != PSA_SUCCESS) {
731             return err;
732         }
733 #if ITS_VALIDATE_METADATA_FROM_FLASH
734         err = its_mblock_validate_metadata_xor(fs_ctx, h_meta, block_id);
735 #endif
736     }
737     return err;
738 }
739 
740 /**
741  * \brief Writes the scratch metadata's header.
742  *
743  * \param[in,out] fs_ctx  Filesystem context
744  *
745  * \return Returns error code as specified in \ref psa_status_t
746  */
its_mblock_write_scratch_meta_header(struct its_flash_fs_ctx_t * fs_ctx)747 static psa_status_t its_mblock_write_scratch_meta_header(
748                                               struct its_flash_fs_ctx_t *fs_ctx)
749 {
750     psa_status_t err;
751 
752     /* Increment the swap count */
753     fs_ctx->meta_block_header.active_swap_count++;
754 
755     err = its_mblock_validate_swap_count(fs_ctx,
756                                    fs_ctx->meta_block_header.active_swap_count);
757     if (err != PSA_SUCCESS) {
758         /* Increment again to avoid using the erase val as the swap count */
759         fs_ctx->meta_block_header.active_swap_count++;
760     }
761 #if ITS_VALIDATE_METADATA_FROM_FLASH
762     /* Calculate metadata XOR value. */
763     err = its_mblock_calculate_metadata_xor(fs_ctx,
764                                        fs_ctx->scratch_metablock,
765                                        &fs_ctx->meta_block_header.metadata_xor);
766     if (err != PSA_SUCCESS) {
767         return err;
768     }
769 #else
770     fs_ctx->meta_block_header.metadata_xor = 0;
771 #endif
772 
773     /* Write the metadata block header */
774     return fs_ctx->ops->write(fs_ctx->cfg, fs_ctx->scratch_metablock,
775                               (uint8_t *)(&fs_ctx->meta_block_header), 0,
776                               ITS_BLOCK_META_HEADER_SIZE);
777 }
778 
779 /**
780  * \brief Upgrade the meta header to ITS_SUPPORTED_VERSION if it is
781  *        ITS_BACKWARD_SUPPORTED_VERSION.
782  *
783  * \param[in,out] fs_ctx  Filesystem context
784  *
785  * \return Returns error code as specified in \ref psa_status_t
786  */
its_mblock_upgrade_meta_header(struct its_flash_fs_ctx_t * fs_ctx)787 static psa_status_t its_mblock_upgrade_meta_header(
788                                               struct its_flash_fs_ctx_t *fs_ctx)
789 {
790     bool backward_compatible = false;
791     psa_status_t err;
792     size_t number;
793     struct its_metadata_block_header_comp_t *meta_block_header_comp;
794     struct its_block_meta_t block_meta_0;
795 
796     err = its_mblock_validate_fs_version(fs_ctx->meta_block_header.fs_version,
797                                          &backward_compatible);
798     if (err != PSA_SUCCESS) {
799         return err;
800     }
801 
802     if (!backward_compatible) {
803         return PSA_SUCCESS;
804     }
805 
806     err = its_flash_fs_mblock_read_block_metadata_comp(fs_ctx,
807                                                        ITS_LOGICAL_DBLOCK0,
808                                                        &block_meta_0);
809     if (err != PSA_SUCCESS) {
810         return err;
811     }
812 
813     /* Copy the entire metadata and the file data in active_metablock to
814      * scratch_metablock. Only the meta_block_header needs to be updated.
815      */
816     number = fs_ctx->cfg->block_size - block_meta_0.free_size -
817                             sizeof(struct its_metadata_block_header_comp_t);
818     err = its_flash_fs_block_to_block_move(fs_ctx,
819                     fs_ctx->scratch_metablock,
820                     its_mblock_block_meta_offset(ITS_LOGICAL_DBLOCK0),
821                     fs_ctx->active_metablock,
822                     sizeof(struct its_metadata_block_header_comp_t),
823                     number);
824     if (err != PSA_SUCCESS) {
825         return err;
826     }
827 
828     /* Update metadata block header.
829      * scratch_dblock field share the same position as in the
830      * ITS_BACKWARD_SUPPORTED_VERSION. So, no need to update it.
831      */
832     meta_block_header_comp =
833         (struct its_metadata_block_header_comp_t *)&fs_ctx->meta_block_header;
834     fs_ctx->meta_block_header.active_swap_count =
835              meta_block_header_comp->active_swap_count;
836     fs_ctx->meta_block_header.fs_version = ITS_SUPPORTED_VERSION;
837     return its_flash_fs_mblock_meta_update_finalize(fs_ctx);
838 }
839 
840 /**
841  * \brief Reads the active metadata block header into its_system_ctx.
842  *
843  * \param[in,out] fs_ctx  Filesystem context
844  *
845  * \return Returns error code as specified in \ref psa_status_t
846  */
its_mblock_read_meta_header(struct its_flash_fs_ctx_t * fs_ctx)847 static psa_status_t its_mblock_read_meta_header(
848                                               struct its_flash_fs_ctx_t *fs_ctx)
849 {
850     psa_status_t err;
851 
852     err = fs_ctx->ops->read(fs_ctx->cfg, fs_ctx->active_metablock,
853                             (uint8_t *)&fs_ctx->meta_block_header, 0,
854                             ITS_BLOCK_META_HEADER_SIZE);
855     if (err != PSA_SUCCESS) {
856         return err;
857     }
858 
859     return its_mblock_validate_header_meta(fs_ctx, &fs_ctx->meta_block_header,
860                                            fs_ctx->active_metablock);
861 }
862 
863 /**
864  * \brief Reserves space for an file.
865  *
866  * \param[in,out] fs_ctx      Filesystem context
867  * \param[in]     fid         File ID
868  * \param[in]     size        Size of the file for which space is reserve
869  * \param[in]     flags       Flags set when the file is created
870  * \param[out]    file_meta   File metadata entry
871  * \param[out]    block_meta  Block metadata entry
872  *
873  * \return Returns error code as specified in \ref psa_status_t
874  */
its_mblock_reserve_file(struct its_flash_fs_ctx_t * fs_ctx,const uint8_t * fid,size_t size,uint32_t flags,struct its_file_meta_t * file_meta,struct its_block_meta_t * block_meta)875 static psa_status_t its_mblock_reserve_file(struct its_flash_fs_ctx_t *fs_ctx,
876                                             const uint8_t *fid, size_t size,
877                                             uint32_t flags,
878                                             struct its_file_meta_t *file_meta,
879                                             struct its_block_meta_t *block_meta)
880 {
881     psa_status_t err;
882     uint32_t i;
883 
884     for (i = 0; i < its_num_active_dblocks(fs_ctx); i++) {
885         err = its_flash_fs_mblock_read_block_metadata(fs_ctx, i, block_meta);
886         if (err != PSA_SUCCESS) {
887             return PSA_ERROR_GENERIC_ERROR;
888         }
889 
890         if (block_meta->free_size >= size) {
891             /* Set file metadata */
892             file_meta->lblock = i;
893             file_meta->data_idx = fs_ctx->cfg->block_size
894                                   - block_meta->free_size;
895             file_meta->max_size = size;
896             memcpy(file_meta->id, fid, ITS_FILE_ID_SIZE);
897             file_meta->cur_size = 0;
898             file_meta->flags = flags;
899 
900             /* Update block metadata */
901             block_meta->free_size -= size;
902             return PSA_SUCCESS;
903         }
904     }
905 
906     /* No block has large enough space to fit the requested file */
907     return PSA_ERROR_INSUFFICIENT_STORAGE;
908 }
909 
910 /**
911  * \brief Validates and find the valid-active metablock
912  *
913  * \param[in,out] fs_ctx  Filesystem context
914  *
915  * \return Returns value as specified in \ref psa_status_t
916  */
its_init_get_active_metablock(struct its_flash_fs_ctx_t * fs_ctx)917 static psa_status_t its_init_get_active_metablock(
918                                               struct its_flash_fs_ctx_t *fs_ctx)
919 {
920     uint32_t cur_meta_block = ITS_BLOCK_INVALID_ID;
921     psa_status_t err;
922     struct its_metadata_block_header_t h_meta0;
923     struct its_metadata_block_header_t h_meta1;
924     uint8_t num_valid_meta_blocks = 0;
925 
926     /* First two blocks are reserved for metadata */
927 
928     /* Read the header of both the metdata blocks. If the read succeeds, then
929      * attempt to validate the metadata header, otherwise assume that the block
930      * update was incomplete
931      */
932     err = fs_ctx->ops->read(fs_ctx->cfg, ITS_METADATA_BLOCK0,
933                             (uint8_t *)&h_meta0, 0, ITS_BLOCK_META_HEADER_SIZE);
934     if (err == PSA_SUCCESS) {
935         if (its_mblock_validate_header_meta(fs_ctx, &h_meta0,
936                                         ITS_METADATA_BLOCK0) == PSA_SUCCESS) {
937             num_valid_meta_blocks++;
938             cur_meta_block = ITS_METADATA_BLOCK0;
939         }
940     }
941 
942     err = fs_ctx->ops->read(fs_ctx->cfg, ITS_METADATA_BLOCK1,
943                             (uint8_t *)&h_meta1, 0, ITS_BLOCK_META_HEADER_SIZE);
944     if (err == PSA_SUCCESS) {
945         if (its_mblock_validate_header_meta(fs_ctx, &h_meta1,
946                                         ITS_METADATA_BLOCK1) == PSA_SUCCESS) {
947             num_valid_meta_blocks++;
948             cur_meta_block = ITS_METADATA_BLOCK1;
949         }
950     }
951 
952     /* If there are more than 1 potential metablocks, the previous
953      * update operation was interrupted by power failure. In which case,
954      * need to find out which one is potentially latest metablock.
955      */
956     if (num_valid_meta_blocks > 1) {
957         cur_meta_block = its_mblock_latest_meta_block(fs_ctx, &h_meta0,
958                                                       &h_meta1);
959     } else if (num_valid_meta_blocks == 0) {
960         return PSA_ERROR_GENERIC_ERROR;
961     }
962 
963     fs_ctx->active_metablock = cur_meta_block;
964     fs_ctx->scratch_metablock = ITS_OTHER_META_BLOCK(cur_meta_block);
965 
966     return PSA_SUCCESS;
967 }
968 
its_flash_fs_mblock_cp_file_meta(struct its_flash_fs_ctx_t * fs_ctx,uint32_t idx_start,uint32_t idx_end)969 psa_status_t its_flash_fs_mblock_cp_file_meta(struct its_flash_fs_ctx_t *fs_ctx,
970                                               uint32_t idx_start,
971                                               uint32_t idx_end)
972 {
973     /* Calculate the positions of the two indexes in the metadata block */
974     size_t pos_start = its_mblock_file_meta_offset(fs_ctx, idx_start);
975     size_t pos_end = its_mblock_file_meta_offset(fs_ctx, idx_end);
976 
977     /* Copy all data between the two positions from the scratch metadata block
978      * to the active metadata block.
979      */
980     return its_flash_fs_block_to_block_move(fs_ctx, fs_ctx->scratch_metablock,
981                                             pos_start, fs_ctx->active_metablock,
982                                             pos_start, pos_end - pos_start);
983 }
984 
its_flash_fs_mblock_cur_data_scratch_id(struct its_flash_fs_ctx_t * fs_ctx,uint32_t lblock)985 uint32_t its_flash_fs_mblock_cur_data_scratch_id(
986                                               struct its_flash_fs_ctx_t *fs_ctx,
987                                               uint32_t lblock)
988 {
989     if (lblock == ITS_LOGICAL_DBLOCK0) {
990         /* Scratch logical data block 0 physical IDs */
991         return fs_ctx->scratch_metablock;
992     }
993 
994     return fs_ctx->meta_block_header.scratch_dblock;
995 }
996 
its_flash_fs_mblock_get_file_idx_meta(struct its_flash_fs_ctx_t * fs_ctx,const uint8_t * fid,uint32_t * idx,struct its_file_meta_t * file_meta)997 psa_status_t its_flash_fs_mblock_get_file_idx_meta(struct its_flash_fs_ctx_t *fs_ctx,
998                                                    const uint8_t *fid,
999                                                    uint32_t *idx,
1000                                                    struct its_file_meta_t *file_meta)
1001 {
1002     psa_status_t err;
1003     uint32_t i;
1004     struct its_file_meta_t tmp_metadata;
1005 
1006     for (i = 0; i < fs_ctx->cfg->max_num_files; i++) {
1007         err = its_flash_fs_mblock_read_file_meta(fs_ctx, i, &tmp_metadata);
1008         if (err != PSA_SUCCESS) {
1009             return PSA_ERROR_GENERIC_ERROR;
1010         }
1011 
1012         /* ID with value 0x00 means end of file meta section */
1013         if (!memcmp(tmp_metadata.id, fid, ITS_FILE_ID_SIZE)) {
1014             /* Found */
1015             *idx = i;
1016             if (file_meta != NULL) {
1017                 *file_meta = tmp_metadata;
1018             }
1019             return PSA_SUCCESS;
1020         }
1021     }
1022 
1023     return PSA_ERROR_DOES_NOT_EXIST;
1024 }
1025 
its_flash_fs_mblock_get_file_idx_flag(struct its_flash_fs_ctx_t * fs_ctx,uint32_t flags,uint32_t * idx)1026 psa_status_t its_flash_fs_mblock_get_file_idx_flag(
1027                                               struct its_flash_fs_ctx_t *fs_ctx,
1028                                               uint32_t flags,
1029                                               uint32_t *idx)
1030 {
1031     psa_status_t err;
1032     uint32_t i;
1033     struct its_file_meta_t tmp_metadata;
1034 
1035     for (i = 0; i < fs_ctx->cfg->max_num_files; i++) {
1036         err = its_flash_fs_mblock_read_file_meta(fs_ctx, i, &tmp_metadata);
1037         if (err != PSA_SUCCESS) {
1038             return PSA_ERROR_GENERIC_ERROR;
1039         }
1040 
1041         if (tmp_metadata.flags & flags) {
1042             /* Found */
1043             *idx = i;
1044             return PSA_SUCCESS;
1045         }
1046     }
1047 
1048     return PSA_ERROR_DOES_NOT_EXIST;
1049 }
1050 
its_flash_fs_mblock_init(struct its_flash_fs_ctx_t * fs_ctx)1051 psa_status_t its_flash_fs_mblock_init(struct its_flash_fs_ctx_t *fs_ctx)
1052 {
1053     psa_status_t err;
1054 
1055     /* Initialize Flash Interface */
1056     err = fs_ctx->ops->init(fs_ctx->cfg);
1057     if (err != PSA_SUCCESS) {
1058         return err;
1059     }
1060 
1061     err = its_init_get_active_metablock(fs_ctx);
1062     if (err != PSA_SUCCESS) {
1063         return PSA_ERROR_GENERIC_ERROR;
1064     }
1065 
1066     err = its_mblock_read_meta_header(fs_ctx);
1067     if (err != PSA_SUCCESS) {
1068         return PSA_ERROR_GENERIC_ERROR;
1069     }
1070 
1071     /* Erase the other scratch metadata block. It can be used in the later
1072      * step.
1073      */
1074     err = its_mblock_erase_scratch_blocks(fs_ctx);
1075     if (err != PSA_SUCCESS) {
1076         return PSA_ERROR_GENERIC_ERROR;
1077     }
1078 
1079     /* Upgrade the metadata header if required. */
1080     return its_mblock_upgrade_meta_header(fs_ctx);
1081 }
1082 
its_flash_fs_mblock_meta_update_finalize(struct its_flash_fs_ctx_t * fs_ctx)1083 psa_status_t its_flash_fs_mblock_meta_update_finalize(
1084                                               struct its_flash_fs_ctx_t *fs_ctx)
1085 {
1086     psa_status_t err;
1087 
1088     /* Write the metadata block header to flash */
1089     err = its_mblock_write_scratch_meta_header(fs_ctx);
1090     if (err != PSA_SUCCESS) {
1091         return err;
1092     }
1093 
1094     /* Commit metadata block modifications to flash */
1095     err = fs_ctx->ops->flush(fs_ctx->cfg, fs_ctx->scratch_metablock);
1096     if (err != PSA_SUCCESS) {
1097         return err;
1098     }
1099 
1100     /* Update the running context */
1101     its_mblock_swap_metablocks(fs_ctx);
1102 
1103     /* Erase meta block and current scratch block */
1104     return its_mblock_erase_scratch_blocks(fs_ctx);
1105 }
1106 
its_flash_fs_mblock_migrate_lb0_data_to_scratch(struct its_flash_fs_ctx_t * fs_ctx)1107 psa_status_t its_flash_fs_mblock_migrate_lb0_data_to_scratch(
1108                                               struct its_flash_fs_ctx_t *fs_ctx)
1109 {
1110     struct its_block_meta_t block_meta;
1111     size_t data_size;
1112     psa_status_t err;
1113 
1114     err = its_flash_fs_mblock_read_block_metadata(fs_ctx, ITS_LOGICAL_DBLOCK0,
1115                                                   &block_meta);
1116     if (err != PSA_SUCCESS) {
1117         return err;
1118     }
1119 
1120     /* Calculate data size stored in the B0 block */
1121     data_size = (fs_ctx->cfg->block_size - block_meta.data_start)
1122                 - block_meta.free_size;
1123 
1124     return its_flash_fs_block_to_block_move(fs_ctx, fs_ctx->scratch_metablock,
1125                                             block_meta.data_start,
1126                                             fs_ctx->active_metablock,
1127                                             block_meta.data_start, data_size);
1128 }
1129 
its_flash_fs_mblock_read_file_meta(struct its_flash_fs_ctx_t * fs_ctx,uint32_t idx,struct its_file_meta_t * file_meta)1130 psa_status_t its_flash_fs_mblock_read_file_meta(
1131                                               struct its_flash_fs_ctx_t *fs_ctx,
1132                                               uint32_t idx,
1133                                               struct its_file_meta_t *file_meta)
1134 {
1135     psa_status_t err;
1136     size_t offset;
1137 
1138     offset = its_mblock_file_meta_offset(fs_ctx, idx);
1139     err = fs_ctx->ops->read(fs_ctx->cfg, fs_ctx->active_metablock,
1140                             (uint8_t *)file_meta, offset,
1141                             ITS_FILE_METADATA_SIZE);
1142 
1143 #if ITS_VALIDATE_METADATA_FROM_FLASH
1144     if (err == PSA_SUCCESS) {
1145         err = its_mblock_validate_file_meta(fs_ctx, file_meta);
1146     }
1147 #endif
1148 
1149     return err;
1150 }
1151 
its_flash_fs_mblock_read_block_metadata(struct its_flash_fs_ctx_t * fs_ctx,uint32_t lblock,struct its_block_meta_t * block_meta)1152 psa_status_t its_flash_fs_mblock_read_block_metadata(
1153                                             struct its_flash_fs_ctx_t *fs_ctx,
1154                                             uint32_t lblock,
1155                                             struct its_block_meta_t *block_meta)
1156 {
1157     psa_status_t err;
1158     size_t pos;
1159 
1160     pos = its_mblock_block_meta_offset(lblock);
1161     err = fs_ctx->ops->read(fs_ctx->cfg, fs_ctx->active_metablock,
1162                             (uint8_t *)block_meta, pos,
1163                             ITS_BLOCK_METADATA_SIZE);
1164 
1165 #if ITS_VALIDATE_METADATA_FROM_FLASH
1166     if (err == PSA_SUCCESS) {
1167         err = its_mblock_validate_block_meta(fs_ctx, block_meta);
1168     }
1169 #endif
1170 
1171     return err;
1172 }
1173 
its_flash_fs_mblock_read_block_metadata_comp(struct its_flash_fs_ctx_t * fs_ctx,uint32_t lblock,struct its_block_meta_t * block_meta)1174 psa_status_t its_flash_fs_mblock_read_block_metadata_comp(
1175                                             struct its_flash_fs_ctx_t *fs_ctx,
1176                                             uint32_t lblock,
1177                                             struct its_block_meta_t *block_meta)
1178 {
1179     psa_status_t err;
1180     size_t pos;
1181 
1182     pos = sizeof(struct its_metadata_block_header_comp_t) +
1183                                              (lblock * ITS_BLOCK_METADATA_SIZE);
1184 
1185     err = fs_ctx->ops->read(fs_ctx->cfg, fs_ctx->active_metablock,
1186                             (uint8_t *)block_meta, pos,
1187                             ITS_BLOCK_METADATA_SIZE);
1188 
1189 #if ITS_VALIDATE_METADATA_FROM_FLASH
1190     if (err == PSA_SUCCESS) {
1191         err = its_mblock_validate_block_meta_comp(fs_ctx, block_meta);
1192     }
1193 #endif
1194 
1195     return err;
1196 }
1197 
its_flash_fs_mblock_reserve_file(struct its_flash_fs_ctx_t * fs_ctx,const uint8_t * fid,bool use_spare,size_t size,uint32_t flags,uint32_t * idx,struct its_file_meta_t * file_meta,struct its_block_meta_t * block_meta)1198 psa_status_t its_flash_fs_mblock_reserve_file(
1199                                             struct its_flash_fs_ctx_t *fs_ctx,
1200                                             const uint8_t *fid,
1201                                             bool use_spare,
1202                                             size_t size,
1203                                             uint32_t flags,
1204                                             uint32_t *idx,
1205                                             struct its_file_meta_t *file_meta,
1206                                             struct its_block_meta_t *block_meta)
1207 {
1208     psa_status_t err;
1209 
1210     err = its_mblock_reserve_file(fs_ctx, fid, size, flags, file_meta,
1211                                   block_meta);
1212 
1213     *idx = its_get_free_file_index(fs_ctx, use_spare);
1214     if ((err != PSA_SUCCESS) ||
1215         (*idx == ITS_METADATA_INVALID_INDEX)) {
1216         return PSA_ERROR_INSUFFICIENT_STORAGE;
1217     }
1218 
1219     return PSA_SUCCESS;
1220 }
1221 
its_flash_fs_mblock_reset_metablock(struct its_flash_fs_ctx_t * fs_ctx)1222 psa_status_t its_flash_fs_mblock_reset_metablock(
1223                                               struct its_flash_fs_ctx_t *fs_ctx)
1224 {
1225     struct its_block_meta_t block_meta;
1226     psa_status_t err;
1227     uint32_t i;
1228     uint32_t metablock_to_erase_first = ITS_METADATA_BLOCK0;
1229     struct its_file_meta_t file_metadata;
1230 
1231     /* Erase both metadata blocks. If at least one metadata block is valid,
1232      * ensure that the active metadata block is erased last to prevent rollback
1233      * in the case of a power failure between the two erases.
1234      */
1235     if (its_init_get_active_metablock(fs_ctx) == PSA_SUCCESS) {
1236         metablock_to_erase_first = fs_ctx->scratch_metablock;
1237     }
1238 
1239     err = fs_ctx->ops->erase(fs_ctx->cfg, metablock_to_erase_first);
1240     if (err != PSA_SUCCESS) {
1241         return err;
1242     }
1243 
1244     err = fs_ctx->ops->erase(fs_ctx->cfg,
1245                              ITS_OTHER_META_BLOCK(metablock_to_erase_first));
1246     if (err != PSA_SUCCESS) {
1247         return err;
1248     }
1249 
1250     fs_ctx->meta_block_header.active_swap_count =
1251                                     (fs_ctx->cfg->erase_val == 0x00U) ? 1U : 0U;
1252     fs_ctx->meta_block_header.scratch_dblock = its_init_scratch_dblock(fs_ctx);
1253     fs_ctx->meta_block_header.fs_version = ITS_SUPPORTED_VERSION;
1254     fs_ctx->scratch_metablock = ITS_METADATA_BLOCK1;
1255     fs_ctx->active_metablock = ITS_METADATA_BLOCK0;
1256 
1257     /* Fill the block metadata for logical datablock 0, which is given the
1258      * physical ID of the current scratch metadata block so that it is in the
1259      * active metadata block after the metadata blocks are swapped. For this
1260      * datablock, the space available for data is from the end of the metadata
1261      * to the end of the block.
1262      */
1263     block_meta.data_start =
1264         its_mblock_file_meta_offset(fs_ctx, fs_ctx->cfg->max_num_files);
1265     block_meta.free_size = fs_ctx->cfg->block_size - block_meta.data_start;
1266     block_meta.phy_id = fs_ctx->scratch_metablock;
1267     err = its_mblock_update_scratch_block_meta(fs_ctx, ITS_LOGICAL_DBLOCK0,
1268                                                &block_meta);
1269     if (err != PSA_SUCCESS) {
1270         return err;
1271     }
1272 
1273     /* Fill the block metadata for the dedicated datablocks, which have logical
1274      * ids beginning from 1 and physical ids initially beginning from
1275      * ITS_INIT_DBLOCK_START. For these datablocks, the space available for
1276      * data is the entire block.
1277      */
1278     block_meta.data_start = 0;
1279     block_meta.free_size = fs_ctx->cfg->block_size;
1280     for (i = 0; i < its_num_dedicated_dblocks(fs_ctx); i++) {
1281         /* If a flash error is detected, the code erases the rest
1282          * of the blocks anyway to remove all data stored in them.
1283          */
1284         err |= fs_ctx->ops->erase(fs_ctx->cfg,
1285                                   i + its_init_dblock_start(fs_ctx));
1286     }
1287 
1288     /* If an error is detected while erasing the flash, then return a
1289      * system error to abort core wipe process.
1290      */
1291     if (err != PSA_SUCCESS) {
1292         return PSA_ERROR_STORAGE_FAILURE;
1293     }
1294 
1295     for (i = 0; i < its_num_dedicated_dblocks(fs_ctx); i++) {
1296         block_meta.phy_id = i + its_init_dblock_start(fs_ctx);
1297         err = its_mblock_update_scratch_block_meta(fs_ctx, i + 1, &block_meta);
1298         if (err != PSA_SUCCESS) {
1299             return PSA_ERROR_GENERIC_ERROR;
1300         }
1301     }
1302 
1303     /* Initialize file metadata table */
1304     (void)memset(&file_metadata, ITS_DEFAULT_EMPTY_BUFF_VAL,
1305                  ITS_FILE_METADATA_SIZE);
1306     for (i = 0; i < fs_ctx->cfg->max_num_files; i++) {
1307         /* In the beginning phys id is same as logical id */
1308         /* Update file metadata to reflect new attributes */
1309         err = its_flash_fs_mblock_update_scratch_file_meta(fs_ctx, i,
1310                                                            &file_metadata);
1311         if (err != PSA_SUCCESS) {
1312             return PSA_ERROR_GENERIC_ERROR;
1313         }
1314     }
1315 
1316     err = its_mblock_write_scratch_meta_header(fs_ctx);
1317     if (err != PSA_SUCCESS) {
1318         return PSA_ERROR_GENERIC_ERROR;
1319     }
1320 
1321     /* Commit metadata block modifications to flash */
1322     err = fs_ctx->ops->flush(fs_ctx->cfg, fs_ctx->scratch_metablock);
1323     if (err != PSA_SUCCESS) {
1324         return err;
1325     }
1326 
1327     /* Swap active and scratch metablocks */
1328     its_mblock_swap_metablocks(fs_ctx);
1329 
1330     return PSA_SUCCESS;
1331 }
1332 
its_flash_fs_mblock_set_data_scratch(struct its_flash_fs_ctx_t * fs_ctx,uint32_t phy_id,uint32_t lblock)1333 void its_flash_fs_mblock_set_data_scratch(struct its_flash_fs_ctx_t *fs_ctx,
1334                                           uint32_t phy_id, uint32_t lblock)
1335 {
1336     if (lblock != ITS_LOGICAL_DBLOCK0) {
1337         fs_ctx->meta_block_header.scratch_dblock = phy_id;
1338     }
1339 }
1340 
its_flash_fs_mblock_update_scratch_block_meta(struct its_flash_fs_ctx_t * fs_ctx,uint32_t lblock,struct its_block_meta_t * block_meta)1341 psa_status_t its_flash_fs_mblock_update_scratch_block_meta(
1342                                             struct its_flash_fs_ctx_t *fs_ctx,
1343                                             uint32_t lblock,
1344                                             struct its_block_meta_t *block_meta)
1345 {
1346     psa_status_t err;
1347 
1348     /* If the file is the logical block 0, then update the physical ID to the
1349      * current scratch metadata block so that it is correct after the metadata
1350      * blocks are swapped.
1351      */
1352     if (lblock == ITS_LOGICAL_DBLOCK0) {
1353         block_meta->phy_id = fs_ctx->scratch_metablock;
1354     }
1355 
1356     err = its_mblock_update_scratch_block_meta(fs_ctx, lblock, block_meta);
1357     if (err != PSA_SUCCESS) {
1358         return PSA_ERROR_GENERIC_ERROR;
1359     }
1360 
1361     return its_mblock_copy_remaining_block_meta(fs_ctx, lblock);
1362 }
1363 
its_flash_fs_mblock_update_scratch_file_meta(struct its_flash_fs_ctx_t * fs_ctx,uint32_t idx,const struct its_file_meta_t * file_meta)1364 psa_status_t its_flash_fs_mblock_update_scratch_file_meta(
1365                                         struct its_flash_fs_ctx_t *fs_ctx,
1366                                         uint32_t idx,
1367                                         const struct its_file_meta_t *file_meta)
1368 {
1369     size_t pos;
1370 
1371     /* Calculate the position */
1372     pos = its_mblock_file_meta_offset(fs_ctx, idx);
1373     return fs_ctx->ops->write(fs_ctx->cfg, fs_ctx->scratch_metablock,
1374                               (const uint8_t *)file_meta, pos,
1375                               ITS_FILE_METADATA_SIZE);
1376 }
1377 
its_flash_fs_block_to_block_move(struct its_flash_fs_ctx_t * fs_ctx,uint32_t dst_block,size_t dst_offset,uint32_t src_block,size_t src_offset,size_t size)1378 psa_status_t its_flash_fs_block_to_block_move(struct its_flash_fs_ctx_t *fs_ctx,
1379                                               uint32_t dst_block,
1380                                               size_t dst_offset,
1381                                               uint32_t src_block,
1382                                               size_t src_offset,
1383                                               size_t size)
1384 {
1385     psa_status_t status;
1386     size_t bytes_to_move;
1387     uint8_t dst_block_data_copy[ITS_MAX_BLOCK_DATA_COPY];
1388 
1389     while (size > 0) {
1390         /* Calculates the number of bytes to move */
1391         bytes_to_move = ITS_UTILS_MIN(size, ITS_MAX_BLOCK_DATA_COPY);
1392 
1393         /* Reads data from source block and store it in the in-memory copy of
1394          * destination content.
1395          */
1396         status = fs_ctx->ops->read(fs_ctx->cfg, src_block, dst_block_data_copy,
1397                                    src_offset, bytes_to_move);
1398         if (status != PSA_SUCCESS) {
1399             return status;
1400         }
1401 
1402         /* Writes in flash the in-memory block content after modification */
1403         status = fs_ctx->ops->write(fs_ctx->cfg, dst_block, dst_block_data_copy,
1404                                     dst_offset, bytes_to_move);
1405         if (status != PSA_SUCCESS) {
1406             return status;
1407         }
1408 
1409         /* Updates pointers to the source and destination flash regions */
1410         dst_offset += bytes_to_move;
1411         src_offset += bytes_to_move;
1412 
1413         /* Decrement remaining size to move */
1414         size -= bytes_to_move;
1415     }
1416 
1417     return PSA_SUCCESS;
1418 }
1419