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