1 /*
2  * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #ifndef __ITS_FLASH_FS_MBLOCK_H__
9 #define __ITS_FLASH_FS_MBLOCK_H__
10 
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 
15 #include "flash/its_flash.h"
16 #include "its_flash_fs.h"
17 #include "its_utils.h"
18 #include "psa/error.h"
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /*!
25  * \def ITS_SUPPORTED_VERSION
26  *
27  * \brief Defines the supported version.
28  */
29 #define ITS_SUPPORTED_VERSION  0x02
30 
31 /*!
32  * \def ITS_BACKWARD_SUPPORTED_VERSION
33  *
34  * \brief Defines the backward supported version.
35  */
36 #define ITS_BACKWARD_SUPPORTED_VERSION  0x01
37 
38 /*!
39  * \def ITS_METADATA_INVALID_INDEX
40  *
41  * \brief Defines the invalid index value when the metadata table is full
42  */
43 #define ITS_METADATA_INVALID_INDEX 0xFFFF
44 
45 /*!
46  * \def ITS_LOGICAL_DBLOCK0
47  *
48  * \brief Defines logical data block 0 ID
49  */
50 #define ITS_LOGICAL_DBLOCK0  0
51 
52 /*!
53  * \struct its_metadata_block_header_t
54  *
55  * \brief Structure to store the metadata block header.
56  *
57  * \note The active_swap_count must be the last member to allow it to be
58  *       programmed last.
59  *       The fs_version must be at the same position as it is in
60  *       its_metadata_block_header_comp_t.
61  *
62  * \note This structure is programmed to flash, so its size must be padded
63  *       to a multiple of the maximum required flash program unit.
64  */
65 #define _T1 \
66     uint32_t scratch_dblock;    /*!< Physical block ID of the data \
67                                  *   section's scratch block \
68                                  */ \
69     uint8_t fs_version;         /*!< Filesystem version */ \
70     uint8_t metadata_xor;       /*!< XOR value based on the whole metadata(not \
71                                  *   including the metadata block header) \
72                                  */ \
73     uint8_t active_swap_count;  /*!< Number of times the metadata blocks have \
74                                  *   been swapped \
75                                  */
76 
77 struct its_metadata_block_header_t {
78     _T1
79 #if ((ITS_FLASH_MAX_ALIGNMENT) > 4)
80     uint8_t roundup[sizeof(struct __attribute__((__aligned__(ITS_FLASH_MAX_ALIGNMENT))) { _T1 }) -
81                     sizeof(struct { _T1 })]; /*!< _T1 has aligned to the maximum
82                                               *   field scratch_dblock which is
83                                               *   4 bytes.
84                                               */
85 #endif
86 };
87 #undef _T1
88 
89 /*!
90  * \struct its_metadata_block_header_comp_t
91  *
92  * \brief The struture of metadata block header in
93  *        ITS_BACKWARD_SUPPORTED_VERSION.
94  *
95  * \note The active_swap_count must be the last member to allow it to be
96  *       programmed last.
97  *
98  * \note This structure is programmed to flash, so its size must be padded
99  *       to a multiple of the maximum required flash program unit.
100  */
101 #define _T1_COMP \
102     uint32_t scratch_dblock;    /*!< Physical block ID of the data \
103                                  *   section's scratch block \
104                                  */ \
105     uint8_t fs_version;         /*!< Filesystem version */ \
106     uint8_t active_swap_count;  /*!< Number of times the metadata blocks have \
107                                  *   been swapped \
108                                  */
109 
110 struct its_metadata_block_header_comp_t {
111     _T1_COMP
112 #if ((ITS_FLASH_MAX_ALIGNMENT) > 4)
113     uint8_t roundup[sizeof(struct __attribute__((__aligned__(ITS_FLASH_MAX_ALIGNMENT))) { _T1_COMP }) -
114                     sizeof(struct { _T1_COMP })];
115 #endif
116 };
117 #undef _T1_COMP
118 
119 /*!
120  * \struct its_block_meta_t
121  *
122  * \brief Structure to store information about each physical flash memory block.
123  *
124  * \note This structure is programmed to flash, so its size must be padded
125  *       to a multiple of the maximum required flash program unit.
126  */
127 #define _T2 \
128     uint32_t phy_id;    /*!< Physical ID of this logical block */ \
129     size_t data_start;  /*!< Offset from the beginning of the block to the \
130                          *   location where the data starts \
131                          */ \
132     size_t free_size;   /*!< Number of bytes free at end of block (set during \
133                          *   block compaction for gap reuse) \
134                          */
135 
136 struct its_block_meta_t {
137     _T2
138 #if ((ITS_FLASH_MAX_ALIGNMENT) > 4)
139     uint8_t roundup[sizeof(struct __attribute__((__aligned__(ITS_FLASH_MAX_ALIGNMENT))) { _T2 }) -
140                     sizeof(struct { _T2 })];
141 #endif
142 };
143 #undef _T2
144 
145 /*!
146  * \struct its_file_meta_t
147  *
148  * \brief Structure to store file metadata.
149  *
150  * \note This structure is programmed to flash, so its size must be padded
151  *       to a multiple of the maximum required flash program unit.
152  */
153 #ifdef ITS_ENCRYPTION
154     #define _T3 \
155     uint32_t lblock;               /* Logical datablock where file is stored */ \
156     size_t data_idx;               /* Offset in the logical data block */ \
157     size_t cur_size;               /* Size in storage system for this fragment */ \
158     size_t max_size;               /* Maximum size of this file */ \
159     uint32_t flags;                /* Flags set when the file was created */ \
160     uint8_t id[ITS_FILE_ID_SIZE];  /* ID of this file */ \
161     uint8_t nonce[TFM_ITS_ENC_NONCE_LENGTH]; \
162     uint8_t tag[TFM_ITS_AUTH_TAG_LENGTH]
163 #else
164     #define _T3 \
165     uint32_t lblock;               /* Logical datablock where file is stored */ \
166     size_t data_idx;               /* Offset in the logical data block */ \
167     size_t cur_size;               /* Size in storage system for this fragment */ \
168     size_t max_size;               /* Maximum size of this file */ \
169     uint32_t flags;                /* Flags set when the file was created */ \
170     uint8_t id[ITS_FILE_ID_SIZE]   /* ID of this file */
171 #endif
172 
173 struct its_file_meta_t {
174     _T3;
175 #if ((ITS_FLASH_MAX_ALIGNMENT) > 4)
176     uint8_t roundup[sizeof(struct __attribute__((__aligned__(ITS_FLASH_MAX_ALIGNMENT))) { _T3; }) -
177                     sizeof(struct { _T3; })];
178 #endif
179 };
180 #undef _T3
181 
182 /**
183  * \struct its_flash_fs_ctx_t
184  *
185  * \brief Structure to store the ITS flash file system context.
186  */
187 struct its_flash_fs_ctx_t {
188     const struct its_flash_fs_config_t *cfg; /**< Filesystem configuration */
189     const struct its_flash_fs_ops_t *ops;    /**< Filesystem flash operations */
190     struct its_metadata_block_header_t meta_block_header; /**< Metadata block
191                                                            *   header
192                                                            */
193     uint32_t active_metablock;  /**< Active metadata block */
194     uint32_t scratch_metablock; /**< Scratch metadata block */
195 };
196 
197 /**
198  * \brief Initializes metadata block with the valid/active metablock.
199  *
200  * \param[in,out] fs_ctx  Filesystem context
201  *
202  * \return Returns value as specified in \ref psa_status_t
203  */
204 psa_status_t its_flash_fs_mblock_init(struct its_flash_fs_ctx_t *fs_ctx);
205 
206 /**
207  * \brief Copies the file metadata entries between two indexes from the active
208  *        metadata block to the scratch metadata block.
209  *
210  * \param[in,out] fs_ctx     Filesystem context
211  * \param[in]     idx_start  File metadata entry index to start copy, inclusive
212  * \param[in]     idx_end    File metadata entry index to end copy, exclusive
213  *
214  * \return Returns error code as specified in \ref psa_status_t
215  */
216 psa_status_t its_flash_fs_mblock_cp_file_meta(struct its_flash_fs_ctx_t *fs_ctx,
217                                               uint32_t idx_start,
218                                               uint32_t idx_end);
219 
220 /**
221  * \brief Gets current scratch datablock physical ID.
222  *
223  * \param[in,out] fs_ctx  Filesystem context
224  * \param[in]     lblock  Logical block number
225  *
226  * \return current scratch data block
227  */
228 uint32_t its_flash_fs_mblock_cur_data_scratch_id(
229                                               struct its_flash_fs_ctx_t *fs_ctx,
230                                               uint32_t lblock);
231 
232 /**
233  * \brief Gets file metadata entry index and file metadata.
234  *
235  * \note  A NULL [file_meta] indicates ignoring file meta.
236  *
237  * \param[in,out]       fs_ctx      Filesystem context
238  * \param[in]           fid         ID of the file
239  * \param[out]          idx         Index of the file metadata in the file system
240  * \param[out]          file_meta   Pointer to file meta structure
241  *
242  * \return Returns error code as specified in \ref psa_status_t
243  */
244 psa_status_t its_flash_fs_mblock_get_file_idx_meta(struct its_flash_fs_ctx_t *fs_ctx,
245                                                    const uint8_t *fid,
246                                                    uint32_t *idx,
247                                                    struct its_file_meta_t *file_meta);
248 /**
249  * \brief Gets file metadata entry index of the first file with one of the
250  *        provided flags set.
251  *
252  * \param[in,out] fs_ctx  Filesystem context
253  * \param[in]     flags   Flags to search for
254  * \param[out]    idx     Index of the file metadata in the file system
255  *
256  * \return Returns error code as specified in \ref psa_status_t
257  */
258 psa_status_t its_flash_fs_mblock_get_file_idx_flag(
259                                               struct its_flash_fs_ctx_t *fs_ctx,
260                                               uint32_t flags,
261                                               uint32_t *idx);
262 
263 /**
264  * \brief Finalizes an update operation.
265  *        Last step when a create/write/delete is performed.
266  *
267  * \param[in,out] fs_ctx  Filesystem context
268  *
269  * \return Returns offset value in metadata block
270  */
271 psa_status_t its_flash_fs_mblock_meta_update_finalize(
272                                              struct its_flash_fs_ctx_t *fs_ctx);
273 
274 /**
275  * \brief Writes the files data area of logical block 0 into the scratch
276  *        block.
277  *
278  * \note The files data in the logical block 0 is stored in same physical
279  *       block where the metadata is stored. A change in the metadata requires a
280  *       swap of physical blocks. So, the files data stored in the current
281  *       medadata block needs to be copied in the scratch block, unless
282  *       the data of the file processed is located in the logical block 0.
283  *
284  * \param[in,out] fs_ctx  Filesystem context
285  *
286  * \return Returns error code as specified in \ref psa_status_t
287  */
288 psa_status_t its_flash_fs_mblock_migrate_lb0_data_to_scratch(
289                                              struct its_flash_fs_ctx_t *fs_ctx);
290 
291 /**
292  * \brief Reads specified file metadata.
293  *
294  * \param[in,out] fs_ctx     Filesystem context
295  * \param[in]     idx        File metadata entry index
296  * \param[out]    file_meta  Pointer to file meta structure
297  *
298  * \return Returns error code as specified in \ref psa_status_t
299  */
300 psa_status_t its_flash_fs_mblock_read_file_meta(
301                                              struct its_flash_fs_ctx_t *fs_ctx,
302                                              uint32_t idx,
303                                              struct its_file_meta_t *file_meta);
304 
305 /**
306  * \brief Reads specified logical block metadata.
307  *
308  * \param[in,out] fs_ctx      Filesystem context
309  * \param[in]     lblock      Logical block number
310  * \param[out]    block_meta  Pointer to block meta structure
311  *
312  * \return Returns error code as specified in \ref psa_status_t
313  */
314 psa_status_t its_flash_fs_mblock_read_block_metadata(
315                                            struct its_flash_fs_ctx_t *fs_ctx,
316                                            uint32_t lblock,
317                                            struct its_block_meta_t *block_meta);
318 
319 /**
320  * \brief Reads specified logical block metadata based on the backward
321  *        compatible FS.
322  *
323  * \param[in,out] fs_ctx      Filesystem context
324  * \param[in]     lblock      Logical block number
325  * \param[out]    block_meta  Pointer to block meta structure
326  *
327  * \return Returns error code as specified in \ref psa_status_t
328  */
329 psa_status_t its_flash_fs_mblock_read_block_metadata_comp(
330                                         struct its_flash_fs_ctx_t *fs_ctx,
331                                         uint32_t lblock,
332                                         struct its_block_meta_t *block_meta);
333 
334 /**
335  * \brief Reserves space for a file.
336  *
337  * \param[in,out] fs_ctx         Filesystem context
338  * \param[in]     fid            File ID
339  * \param[in]     use_spare      If true then the spare file will be used,
340  *                               otherwise at least one file will be left free
341  * \param[in]     size           Size of the file for which space is reserve
342  * \param[in]     flags          Flags set when the file was created
343  * \param[out]    file_meta_idx  File metadata entry index
344  * \param[out]    file_meta      File metadata entry
345  * \param[out]    block_meta     Block metadata entry
346  *
347  * \return Returns error code as specified in \ref psa_status_t
348  */
349 psa_status_t its_flash_fs_mblock_reserve_file(
350                                            struct its_flash_fs_ctx_t *fs_ctx,
351                                            const uint8_t *fid,
352                                            bool use_spare,
353                                            size_t size,
354                                            uint32_t flags,
355                                            uint32_t *file_meta_idx,
356                                            struct its_file_meta_t *file_meta,
357                                            struct its_block_meta_t *block_meta);
358 
359 /**
360  * \brief Resets metablock by cleaning and initializing the metadatablock.
361  *
362  * \param[in,out] fs_ctx  Filesystem context
363  *
364  * \return Returns value as specified in \ref psa_status_t
365  */
366 psa_status_t its_flash_fs_mblock_reset_metablock(
367                                              struct its_flash_fs_ctx_t *fs_ctx);
368 
369 /**
370  * \brief Sets current data scratch block
371  *
372  * \param[in,out] fs_ctx  Filesystem context
373  * \param[in]     phy_id  Physical ID of scratch data block
374  * \param[in]     lblock  Logical block number
375  */
376 void its_flash_fs_mblock_set_data_scratch(struct its_flash_fs_ctx_t *fs_ctx,
377                                           uint32_t phy_id, uint32_t lblock);
378 
379 /**
380  * \brief Puts logical block's metadata in scratch metadata block
381  *
382  * \param[in,out] fs_ctx      Filesystem context
383  * \param[in]     lblock      Logical block number
384  * \param[in]     block_meta  Pointer to block's metadata
385  *
386  * \return Returns error code as specified in \ref psa_status_t
387  */
388 psa_status_t its_flash_fs_mblock_update_scratch_block_meta(
389                                            struct its_flash_fs_ctx_t *fs_ctx,
390                                            uint32_t lblock,
391                                            struct its_block_meta_t *block_meta);
392 
393 /**
394  * \brief Writes a file metadata entry into scratch metadata block.
395  *
396  * \param[in,out] fs_ctx     Filesystem context
397  * \param[in]     idx        File's index in the metadata table
398  * \param[in]     file_meta  Metadata pointer
399  *
400  * \return Returns error code as specified in \ref psa_status_t
401  */
402 psa_status_t its_flash_fs_mblock_update_scratch_file_meta(
403                                        struct its_flash_fs_ctx_t *fs_ctx,
404                                        uint32_t idx,
405                                        const struct its_file_meta_t *file_meta);
406 
407 /**
408  * \brief Moves data from source block ID to destination block ID.
409  *
410  * \param[in] fs_ctx      Filesystem context
411  * \param[in] dst_block   Destination block ID
412  * \param[in] dst_offset  Destination offset position from the init of the
413  *                        destination block
414  * \param[in] src_block   Source block ID
415  * \param[in] src_offset  Source offset position from the init of the source
416  *                        block
417  * \param[in] size        Number of bytes to moves
418  *
419  * \note This function assumes all input values are valid. That is, the address
420  *       range, based on blockid, offset and size, is a valid range in flash.
421  *       It also assumes that the destination block is already erased and ready
422  *       to be written.
423  *
424  * \return Returns PSA_SUCCESS if the function is executed correctly. Otherwise,
425  *         it returns PSA_ERROR_STORAGE_FAILURE.
426  */
427 psa_status_t its_flash_fs_block_to_block_move(struct its_flash_fs_ctx_t *fs_ctx,
428                                               uint32_t dst_block,
429                                               size_t dst_offset,
430                                               uint32_t src_block,
431                                               size_t src_offset,
432                                               size_t size);
433 
434 #ifdef __cplusplus
435 }
436 #endif
437 
438 #endif /* __ITS_FLASH_FS_MBLOCK_H__ */
439