TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
its_flash_fs_mblock.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "its_flash_fs_mblock.h"
9 
10 #include "psa/storage_common.h"
11 #include "tfm_memory_utils.h"
12 
13 /* Physical ID of the two metadata blocks */
14 /* NOTE: the earmarked area may not always start at block number 0.
15  * However, the flash interface can always add the required offset.
16  */
17 #define ITS_METADATA_BLOCK0 0
18 #define ITS_METADATA_BLOCK1 1
19 
25 #define ITS_OTHER_META_BLOCK(metablock) \
26 (((metablock) == ITS_METADATA_BLOCK0) ? \
27 (ITS_METADATA_BLOCK1) : (ITS_METADATA_BLOCK0))
28 
29 #define ITS_BLOCK_META_HEADER_SIZE sizeof(struct its_metadata_block_header_t)
30 #define ITS_BLOCK_METADATA_SIZE sizeof(struct its_block_meta_t)
31 #define ITS_FILE_METADATA_SIZE sizeof(struct its_file_meta_t)
32 
33 /* FIXME: Precompute these for each context */
42 __attribute__((always_inline))
43 static inline uint32_t its_init_scratch_dblock(
44  struct its_flash_fs_ctx_t *fs_ctx)
45 {
46  /* When there are two blocks, the initial position of the scratch data block
47  * is the scratch metadata block. Otherwise, the initial position of scratch
48  * data block is immediately after the metadata blocks.
49  */
50  return fs_ctx->flash_info->num_blocks == 2 ? 1 : 2;
51 }
52 
61 __attribute__((always_inline))
62 static inline uint32_t its_init_dblock_start(struct its_flash_fs_ctx_t *fs_ctx)
63 {
64  /* Metadata and data are always stored in the same block with two blocks.
65  * Otherwise, one metadata block and two scratch blocks are reserved. One
66  * scratch block for metadata operations and the other for data operations.
67  */
68  return fs_ctx->flash_info->num_blocks == 2 ? 0 : 3;
69 }
70 
79 static uint32_t its_num_dedicated_dblocks(struct its_flash_fs_ctx_t *fs_ctx)
80 {
81  /* There are no dedicated data blocks when only two blocks are available.
82  * Otherwise, the number of blocks dedicated just for data is the number of
83  * blocks available beyond the initial datablock start index.
84  */
85  return fs_ctx->flash_info->num_blocks == 2 ? 0 :
86  fs_ctx->flash_info->num_blocks - its_init_dblock_start(fs_ctx);
87 }
88 
96 __attribute__((always_inline))
97 static inline uint32_t its_num_active_dblocks(struct its_flash_fs_ctx_t *fs_ctx)
98 {
99  /* Total number of data blocks is the number of dedicated data blocks plus
100  * logical data block 0 stored in the metadata block.
101  */
102  return its_num_dedicated_dblocks(fs_ctx) + 1;
103 }
104 
112 static size_t its_mblock_block_meta_offset(uint32_t lblock)
113 {
115 }
116 
125 static size_t its_mblock_file_meta_offset(struct its_flash_fs_ctx_t *fs_ctx,
126  uint32_t idx)
127 {
129  + (its_num_active_dblocks(fs_ctx) * ITS_BLOCK_METADATA_SIZE)
130  + (idx * ITS_FILE_METADATA_SIZE);
131 }
132 
138 static void its_mblock_swap_metablocks(struct its_flash_fs_ctx_t *fs_ctx)
139 {
140  uint32_t tmp_block;
141 
142  tmp_block = fs_ctx->scratch_metablock;
143  fs_ctx->scratch_metablock = fs_ctx->active_metablock;
144  fs_ctx->active_metablock = tmp_block;
145 }
146 
155 static uint8_t its_mblock_latest_meta_block(
156  const struct its_metadata_block_header_t *h_meta0,
157  const struct its_metadata_block_header_t *h_meta1)
158 {
159  uint8_t cur_meta;
160  uint8_t meta0_swap_count = h_meta0->active_swap_count;
161  uint8_t meta1_swap_count = h_meta1->active_swap_count;
162 
163  /* Logic: if the swap count is 0, then it has rolled over. The metadata
164  * block with a swap count of 0 is the latest one, unless the other block
165  * has a swap count of 1, in which case the roll over occurred in the
166  * previous update. In all other cases, the block with the highest swap
167  * count is the latest one.
168  */
169  if ((meta1_swap_count == 0) && (meta0_swap_count != 1)) {
170  /* Metadata block 1 swap count has rolled over and metadata block 0
171  * swap count has not, so block 1 is the latest.
172  */
173  cur_meta = ITS_METADATA_BLOCK1;
174 
175  } else if ((meta0_swap_count == 0) && (meta1_swap_count != 1)) {
176  /* Metadata block 0 swap count has rolled over and metadata block 1
177  * swap count has not, so block 0 is the latest.
178  */
179  cur_meta = ITS_METADATA_BLOCK0;
180 
181  } else if (meta1_swap_count > meta0_swap_count) {
182  /* Neither swap count has just rolled over and metadata block 1 has a
183  * higher swap count, so block 1 is the latest.
184  */
185  cur_meta = ITS_METADATA_BLOCK1;
186 
187  } else {
188  /* Neither swap count has just rolled over and metadata block 0 has a
189  * higher or equal swap count, so block 0 is the latest.
190  */
191  cur_meta = ITS_METADATA_BLOCK0;
192  }
193 
194  return cur_meta;
195 }
196 
197 #ifdef ITS_VALIDATE_METADATA_FROM_FLASH
198 
208 __attribute__((always_inline))
209 static inline psa_status_t its_mblock_validate_file_meta(
210  struct its_flash_fs_ctx_t *fs_ctx,
211  const struct its_file_meta_t *file_meta)
212 {
213  psa_status_t err;
214 
215  /* Logical block ID can not be bigger or equal than number of
216  * active blocks.
217  */
218  if (file_meta->lblock >= its_num_active_dblocks(fs_ctx)) {
219  return PSA_ERROR_DATA_CORRUPT;
220  }
221 
222  /* meta->id can be 0 if the file is not in use. If it is in
223  * use, check the metadata.
224  */
225  if (its_utils_validate_fid(file_meta->id) == PSA_SUCCESS) {
226  /* validate files values if file is in use */
227  if (file_meta->max_size > fs_ctx->flash_info->max_file_size) {
228  return PSA_ERROR_DATA_CORRUPT;
229  }
230 
231  /* The current file data size must be smaller or equal than
232  * file data max size.
233  */
234  if (file_meta->cur_size > file_meta->max_size) {
235  return PSA_ERROR_DATA_CORRUPT;
236  }
237 
238  if (file_meta->lblock == ITS_LOGICAL_DBLOCK0) {
239  /* In block 0, data index must be located after the metadata */
240  if (file_meta->data_idx < its_mblock_file_meta_offset(fs_ctx,
241  fs_ctx->flash_info->max_num_files)) {
242  return PSA_ERROR_DATA_CORRUPT;
243  }
244  }
245 
246  /* Boundary check the incoming request */
247  err = its_utils_check_contained_in(fs_ctx->flash_info->block_size,
248  file_meta->data_idx,
249  file_meta->max_size);
250  if (err != PSA_SUCCESS) {
251  return PSA_ERROR_DATA_CORRUPT;
252  }
253  }
254 
255  return PSA_SUCCESS;
256 }
257 
268 __attribute__((always_inline))
269 static inline psa_status_t its_mblock_validate_block_meta(
270  struct its_flash_fs_ctx_t *fs_ctx,
271  const struct its_block_meta_t *block_meta)
272 {
273  psa_status_t err;
274  /* Data block's data start at position 0 */
275  size_t valid_data_start_value = 0;
276 
277  if (block_meta->phy_id >= fs_ctx->flash_info->num_blocks) {
278  return PSA_ERROR_DATA_CORRUPT;
279  }
280 
281  /* Boundary check: block data start + free size can not be bigger
282  * than max block size.
283  */
284  err = its_utils_check_contained_in(fs_ctx->flash_info->block_size,
285  block_meta->data_start,
286  block_meta->free_size);
287  if (err != PSA_SUCCESS) {
288  return PSA_ERROR_DATA_CORRUPT;
289  }
290 
291  if (block_meta->phy_id == ITS_METADATA_BLOCK0 ||
292  block_meta->phy_id == ITS_METADATA_BLOCK1) {
293 
294  /* For metadata + data block, data index must start after the
295  * metadata area.
296  */
297  valid_data_start_value = its_mblock_file_meta_offset(fs_ctx,
298  fs_ctx->flash_info->max_num_files);
299  }
300 
301  if (block_meta->data_start != valid_data_start_value) {
302  return PSA_ERROR_DATA_CORRUPT;
303  }
304 
305  return PSA_SUCCESS;
306 }
307 #endif /* ITS_VALIDATE_METADATA_FROM_FLASH */
308 
318 static uint32_t its_get_free_file_index(struct its_flash_fs_ctx_t *fs_ctx,
319  bool use_spare)
320 {
321  psa_status_t err;
322  uint32_t i;
323  struct its_file_meta_t tmp_metadata;
324 
325  for (i = 0; i < fs_ctx->flash_info->max_num_files; i++) {
326  err = its_flash_fs_mblock_read_file_meta(fs_ctx, i, &tmp_metadata);
327  if (err != PSA_SUCCESS) {
329  }
330 
331  /* Check if this entry is free by checking if ID values is an
332  * invalid ID.
333  */
334  if (its_utils_validate_fid(tmp_metadata.id) != PSA_SUCCESS) {
335  if (!use_spare) {
336  /* Keep the first free file index as a spare, indicate that the
337  * next free file index should be used and continue searching.
338  */
339  use_spare = true;
340  continue;
341  }
342  /* Found */
343  return i;
344  }
345  }
346 
348 }
349 
357 static psa_status_t its_mblock_erase_scratch_blocks(
358  struct its_flash_fs_ctx_t *fs_ctx)
359 {
360  psa_status_t err;
361  uint32_t scratch_datablock;
362 
363  /* For the atomicity of the data update process
364  * and power-failure-safe operation, it is necessary that
365  * metadata scratch block is erased before data block.
366  */
367  err = fs_ctx->flash_info->erase(fs_ctx->flash_info,
368  fs_ctx->scratch_metablock);
369  if (err != PSA_SUCCESS) {
370  return err;
371  }
372 
373  /* If the number of blocks is bigger than 2, the code needs to erase the
374  * scratch block used to process any change in the data block which contains
375  * only data. Otherwise, if the number of blocks is equal to 2, it means
376  * that all data is stored in the metadata block.
377  */
378  if (fs_ctx->flash_info->num_blocks > 2) {
379  scratch_datablock =
381  (ITS_LOGICAL_DBLOCK0 + 1));
382  err = fs_ctx->flash_info->erase(fs_ctx->flash_info, scratch_datablock);
383  }
384 
385  return err;
386 }
387 
398 static psa_status_t its_mblock_update_scratch_block_meta(
399  struct its_flash_fs_ctx_t *fs_ctx,
400  uint32_t lblock,
401  const struct its_block_meta_t *block_meta)
402 {
403  size_t pos;
404 
405  /* Calculate the position */
406  pos = its_mblock_block_meta_offset(lblock);
407  return fs_ctx->flash_info->write(fs_ctx->flash_info,
408  fs_ctx->scratch_metablock,
409  (const uint8_t *)block_meta, pos,
411 }
412 
421 static psa_status_t its_mblock_copy_remaining_block_meta(
422  struct its_flash_fs_ctx_t *fs_ctx,
423  uint32_t lblock)
424 {
425  struct its_block_meta_t block_meta;
426  psa_status_t err;
427  uint32_t meta_block;
428  size_t pos;
429  uint32_t scratch_block;
430  size_t size;
431 
432  scratch_block = fs_ctx->scratch_metablock;
433  meta_block = fs_ctx->active_metablock;
434 
435  if (lblock != ITS_LOGICAL_DBLOCK0) {
436  /* The file data in the logical block 0 is stored in same physical
437  * block where the metadata is stored. A change in the metadata requires
438  * a swap of physical blocks. So, the physical block ID of logical block
439  * 0 needs to be updated to reflect this change, if the file processed
440  * is not located in logical block 0. If it is located in block 0,
441  * the physical block ID has been updated while processing the file
442  * data.
443  */
446  &block_meta);
447  if (err != PSA_SUCCESS) {
449  }
450 
451  /* Update physical ID for logical block 0 to match with the
452  * metadata block physical ID.
453  */
454  block_meta.phy_id = scratch_block;
455  err = its_mblock_update_scratch_block_meta(fs_ctx, ITS_LOGICAL_DBLOCK0,
456  &block_meta);
457  if (err != PSA_SUCCESS) {
459  }
460 
461  /* Copy the rest of metadata blocks between logical block 0 and
462  * the logical block provided in the function.
463  */
464  if (lblock > 1) {
465  pos = its_mblock_block_meta_offset(ITS_LOGICAL_DBLOCK0 + 1);
466 
467  size = its_mblock_block_meta_offset(lblock) - pos;
468 
469  /* Copy rest of the block data from previous block */
470  /* Data before updated content */
472  scratch_block, pos, meta_block,
473  pos, size);
474  if (err != PSA_SUCCESS) {
475  return err;
476  }
477  }
478  }
479 
480  /* Move meta blocks data after updated content */
481  pos = its_mblock_block_meta_offset(lblock+1);
482 
483  size = its_mblock_file_meta_offset(fs_ctx, 0) - pos;
484 
485  return its_flash_block_to_block_move(fs_ctx->flash_info, scratch_block, pos,
486  meta_block, pos, size);
487 }
488 
497 __attribute__((always_inline))
498 static inline psa_status_t its_mblock_validate_swap_count(
499  struct its_flash_fs_ctx_t *fs_ctx,
500  uint8_t swap_count)
501 {
502  /* When a flash block is erased, the default value
503  * is usually 0xFF (i.e. all 1s). Since the swap count
504  * is updated last (when encryption is disabled), it is
505  * possible that due to a power failure, the swap count
506  * value in metadata header is 0xFFFF..., which mean
507  * it will appear to be most recent block. Which isn't
508  * a problem in itself, as the rest of the metadata is fully
509  * valid (as it would have been written before swap count).
510  * However, this also means that previous update process
511  * wasn't complete. So, if the value is 0xFF..., revert
512  * back to previous metablock instead.
513  */
514  return (swap_count == fs_ctx->flash_info->erase_val)
516  : PSA_SUCCESS;
517 }
518 
526 __attribute__((always_inline))
527 static inline psa_status_t its_mblock_validate_fs_version(uint8_t fs_version)
528 {
529  /* Looks for exact version number.
530  * FIXME: backward compatibility could be considered in future revisions.
531  */
532  return (fs_version != ITS_SUPPORTED_VERSION) ? PSA_ERROR_GENERIC_ERROR
533  : PSA_SUCCESS;
534 }
535 
546 static psa_status_t its_mblock_validate_header_meta(
547  struct its_flash_fs_ctx_t *fs_ctx,
548  const struct its_metadata_block_header_t *h_meta)
549 {
550  psa_status_t err;
551 
552  err = its_mblock_validate_fs_version(h_meta->fs_version);
553  if (err == PSA_SUCCESS) {
554  err = its_mblock_validate_swap_count(fs_ctx, h_meta->active_swap_count);
555  }
556 
557  return err;
558 }
559 
567 static psa_status_t its_mblock_write_scratch_meta_header(
568  struct its_flash_fs_ctx_t *fs_ctx)
569 {
570  psa_status_t err;
571 
572  /* Increment the swap count */
574 
575  err = its_mblock_validate_swap_count(fs_ctx,
577  if (err != PSA_SUCCESS) {
578  /* Reset the swap count to 0 */
580  }
581 
582  /* Write the metadata block header */
583  return fs_ctx->flash_info->write(fs_ctx->flash_info,
584  fs_ctx->scratch_metablock,
585  (uint8_t *)(&fs_ctx->meta_block_header),
587 }
588 
596 static psa_status_t its_mblock_read_meta_header(
597  struct its_flash_fs_ctx_t *fs_ctx)
598 {
599  psa_status_t err;
600 
601  err = fs_ctx->flash_info->read(fs_ctx->flash_info, fs_ctx->active_metablock,
602  (uint8_t *)&fs_ctx->meta_block_header, 0,
604  if (err != PSA_SUCCESS) {
605  return err;
606  }
607 
608  return its_mblock_validate_header_meta(fs_ctx, &fs_ctx->meta_block_header);
609 }
610 
623 static psa_status_t its_mblock_reserve_file(struct its_flash_fs_ctx_t *fs_ctx,
624  const uint8_t *fid, size_t size,
625  uint32_t flags,
626  struct its_file_meta_t *file_meta,
627  struct its_block_meta_t *block_meta)
628 {
629  psa_status_t err;
630  uint32_t i;
631 
632  for (i = 0; i < its_num_active_dblocks(fs_ctx); i++) {
633  err = its_flash_fs_mblock_read_block_metadata(fs_ctx, i, block_meta);
634  if (err != PSA_SUCCESS) {
636  }
637 
638  if (block_meta->free_size >= size) {
639  /* Set file metadata */
640  file_meta->lblock = i;
641  file_meta->data_idx = fs_ctx->flash_info->block_size
642  - block_meta->free_size;
643  file_meta->max_size = size;
644  tfm_memcpy(file_meta->id, fid, ITS_FILE_ID_SIZE);
645  file_meta->cur_size = 0;
646  file_meta->flags = flags;
647 
648  /* Update block metadata */
649  block_meta->free_size -= size;
650  return PSA_SUCCESS;
651  }
652  }
653 
654  /* No block has large enough space to fit the requested file */
656 }
657 
665 static psa_status_t its_init_get_active_metablock(
666  struct its_flash_fs_ctx_t *fs_ctx)
667 {
668  uint32_t cur_meta_block = ITS_BLOCK_INVALID_ID;
669  psa_status_t err;
670  struct its_metadata_block_header_t h_meta0;
671  struct its_metadata_block_header_t h_meta1;
672  uint8_t num_valid_meta_blocks = 0;
673 
674  /* First two blocks are reserved for metadata */
675 
676  /* Read the header of both the metdata blocks. If the read succeeds, then
677  * attempt to validate the metadata header, otherwise assume that the block
678  * update was incomplete
679  */
680  err = fs_ctx->flash_info->read(fs_ctx->flash_info, ITS_METADATA_BLOCK0,
681  (uint8_t *)&h_meta0, 0,
683  if (err == PSA_SUCCESS) {
684  if (its_mblock_validate_header_meta(fs_ctx, &h_meta0) == PSA_SUCCESS) {
685  num_valid_meta_blocks++;
686  cur_meta_block = ITS_METADATA_BLOCK0;
687  }
688  }
689 
690  err = fs_ctx->flash_info->read(fs_ctx->flash_info, ITS_METADATA_BLOCK1,
691  (uint8_t *)&h_meta1, 0,
693  if (err == PSA_SUCCESS) {
694  if (its_mblock_validate_header_meta(fs_ctx, &h_meta1) == PSA_SUCCESS) {
695  num_valid_meta_blocks++;
696  cur_meta_block = ITS_METADATA_BLOCK1;
697  }
698  }
699 
700  /* If there are more than 1 potential metablocks, the previous
701  * update operation was interrupted by power failure. In which case,
702  * need to find out which one is potentially latest metablock.
703  */
704  if (num_valid_meta_blocks > 1) {
705  cur_meta_block = its_mblock_latest_meta_block(&h_meta0, &h_meta1);
706  } else if (num_valid_meta_blocks == 0) {
708  }
709 
710  fs_ctx->active_metablock = cur_meta_block;
711  fs_ctx->scratch_metablock = ITS_OTHER_META_BLOCK(cur_meta_block);
712 
713  return PSA_SUCCESS;
714 }
715 
717  uint32_t idx_start,
718  uint32_t idx_end)
719 {
720  /* Calculate the positions of the two indexes in the metadata block */
721  size_t pos_start = its_mblock_file_meta_offset(fs_ctx, idx_start);
722  size_t pos_end = its_mblock_file_meta_offset(fs_ctx, idx_end);
723 
724  /* Copy all data between the two positions from the scratch metadata block
725  * to the active metadata block.
726  */
728  fs_ctx->scratch_metablock, pos_start,
729  fs_ctx->active_metablock, pos_start,
730  pos_end - pos_start);
731 }
732 
734  struct its_flash_fs_ctx_t *fs_ctx,
735  uint32_t lblock)
736 {
737  if (lblock == ITS_LOGICAL_DBLOCK0) {
738  /* Scratch logical data block 0 physical IDs */
739  return fs_ctx->scratch_metablock;
740  }
741 
742  return fs_ctx->meta_block_header.scratch_dblock;
743 }
744 
746  const uint8_t *fid,
747  uint32_t *idx)
748 {
749  psa_status_t err;
750  uint32_t i;
751  struct its_file_meta_t tmp_metadata;
752 
753  for (i = 0; i < fs_ctx->flash_info->max_num_files; i++) {
754  err = its_flash_fs_mblock_read_file_meta(fs_ctx, i, &tmp_metadata);
755  if (err != PSA_SUCCESS) {
757  }
758 
759  /* ID with value 0x00 means end of file meta section */
760  if (!tfm_memcmp(tmp_metadata.id, fid, ITS_FILE_ID_SIZE)) {
761  /* Found */
762  *idx = i;
763  return PSA_SUCCESS;
764  }
765  }
766 
768 }
769 
771  struct its_flash_fs_ctx_t *fs_ctx,
772  uint32_t flags,
773  uint32_t *idx)
774 {
775  psa_status_t err;
776  uint32_t i;
777  struct its_file_meta_t tmp_metadata;
778 
779  for (i = 0; i < fs_ctx->flash_info->max_num_files; i++) {
780  err = its_flash_fs_mblock_read_file_meta(fs_ctx, i, &tmp_metadata);
781  if (err != PSA_SUCCESS) {
783  }
784 
785  if (tmp_metadata.flags & flags) {
786  /* Found */
787  *idx = i;
788  return PSA_SUCCESS;
789  }
790  }
791 
793 }
794 
796 {
797  psa_status_t err;
798 
799  /* Initialize Flash Interface */
800  err = fs_ctx->flash_info->init(fs_ctx->flash_info);
801  if (err != PSA_SUCCESS) {
802  return err;
803  }
804 
805  err = its_init_get_active_metablock(fs_ctx);
806  if (err != PSA_SUCCESS) {
808  }
809 
810  err = its_mblock_read_meta_header(fs_ctx);
811  if (err != PSA_SUCCESS) {
813  }
814 
815  /* Erase the other scratch metadata block */
816  return its_mblock_erase_scratch_blocks(fs_ctx);
817 }
818 
820  struct its_flash_fs_ctx_t *fs_ctx)
821 {
822  psa_status_t err;
823 
824  /* Write the metadata block header to flash */
825  err = its_mblock_write_scratch_meta_header(fs_ctx);
826  if (err != PSA_SUCCESS) {
827  return err;
828  }
829 
830  /* Commit metadata block modifications to flash */
831  err = fs_ctx->flash_info->flush(fs_ctx->flash_info);
832  if (err != PSA_SUCCESS) {
833  return err;
834  }
835 
836  /* Update the running context */
837  its_mblock_swap_metablocks(fs_ctx);
838 
839  /* Erase meta block and current scratch block */
840  return its_mblock_erase_scratch_blocks(fs_ctx);
841 }
842 
844  struct its_flash_fs_ctx_t *fs_ctx)
845 {
846  struct its_block_meta_t block_meta;
847  size_t data_size;
848  psa_status_t err;
849 
851  &block_meta);
852  if (err != PSA_SUCCESS) {
853  return err;
854  }
855 
856  /* Calculate data size stored in the B0 block */
857  data_size = (fs_ctx->flash_info->block_size - block_meta.data_start)
858  - block_meta.free_size;
859 
861  fs_ctx->scratch_metablock,
862  block_meta.data_start,
863  fs_ctx->active_metablock,
864  block_meta.data_start,
865  data_size);
866 }
867 
869  struct its_flash_fs_ctx_t *fs_ctx,
870  uint32_t idx,
871  struct its_file_meta_t *file_meta)
872 {
873  psa_status_t err;
874  size_t offset;
875 
876  offset = its_mblock_file_meta_offset(fs_ctx, idx);
877  err = fs_ctx->flash_info->read(fs_ctx->flash_info, fs_ctx->active_metablock,
878  (uint8_t *)file_meta, offset,
880 
881 #ifdef ITS_VALIDATE_METADATA_FROM_FLASH
882  if (err == PSA_SUCCESS) {
883  err = its_mblock_validate_file_meta(fs_ctx, file_meta);
884  }
885 #endif
886 
887  return err;
888 }
889 
891  struct its_flash_fs_ctx_t *fs_ctx,
892  uint32_t lblock,
893  struct its_block_meta_t *block_meta)
894 {
895  psa_status_t err;
896  size_t pos;
897 
898  pos = its_mblock_block_meta_offset(lblock);
899  err = fs_ctx->flash_info->read(fs_ctx->flash_info, fs_ctx->active_metablock,
900  (uint8_t *)block_meta, pos,
902 
903 #ifdef ITS_VALIDATE_METADATA_FROM_FLASH
904  if (err == PSA_SUCCESS) {
905  err = its_mblock_validate_block_meta(fs_ctx, block_meta);
906  }
907 #endif
908 
909  return err;
910 }
911 
913  struct its_flash_fs_ctx_t *fs_ctx,
914  const uint8_t *fid,
915  bool use_spare,
916  size_t size,
917  uint32_t flags,
918  uint32_t *idx,
919  struct its_file_meta_t *file_meta,
920  struct its_block_meta_t *block_meta)
921 {
922  psa_status_t err;
923 
924  err = its_mblock_reserve_file(fs_ctx, fid, size, flags, file_meta,
925  block_meta);
926 
927  *idx = its_get_free_file_index(fs_ctx, use_spare);
928  if ((err != PSA_SUCCESS) ||
929  (*idx == ITS_METADATA_INVALID_INDEX)) {
931  }
932 
933  return PSA_SUCCESS;
934 }
935 
937  struct its_flash_fs_ctx_t *fs_ctx)
938 {
939  struct its_block_meta_t block_meta;
940  psa_status_t err;
941  uint32_t i;
942  uint32_t metablock_to_erase_first = ITS_METADATA_BLOCK0;
943  struct its_file_meta_t file_metadata;
944 
945  /* Erase both metadata blocks. If at least one metadata block is valid,
946  * ensure that the active metadata block is erased last to prevent rollback
947  * in the case of a power failure between the two erases.
948  */
949  if (its_init_get_active_metablock(fs_ctx) == PSA_SUCCESS) {
950  metablock_to_erase_first = fs_ctx->scratch_metablock;
951  }
952 
953  err = fs_ctx->flash_info->erase(fs_ctx->flash_info,
954  metablock_to_erase_first);
955  if (err != PSA_SUCCESS) {
956  return err;
957  }
958 
959  err = fs_ctx->flash_info->erase(fs_ctx->flash_info,
960  ITS_OTHER_META_BLOCK(metablock_to_erase_first));
961  if (err != PSA_SUCCESS) {
962  return err;
963  }
964 
966  fs_ctx->meta_block_header.scratch_dblock = its_init_scratch_dblock(fs_ctx);
970 
971  /* Fill the block metadata for logical datablock 0, which has the physical
972  * id of the active metadata block. For this datablock, the space available
973  * for data is from the end of the metadata to the end of the block.
974  */
975  block_meta.data_start =
976  its_mblock_file_meta_offset(fs_ctx, fs_ctx->flash_info->max_num_files);
977  block_meta.free_size = fs_ctx->flash_info->block_size
978  - block_meta.data_start;
979  block_meta.phy_id = ITS_METADATA_BLOCK0;
980  err = its_mblock_update_scratch_block_meta(fs_ctx, ITS_LOGICAL_DBLOCK0,
981  &block_meta);
982  if (err != PSA_SUCCESS) {
983  return err;
984  }
985 
986  /* Fill the block metadata for the dedicated datablocks, which have logical
987  * ids beginning from 1 and physical ids initially beginning from
988  * ITS_INIT_DBLOCK_START. For these datablocks, the space available for
989  * data is the entire block.
990  */
991  block_meta.data_start = 0;
992  block_meta.free_size = fs_ctx->flash_info->block_size;
993  for (i = 0; i < its_num_dedicated_dblocks(fs_ctx); i++) {
994  /* If a flash error is detected, the code erases the rest
995  * of the blocks anyway to remove all data stored in them.
996  */
997  err |= fs_ctx->flash_info->erase(fs_ctx->flash_info,
998  i + its_init_dblock_start(fs_ctx));
999  }
1000 
1001  /* If an error is detected while erasing the flash, then return a
1002  * system error to abort core wipe process.
1003  */
1004  if (err != PSA_SUCCESS) {
1006  }
1007 
1008  for (i = 0; i < its_num_dedicated_dblocks(fs_ctx); i++) {
1009  block_meta.phy_id = i + its_init_dblock_start(fs_ctx);
1010  err = its_mblock_update_scratch_block_meta(fs_ctx, i + 1, &block_meta);
1011  if (err != PSA_SUCCESS) {
1012  return PSA_ERROR_GENERIC_ERROR;
1013  }
1014  }
1015 
1016  /* Initialize file metadata table */
1017  (void)tfm_memset(&file_metadata, ITS_DEFAULT_EMPTY_BUFF_VAL,
1019  for (i = 0; i < fs_ctx->flash_info->max_num_files; i++) {
1020  /* In the beginning phys id is same as logical id */
1021  /* Update file metadata to reflect new attributes */
1023  &file_metadata);
1024  if (err != PSA_SUCCESS) {
1025  return PSA_ERROR_GENERIC_ERROR;
1026  }
1027  }
1028 
1029  err = its_mblock_write_scratch_meta_header(fs_ctx);
1030  if (err != PSA_SUCCESS) {
1031  return PSA_ERROR_GENERIC_ERROR;
1032  }
1033 
1034  /* Commit metadata block modifications to flash */
1035  err = fs_ctx->flash_info->flush(fs_ctx->flash_info);
1036  if (err != PSA_SUCCESS) {
1037  return err;
1038  }
1039 
1040  /* Swap active and scratch metablocks */
1041  its_mblock_swap_metablocks(fs_ctx);
1042 
1043  return PSA_SUCCESS;
1044 }
1045 
1047  uint32_t phy_id, uint32_t lblock)
1048 {
1049  if (lblock != ITS_LOGICAL_DBLOCK0) {
1050  fs_ctx->meta_block_header.scratch_dblock = phy_id;
1051  }
1052 }
1053 
1055  struct its_flash_fs_ctx_t *fs_ctx,
1056  uint32_t lblock,
1057  struct its_block_meta_t *block_meta)
1058 {
1059  psa_status_t err;
1060 
1061  /* If the file is the logical block 0, then update the physical ID to the
1062  * current scratch metadata block so that it is correct after the metadata
1063  * blocks are swapped.
1064  */
1065  if (lblock == ITS_LOGICAL_DBLOCK0) {
1066  block_meta->phy_id = fs_ctx->scratch_metablock;
1067  }
1068 
1069  err = its_mblock_update_scratch_block_meta(fs_ctx, lblock, block_meta);
1070  if (err != PSA_SUCCESS) {
1071  return PSA_ERROR_GENERIC_ERROR;
1072  }
1073 
1074  return its_mblock_copy_remaining_block_meta(fs_ctx, lblock);
1075 }
1076 
1078  struct its_flash_fs_ctx_t *fs_ctx,
1079  uint32_t idx,
1080  const struct its_file_meta_t *file_meta)
1081 {
1082  size_t pos;
1083 
1084  /* Calculate the position */
1085  pos = its_mblock_file_meta_offset(fs_ctx, idx);
1086  return fs_ctx->flash_info->write(fs_ctx->flash_info,
1087  fs_ctx->scratch_metablock,
1088  (const uint8_t *)file_meta, pos,
1090 }
#define ITS_OTHER_META_BLOCK(metablock)
Macro to get the the swap metadata block.
psa_status_t 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)
Puts logical block's metadata in scratch metadata block.
const struct its_flash_info_t * flash_info
#define ITS_LOGICAL_DBLOCK0
Defines logical data block 0 ID.
psa_status_t its_flash_fs_mblock_get_file_idx(struct its_flash_fs_ctx_t *fs_ctx, const uint8_t *fid, uint32_t *idx)
Gets file metadata entry index.
psa_status_t(* erase)(const struct its_flash_info_t *info, uint32_t block_id)
Erases block ID data.
Definition: its_flash.h:152
#define PSA_ERROR_STORAGE_FAILURE
__STATIC_INLINE void * tfm_memset(void *ptr, int value, size_t num)
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define ITS_BLOCK_META_HEADER_SIZE
uint8_t id[ITS_FILE_ID_SIZE]
psa_status_t its_utils_validate_fid(const uint8_t *fid)
Validates file ID.
Definition: its_utils.c:30
uint16_t block_size
Definition: its_flash.h:160
Structure to store information about each physical flash memory block.
psa_status_t 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)
Reads specified logical block metadata.
#define ITS_FILE_METADATA_SIZE
struct its_metadata_block_header_t meta_block_header
psa_status_t its_flash_block_to_block_move(const struct its_flash_info_t *info, uint32_t dst_block, size_t dst_offset, uint32_t src_block, size_t src_offset, size_t size)
Moves data from source block ID to destination block ID.
Definition: its_flash.c:56
uint32_t its_flash_fs_mblock_cur_data_scratch_id(struct its_flash_fs_ctx_t *fs_ctx, uint32_t lblock)
Gets current scratch datablock physical ID.
psa_status_t 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)
Reserves space for a file.
#define PSA_ERROR_INSUFFICIENT_STORAGE
void its_flash_fs_mblock_set_data_scratch(struct its_flash_fs_ctx_t *fs_ctx, uint32_t phy_id, uint32_t lblock)
Sets current data scratch block.
psa_status_t(* read)(const struct its_flash_info_t *info, uint32_t block_id, uint8_t *buff, size_t offset, size_t size)
Reads block data from the position specified by block ID and offset.
Definition: its_flash.h:101
#define PSA_ERROR_GENERIC_ERROR
Definition: crypto_values.h:43
psa_status_t its_flash_fs_mblock_reset_metablock(struct its_flash_fs_ctx_t *fs_ctx)
Resets metablock by cleaning and initializing the metadatablock.
Structure to store file metadata.
psa_status_t its_utils_check_contained_in(size_t superset_size, size_t subset_offset, size_t subset_size)
Checks if a subset region is fully contained within a superset region.
Definition: its_utils.c:10
uint16_t num_blocks
Definition: its_flash.h:164
#define ITS_FILE_ID_SIZE
Definition: its_utils.h:20
#define ITS_METADATA_INVALID_INDEX
Defines the invalid index value when the metadata table is full.
#define ITS_SUPPORTED_VERSION
Defines the supported version.
psa_status_t(* flush)(const struct its_flash_info_t *info)
Flushes modifications to a block to flash. Must be called after a sequence of calls to write() (inclu...
Definition: its_flash.h:139
psa_status_t its_flash_fs_mblock_meta_update_finalize(struct its_flash_fs_ctx_t *fs_ctx)
Finalizes an update operation. Last step when a create/write/delete is performed. ...
#define ITS_BLOCK_METADATA_SIZE
psa_status_t 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)
Reads specified file metadata.
psa_status_t its_flash_fs_mblock_get_file_idx_flag(struct its_flash_fs_ctx_t *fs_ctx, uint32_t flags, uint32_t *idx)
Gets file metadata entry index of the first file with one of the provided flags set.
__STATIC_INLINE void * tfm_memcpy(void *dest, const void *src, size_t num)
Structure to store the metadata block header.
__STATIC_INLINE int tfm_memcmp(const void *ptr1, const void *ptr2, size_t num)
psa_status_t its_flash_fs_mblock_cp_file_meta(struct its_flash_fs_ctx_t *fs_ctx, uint32_t idx_start, uint32_t idx_end)
Copies the file metadata entries between two indexes from the active metadata block to the scratch me...
Structure to store the ITS flash file system context.
psa_status_t(* init)(const struct its_flash_info_t *info)
Initialize the Flash Interface.
Definition: its_flash.h:82
#define ITS_METADATA_BLOCK1
#define PSA_ERROR_DOES_NOT_EXIST
Definition: crypto_values.h:89
uint16_t max_num_files
Definition: its_flash.h:167
#define ITS_BLOCK_INVALID_ID
Definition: its_flash.h:24
psa_status_t 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)
Writes a file metadata entry into scratch metadata block.
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
#define PSA_ERROR_DATA_CORRUPT
#define ITS_DEFAULT_EMPTY_BUFF_VAL
Definition: its_utils.h:21
psa_status_t its_flash_fs_mblock_init(struct its_flash_fs_ctx_t *fs_ctx)
Initializes metadata block with the valid/active metablock.
#define ITS_METADATA_BLOCK0
psa_status_t(* write)(const struct its_flash_info_t *info, uint32_t block_id, const uint8_t *buff, size_t offset, size_t size)
Writes block data to the position specified by block ID and offset.
Definition: its_flash.h:121
psa_status_t its_flash_fs_mblock_migrate_lb0_data_to_scratch(struct its_flash_fs_ctx_t *fs_ctx)
Writes the files data area of logical block 0 into the scratch block.