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