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