1 /*
2 * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include <string.h>
8 #include "config_its.h"
9 #include "tfm_internal_trusted_storage.h"
10
11 #include "tfm_hal_its.h"
12 #include "tfm_hal_ps.h"
13 #include "flash_fs/its_flash_fs.h"
14 #include "psa_manifest/pid.h"
15 #include "tfm_its_defs.h"
16 #include "its_utils.h"
17 #include "tfm_sp_log.h"
18
19 #ifdef TFM_PARTITION_PROTECTED_STORAGE
20 #include "ps_object_defs.h"
21 #endif
22
23 static uint8_t g_fid[ITS_FILE_ID_SIZE];
24 static struct its_file_info_t g_file_info;
25
26 static its_flash_fs_ctx_t fs_ctx_its;
27 static struct its_flash_fs_config_t fs_cfg_its = {
28 .flash_dev = &ITS_FLASH_DEV,
29 .program_unit = ITS_FLASH_ALIGNMENT,
30 .max_file_size = ITS_UTILS_ALIGN(ITS_MAX_ASSET_SIZE, ITS_FLASH_ALIGNMENT),
31 .max_num_files = ITS_NUM_ASSETS + 1, /* Extra file for atomic replacement */
32 };
33
34 #ifdef TFM_PARTITION_PROTECTED_STORAGE
35 static its_flash_fs_ctx_t fs_ctx_ps;
36 static struct its_flash_fs_config_t fs_cfg_ps = {
37 .flash_dev = &PS_FLASH_DEV,
38 .program_unit = PS_FLASH_ALIGNMENT,
39 .max_file_size = ITS_UTILS_ALIGN(PS_MAX_OBJECT_SIZE, PS_FLASH_ALIGNMENT),
40 .max_num_files = PS_MAX_NUM_OBJECTS,
41 };
42 #endif
43
get_fs_ctx(int32_t client_id)44 static its_flash_fs_ctx_t *get_fs_ctx(int32_t client_id)
45 {
46 #ifdef TFM_PARTITION_PROTECTED_STORAGE
47 return (client_id == TFM_SP_PS) ? &fs_ctx_ps : &fs_ctx_its;
48 #else
49 (void)client_id;
50 return &fs_ctx_its;
51 #endif
52 }
53
54 /**
55 * \brief Maps a pair of client id and uid to a file id.
56 *
57 * \param[in] client_id Identifier of the asset's owner (client)
58 * \param[in] uid Identifier for the data
59 * \param[out] fid Identifier of the file
60 */
tfm_its_get_fid(int32_t client_id,psa_storage_uid_t uid,uint8_t * fid)61 static void tfm_its_get_fid(int32_t client_id,
62 psa_storage_uid_t uid,
63 uint8_t *fid)
64 {
65 memcpy(fid, (const void *)&client_id, sizeof(client_id));
66 memcpy(fid + sizeof(client_id), (const void *)&uid, sizeof(uid));
67 }
68
69 /**
70 * \brief Initialise the static filesystem configurations.
71 *
72 * \return Returns PSA_ERROR_PROGRAMMER_ERROR if there is a configuration error,
73 * and PSA_SUCCESS otherwise.
74 */
init_fs_cfg(void)75 static psa_status_t init_fs_cfg(void)
76 {
77 struct tfm_hal_its_fs_info_t its_fs_info;
78
79 /* Check the compile-time program unit matches the runtime value */
80 if (TFM_HAL_ITS_FLASH_DRIVER.GetInfo()->program_unit
81 != TFM_HAL_ITS_PROGRAM_UNIT) {
82 return PSA_ERROR_PROGRAMMER_ERROR;
83 }
84
85 /* Retrieve flash properties from the ITS flash driver */
86 fs_cfg_its.sector_size = TFM_HAL_ITS_FLASH_DRIVER.GetInfo()->sector_size;
87 fs_cfg_its.erase_val = TFM_HAL_ITS_FLASH_DRIVER.GetInfo()->erased_value;
88
89 /* Retrieve FS parameters from the ITS HAL */
90 if (tfm_hal_its_fs_info(&its_fs_info) != TFM_HAL_SUCCESS) {
91 return PSA_ERROR_PROGRAMMER_ERROR;
92 }
93
94 /* Derive address, block_size and num_blocks from the HAL parameters */
95 fs_cfg_its.flash_area_addr = its_fs_info.flash_area_addr;
96 fs_cfg_its.block_size = fs_cfg_its.sector_size
97 * its_fs_info.sectors_per_block;
98 fs_cfg_its.num_blocks = its_fs_info.flash_area_size / fs_cfg_its.block_size;
99
100 #ifdef TFM_PARTITION_PROTECTED_STORAGE
101 struct tfm_hal_ps_fs_info_t ps_fs_info;
102
103 /* Check the compile-time program unit matches the runtime value */
104 if (TFM_HAL_PS_FLASH_DRIVER.GetInfo()->program_unit
105 != TFM_HAL_PS_PROGRAM_UNIT) {
106 return PSA_ERROR_PROGRAMMER_ERROR;
107 }
108
109 /* Retrieve flash properties from the PS flash driver */
110 fs_cfg_ps.sector_size = TFM_HAL_PS_FLASH_DRIVER.GetInfo()->sector_size;
111 fs_cfg_ps.erase_val = TFM_HAL_PS_FLASH_DRIVER.GetInfo()->erased_value;
112
113 /* Retrieve FS parameters from the PS HAL */
114 if (tfm_hal_ps_fs_info(&ps_fs_info) != TFM_HAL_SUCCESS) {
115 return PSA_ERROR_PROGRAMMER_ERROR;
116 }
117
118 /* Derive address, block_size and num_blocks from the HAL parameters */
119 fs_cfg_ps.flash_area_addr = ps_fs_info.flash_area_addr;
120 fs_cfg_ps.block_size = fs_cfg_ps.sector_size * ps_fs_info.sectors_per_block;
121 fs_cfg_ps.num_blocks = ps_fs_info.flash_area_size / fs_cfg_ps.block_size;
122 #endif
123
124 return PSA_SUCCESS;
125 }
126
tfm_its_init(void)127 psa_status_t tfm_its_init(void)
128 {
129 psa_status_t status;
130
131 status = init_fs_cfg();
132 if (status != PSA_SUCCESS) {
133 return status;
134 }
135
136 /* Initialise the ITS filesystem context */
137 status = its_flash_fs_init_ctx(&fs_ctx_its, &fs_cfg_its, &ITS_FLASH_OPS);
138 if (status != PSA_SUCCESS) {
139 return status;
140 }
141
142 /* Prepare the ITS filesystem */
143 status = its_flash_fs_prepare(&fs_ctx_its);
144 #if ITS_CREATE_FLASH_LAYOUT
145 /* If ITS_CREATE_FLASH_LAYOUT is set to 1, it indicates that it is required to
146 * create a ITS flash layout. ITS service will generate an empty and valid
147 * ITS flash layout to store assets. It will erase all data located in the
148 * assigned ITS memory area before generating the ITS layout.
149 * This flag is required to be set if the ITS memory area is located in
150 * non-persistent memory.
151 * This flag can be set if the ITS memory area is located in persistent
152 * memory without a previous valid ITS flash layout in it. That is the case
153 * when it is the first time in the device life that the ITS service is
154 * executed.
155 */
156 if (status != PSA_SUCCESS) {
157 /* Remove all data in the ITS memory area and create a valid ITS flash
158 * layout in that area.
159 */
160 LOG_INFFMT("Creating an empty ITS flash layout.\r\n");
161 status = its_flash_fs_wipe_all(&fs_ctx_its);
162 if (status != PSA_SUCCESS) {
163 return status;
164 }
165
166 /* Attempt to prepare again */
167 status = its_flash_fs_prepare(&fs_ctx_its);
168 }
169 #endif /* ITS_CREATE_FLASH_LAYOUT */
170
171 #ifdef TFM_PARTITION_PROTECTED_STORAGE
172 /* Check status of ITS initialisation before continuing with PS */
173 if (status != PSA_SUCCESS) {
174 return status;
175 }
176
177 /* Initialise the PS filesystem context */
178 status = its_flash_fs_init_ctx(&fs_ctx_ps, &fs_cfg_ps, &PS_FLASH_OPS);
179 if (status != PSA_SUCCESS) {
180 return status;
181 }
182
183 /* Prepare the PS filesystem */
184 status = its_flash_fs_prepare(&fs_ctx_ps);
185 #if PS_CREATE_FLASH_LAYOUT
186 /* If PS_CREATE_FLASH_LAYOUT is set to 1, it indicates that it is required to
187 * create a PS flash layout. PS service will generate an empty and valid
188 * PS flash layout to store assets. It will erase all data located in the
189 * assigned PS memory area before generating the PS layout.
190 * This flag is required to be set if the PS memory area is located in
191 * non-persistent memory.
192 * This flag can be set if the PS memory area is located in persistent
193 * memory without a previous valid PS flash layout in it. That is the case
194 * when it is the first time in the device life that the PS service is
195 * executed.
196 */
197 if (status != PSA_SUCCESS) {
198 /* Remove all data in the PS memory area and create a valid PS flash
199 * layout in that area.
200 */
201 LOG_INFFMT("Creating an empty PS flash layout.\r\n");
202 status = its_flash_fs_wipe_all(&fs_ctx_ps);
203 if (status != PSA_SUCCESS) {
204 return status;
205 }
206
207 /* Attempt to prepare again */
208 status = its_flash_fs_prepare(&fs_ctx_ps);
209 }
210 #endif /* PS_CREATE_FLASH_LAYOUT */
211 #endif /* TFM_PARTITION_PROTECTED_STORAGE */
212
213 return status;
214 }
215
tfm_its_set(struct its_asset_info * asset_info,uint8_t * data_buf,size_t max_size,size_t size_to_write,size_t offset)216 psa_status_t tfm_its_set(struct its_asset_info *asset_info,
217 uint8_t *data_buf,
218 size_t max_size,
219 size_t size_to_write,
220 size_t offset)
221 {
222 psa_status_t status;
223 psa_storage_uid_t uid;
224 psa_storage_create_flags_t create_flags;
225 int32_t client_id;
226
227 uid = asset_info->uid;
228 create_flags = asset_info->create_flags;
229 client_id = asset_info->client_id;
230
231 /* Check that the create_flags does not contain any unsupported flags */
232 if (create_flags & ~(PSA_STORAGE_FLAG_WRITE_ONCE |
233 PSA_STORAGE_FLAG_NO_CONFIDENTIALITY |
234 PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION)) {
235 return PSA_ERROR_NOT_SUPPORTED;
236 }
237
238 if (offset == 0) {
239 /* First time creating an asset */
240
241 /* Check that the UID is valid */
242 if (uid == TFM_ITS_INVALID_UID) {
243 return PSA_ERROR_INVALID_ARGUMENT;
244 }
245
246 /* Set file id */
247 tfm_its_get_fid(client_id, uid, g_fid);
248
249 /* Read file info */
250 status = its_flash_fs_file_get_info(get_fs_ctx(client_id), g_fid,
251 &g_file_info);
252 if (status == PSA_SUCCESS) {
253 /*
254 * If the object exists and has the write once flag set, then it
255 * cannot be modified.
256 */
257 if (g_file_info.flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
258 return PSA_ERROR_NOT_PERMITTED;
259 }
260 } else if (status != PSA_ERROR_DOES_NOT_EXIST) {
261 /*
262 * If the file does not exist, then do nothing.
263 * If other error occurred, return it
264 */
265 return status;
266 }
267
268 create_flags |= ITS_FLASH_FS_FLAG_CREATE | ITS_FLASH_FS_FLAG_TRUNCATE;
269 }
270
271 /* Write to the file in the file system */
272 status = its_flash_fs_file_write(get_fs_ctx(client_id),
273 g_fid,
274 create_flags, max_size,
275 size_to_write, offset, data_buf);
276 if (status != PSA_SUCCESS) {
277 return status;
278 }
279
280 return PSA_SUCCESS;
281 }
282
tfm_its_get(struct its_asset_info * asset_info,uint8_t * data_buf,size_t size_to_read,size_t offset,size_t * size_read,bool first_get)283 psa_status_t tfm_its_get(struct its_asset_info *asset_info,
284 uint8_t *data_buf,
285 size_t size_to_read,
286 size_t offset,
287 size_t *size_read,
288 bool first_get)
289 {
290 psa_status_t status;
291 int32_t client_id;
292 psa_storage_uid_t uid;
293
294 client_id = asset_info->client_id;
295 uid = asset_info->uid;
296
297 #ifdef TFM_PARTITION_TEST_PS
298 /*
299 * The PS test partition can call tfm_its_get() through PS code. Treat it
300 * as if it were PS.
301 */
302 if (client_id == TFM_SP_PS_TEST) {
303 client_id = TFM_SP_PS;
304 }
305 #endif
306
307 if (first_get) {
308 /* Check that the UID is valid */
309 if (uid == TFM_ITS_INVALID_UID) {
310 return PSA_ERROR_INVALID_ARGUMENT;
311 }
312
313 /* Set file id */
314 tfm_its_get_fid(client_id, uid, g_fid);
315
316 /* Read file info */
317 status = its_flash_fs_file_get_info(get_fs_ctx(client_id), g_fid,
318 &g_file_info);
319 if (status != PSA_SUCCESS) {
320 return status;
321 }
322 }
323
324 /* Boundary check the incoming request */
325 if (offset > g_file_info.size_current) {
326 return PSA_ERROR_INVALID_ARGUMENT;
327 }
328
329 /* Copy the object data only from within the file boundary */
330 size_to_read = ITS_UTILS_MIN(size_to_read,
331 g_file_info.size_current - offset);
332
333 /* Read file data from the filesystem */
334 status = its_flash_fs_file_read(get_fs_ctx(client_id),
335 g_fid, size_to_read,
336 offset, data_buf);
337 if (status != PSA_SUCCESS) {
338 return status;
339 }
340
341 /* Update the size of the output data */
342 *size_read = size_to_read;
343
344 return PSA_SUCCESS;
345 }
346
tfm_its_get_info(int32_t client_id,psa_storage_uid_t uid,struct psa_storage_info_t * p_info)347 psa_status_t tfm_its_get_info(int32_t client_id, psa_storage_uid_t uid,
348 struct psa_storage_info_t *p_info)
349 {
350 psa_status_t status;
351
352 /* Check that the UID is valid */
353 if (uid == TFM_ITS_INVALID_UID) {
354 return PSA_ERROR_INVALID_ARGUMENT;
355 }
356
357 /* Set file id */
358 tfm_its_get_fid(client_id, uid, g_fid);
359
360 /* Read file info */
361 status = its_flash_fs_file_get_info(get_fs_ctx(client_id), g_fid,
362 &g_file_info);
363 if (status != PSA_SUCCESS) {
364 return status;
365 }
366
367 /* Copy file info to the PSA info struct */
368 p_info->capacity = g_file_info.size_current;
369 p_info->size = g_file_info.size_current;
370 p_info->flags = g_file_info.flags;
371
372 return PSA_SUCCESS;
373 }
374
tfm_its_remove(int32_t client_id,psa_storage_uid_t uid)375 psa_status_t tfm_its_remove(int32_t client_id, psa_storage_uid_t uid)
376 {
377 psa_status_t status;
378
379 #ifdef TFM_PARTITION_TEST_PS
380 /* The PS test partition can call tfm_its_remove() through PS code. Treat
381 * it as if it were PS.
382 */
383 if (client_id == TFM_SP_PS_TEST) {
384 client_id = TFM_SP_PS;
385 }
386 #endif
387
388 /* Check that the UID is valid */
389 if (uid == TFM_ITS_INVALID_UID) {
390 return PSA_ERROR_INVALID_ARGUMENT;
391 }
392
393 /* Set file id */
394 tfm_its_get_fid(client_id, uid, g_fid);
395
396 status = its_flash_fs_file_get_info(get_fs_ctx(client_id), g_fid,
397 &g_file_info);
398 if (status != PSA_SUCCESS) {
399 return status;
400 }
401
402 /* If the object exists and has the write once flag set, then it
403 * cannot be deleted.
404 */
405 if (g_file_info.flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
406 return PSA_ERROR_NOT_PERMITTED;
407 }
408
409 /* Delete old file from the persistent area */
410 return its_flash_fs_file_delete(get_fs_ctx(client_id), g_fid);
411 }
412