1 /*
2  * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "its_flash_fs_dblock.h"
9 
10 #include "its_flash_fs.h"
11 
12 /**
13  * \brief Converts logical data block number to physical number.
14  *
15  * \param[in,out] fs_ctx  Filesystem context
16  * \param[in]     lblock  Logical block number
17  *
18  * \return Return physical block number.
19  */
its_dblock_lo_to_phy(struct its_flash_fs_ctx_t * fs_ctx,uint32_t lblock)20 static uint32_t its_dblock_lo_to_phy(struct its_flash_fs_ctx_t *fs_ctx,
21                                      uint32_t lblock)
22 {
23     struct its_block_meta_t block_meta;
24     psa_status_t err;
25 
26     err = its_flash_fs_mblock_read_block_metadata(fs_ctx, lblock, &block_meta);
27     if (err != PSA_SUCCESS) {
28         return ITS_BLOCK_INVALID_ID;
29     }
30 
31     return block_meta.phy_id;
32 }
33 
its_flash_fs_dblock_compact_block(struct its_flash_fs_ctx_t * fs_ctx,uint32_t lblock,size_t free_size,size_t src_offset,size_t dst_offset,size_t size)34 psa_status_t its_flash_fs_dblock_compact_block(
35                                               struct its_flash_fs_ctx_t *fs_ctx,
36                                               uint32_t lblock,
37                                               size_t free_size,
38                                               size_t src_offset,
39                                               size_t dst_offset,
40                                               size_t size)
41 {
42     struct its_block_meta_t block_meta;
43     psa_status_t err;
44     uint32_t scratch_id = 0;
45     int8_t flush_data = 0;
46 
47     /* Read current block meta */
48     err = its_flash_fs_mblock_read_block_metadata(fs_ctx, lblock, &block_meta);
49     if (err != PSA_SUCCESS) {
50         return err;
51     }
52 
53     /* Release data from block meta */
54     block_meta.free_size += free_size;
55 
56     /* Save scratch data block physical IDs */
57     scratch_id = its_flash_fs_mblock_cur_data_scratch_id(fs_ctx, lblock);
58 
59     /* Check if there are bytes to be compacted */
60     if (size > 0) {
61         /* Move data from source offset in current data block to scratch block
62          * destination offset.
63          */
64         err = its_flash_fs_block_to_block_move(fs_ctx, scratch_id, dst_offset,
65                                                block_meta.phy_id, src_offset,
66                                                size);
67         if (err != PSA_SUCCESS) {
68             return PSA_ERROR_GENERIC_ERROR;
69         }
70         flush_data = 1;
71     }
72 
73     if (dst_offset > block_meta.data_start) {
74         /* Copy data from the beginning of data block until
75          * the position where the data will be reallocated later
76          */
77         err = its_flash_fs_block_to_block_move(fs_ctx, scratch_id,
78                                                block_meta.data_start,
79                                                block_meta.phy_id,
80                                                block_meta.data_start,
81                                               dst_offset-block_meta.data_start);
82         if (err != PSA_SUCCESS) {
83             return PSA_ERROR_GENERIC_ERROR;
84         }
85         flush_data = 1;
86     }
87 
88     /* Swap the scratch and current data blocks. Must swap even with nothing
89      * to compact so that deleted file is left in scratch and erased as part
90      * of finalization.
91      */
92     its_flash_fs_mblock_set_data_scratch(fs_ctx, block_meta.phy_id, lblock);
93 
94     /* Set scratch block ID as the one which contains the new data block */
95     block_meta.phy_id = scratch_id;
96 
97     /* Update block metadata in scratch metadata block */
98     err = its_flash_fs_mblock_update_scratch_block_meta(fs_ctx, lblock,
99                                                         &block_meta);
100     if (err != PSA_SUCCESS) {
101         /* Swap back the data block as there was an issue in the process */
102         its_flash_fs_mblock_set_data_scratch(fs_ctx, scratch_id, lblock);
103         return err;
104     }
105 
106     /* Commit data block modifications to flash, unless the data is in logical
107      * data block 0, in which case it will be flushed at the end of the metadata
108      * block update.
109      */
110     if ((lblock != ITS_LOGICAL_DBLOCK0) && (flush_data != 0)) {
111         err = fs_ctx->ops->flush(fs_ctx->cfg, scratch_id);
112     }
113 
114     return err;
115 }
116 
its_flash_fs_dblock_read_file(struct its_flash_fs_ctx_t * fs_ctx,const struct its_file_meta_t * file_meta,size_t offset,size_t size,uint8_t * buf)117 psa_status_t its_flash_fs_dblock_read_file(
118                                         struct its_flash_fs_ctx_t *fs_ctx,
119                                         const struct its_file_meta_t *file_meta,
120                                         size_t offset,
121                                         size_t size,
122                                         uint8_t *buf)
123 {
124     uint32_t phys_block;
125     size_t pos;
126 
127     phys_block = its_dblock_lo_to_phy(fs_ctx, file_meta->lblock);
128     if (phys_block == ITS_BLOCK_INVALID_ID) {
129         return PSA_ERROR_GENERIC_ERROR;
130     }
131 
132     pos = (file_meta->data_idx + offset);
133 
134     return fs_ctx->ops->read(fs_ctx->cfg, phys_block, buf, pos, size);
135 }
136 
its_flash_fs_dblock_write_file(struct its_flash_fs_ctx_t * fs_ctx,const struct its_block_meta_t * block_meta,const struct its_file_meta_t * file_meta,size_t offset,size_t size,const uint8_t * data)137 psa_status_t its_flash_fs_dblock_write_file(
138                                       struct its_flash_fs_ctx_t *fs_ctx,
139                                       const struct its_block_meta_t *block_meta,
140                                       const struct its_file_meta_t *file_meta,
141                                       size_t offset,
142                                       size_t size,
143                                       const uint8_t *data)
144 {
145     psa_status_t err;
146     uint32_t scratch_id;
147     size_t pos;
148     size_t num_bytes;
149 
150     scratch_id = its_flash_fs_mblock_cur_data_scratch_id(fs_ctx,
151                                                          file_meta->lblock);
152 
153     /* Calculate the position of the new file data in the block */
154     pos = file_meta->data_idx + offset;
155 
156     /* Move data up to the new file data position */
157     err = its_flash_fs_block_to_block_move(fs_ctx, scratch_id,
158                                            block_meta->data_start,
159                                            block_meta->phy_id,
160                                            block_meta->data_start,
161                                            pos - block_meta->data_start);
162     if (err != PSA_SUCCESS) {
163         return err;
164     }
165 
166     /* Write the new file data */
167     err = fs_ctx->ops->write(fs_ctx->cfg, scratch_id, data, pos, size);
168     if (err != PSA_SUCCESS) {
169         return err;
170     }
171 
172     /* Calculate the position of the end of the file */
173     pos = file_meta->data_idx + file_meta->max_size;
174 
175     /* Calculate the size of the data in the block after the end of the file */
176     num_bytes = (fs_ctx->cfg->block_size - block_meta->free_size) - pos;
177 
178     /* Move data between the end of the file and the end of the block data */
179     err = its_flash_fs_block_to_block_move(fs_ctx, scratch_id, pos,
180                                            block_meta->phy_id, pos, num_bytes);
181     if (err != PSA_SUCCESS) {
182         return err;
183     }
184 
185     /* Commit data block modifications to flash, unless the data is in logical
186      * data block 0, in which case it will be flushed at the end of the metadata
187      * block update.
188      */
189     if (file_meta->lblock != ITS_LOGICAL_DBLOCK0) {
190         err = fs_ctx->ops->flush(fs_ctx->cfg, scratch_id);
191     }
192 
193     return err;
194 }
195