1 /*
2  * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stdint.h>
9 #include <string.h>
10 #include <stdbool.h>
11 
12 #include "cmsis_compiler.h"
13 #include "config_its.h"
14 #include "psa/storage_common.h"
15 #include "tfm_internal_trusted_storage.h"
16 #include "its_utils.h"
17 
18 #include "psa/framework_feature.h"
19 #include "psa/service.h"
20 #include "psa_manifest/tfm_internal_trusted_storage.h"
21 #include "tfm_its_defs.h"
22 #if PSA_FRAMEWORK_HAS_MM_IOVEC != 1
23 #include "flash/its_flash.h"
24 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC != 1 */
25 
26 #if PSA_FRAMEWORK_HAS_MM_IOVEC != 1
27 /* Buffer to store asset data from the caller.
28  * Note: size must be aligned to the max flash program unit to meet the
29  * alignment requirement of the filesystem.
30  */
31 static uint8_t __ALIGNED(4) asset_data[ITS_UTILS_ALIGN(ITS_BUF_SIZE,
32                                           ITS_FLASH_MAX_ALIGNMENT)];
33 #endif
34 
tfm_its_set_req(const psa_msg_t * msg)35 static psa_status_t tfm_its_set_req(const psa_msg_t *msg)
36 {
37     psa_status_t status;
38     psa_storage_uid_t uid;
39     uint8_t *data_buf;
40     size_t size_remaining;
41     size_t offset;
42     psa_storage_create_flags_t create_flags;
43     struct its_asset_info asset_info;
44     size_t num;
45 
46     if (msg->in_size[0] != sizeof(uid) ||
47         msg->in_size[2] != sizeof(create_flags)) {
48         /* The size of one of the arguments is incorrect */
49         return PSA_ERROR_PROGRAMMER_ERROR;
50     }
51 
52     num = psa_read(msg->handle, 0, &uid, sizeof(uid));
53     if (num != sizeof(uid)) {
54         return PSA_ERROR_PROGRAMMER_ERROR;
55     }
56 
57     num = psa_read(msg->handle, 2, &create_flags, sizeof(create_flags));
58     if (num != sizeof(create_flags)) {
59         return PSA_ERROR_PROGRAMMER_ERROR;
60     }
61 
62     asset_info.uid = uid;
63     asset_info.client_id = msg->client_id;
64     asset_info.create_flags = create_flags;
65 
66     size_remaining = msg->in_size[1];
67     offset = 0;
68 
69 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
70     if (size_remaining != 0) {
71         data_buf = (uint8_t *)psa_map_invec(msg->handle, 1);
72     } else {
73         /* zero-size asset is supported */
74         data_buf = NULL;
75     }
76 
77     status = tfm_its_set(&asset_info, data_buf, size_remaining,
78                          size_remaining, offset);
79 #else
80     data_buf = asset_data;
81     do {
82         num = psa_read(msg->handle, 1, asset_data,
83                        ITS_UTILS_MIN(size_remaining, sizeof(asset_data)));
84 
85         status = tfm_its_set(&asset_info, data_buf, size_remaining,
86                              num, offset);
87         if (status != PSA_SUCCESS) {
88             return status;
89         }
90 
91         size_remaining -= num;
92         offset += num;
93     } while (size_remaining);
94 #endif
95 
96     return status;
97 }
98 
tfm_its_get_req(const psa_msg_t * msg)99 static psa_status_t tfm_its_get_req(const psa_msg_t *msg)
100 {
101     psa_status_t status;
102     psa_storage_uid_t uid;
103     uint8_t *data_buf;
104     size_t size_to_read;
105     size_t data_offset;
106     size_t out_size;
107     size_t size_read;
108     size_t num;
109     struct its_asset_info asset_info;
110     bool first_get;
111 
112     if (msg->in_size[0] != sizeof(uid) ||
113         msg->in_size[1] != sizeof(data_offset)) {
114         /* The size of one of the arguments is incorrect */
115         return PSA_ERROR_PROGRAMMER_ERROR;
116     }
117 
118     num = psa_read(msg->handle, 0, &uid, sizeof(uid));
119     if (num != sizeof(uid)) {
120         return PSA_ERROR_PROGRAMMER_ERROR;
121     }
122 
123     num = psa_read(msg->handle, 1, &data_offset, sizeof(data_offset));
124     if (num != sizeof(data_offset)) {
125         return PSA_ERROR_PROGRAMMER_ERROR;
126     }
127 
128     asset_info.uid = uid;
129     asset_info.client_id = msg->client_id;
130     out_size = msg->out_size[0];
131     first_get = true;
132 
133 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
134     size_to_read = msg->out_size[0];
135     if (size_to_read != 0) {
136         data_buf = (uint8_t *)psa_map_outvec(msg->handle, 0);
137     } else {
138         data_buf = NULL;
139     }
140 
141     status = tfm_its_get(&asset_info, data_buf, size_to_read,
142                          data_offset, &size_read, first_get);
143     if (status == PSA_SUCCESS && size_to_read != 0) {
144         /* Unmap to update caller’s outvec with the number of bytes written  */
145         psa_unmap_outvec(msg->handle, 0, size_read);
146     }
147 #else
148     /* Fill in the outvec unless no data left */
149     data_buf = asset_data;
150     do {
151         size_to_read = ITS_UTILS_MIN(out_size, sizeof(asset_data));
152         status = tfm_its_get(&asset_info, data_buf, size_to_read,
153                              data_offset, &size_read, first_get);
154         if (status != PSA_SUCCESS) {
155             return status;
156         }
157         if (size_read == 0) {
158             /* No more data */
159             return PSA_SUCCESS;
160         }
161 
162         psa_write(msg->handle, 0, data_buf, size_read);
163 
164         first_get = false;
165         out_size -= size_read;
166         data_offset += size_read;
167     } while (out_size > 0);
168 #endif
169 
170     return status;
171 }
172 
tfm_its_get_info_req(const psa_msg_t * msg)173 static psa_status_t tfm_its_get_info_req(const psa_msg_t *msg)
174 {
175     psa_status_t status;
176     psa_storage_uid_t uid;
177     struct psa_storage_info_t info;
178     size_t num;
179 
180     if (msg->in_size[0] != sizeof(uid) ||
181         msg->out_size[0] != sizeof(info)) {
182         /* The size of one of the arguments is incorrect */
183         return PSA_ERROR_PROGRAMMER_ERROR;
184     }
185 
186     num = psa_read(msg->handle, 0, &uid, sizeof(uid));
187     if (num != sizeof(uid)) {
188         return PSA_ERROR_PROGRAMMER_ERROR;
189     }
190 
191     status = tfm_its_get_info(msg->client_id, uid, &info);
192     if (status == PSA_SUCCESS) {
193         psa_write(msg->handle, 0, &info, sizeof(info));
194     }
195 
196     return status;
197 }
198 
tfm_its_remove_req(const psa_msg_t * msg)199 static psa_status_t tfm_its_remove_req(const psa_msg_t *msg)
200 {
201     psa_storage_uid_t uid;
202     size_t num;
203 
204     if (msg->in_size[0] != sizeof(uid)) {
205         /* The input argument size is incorrect */
206         return PSA_ERROR_PROGRAMMER_ERROR;
207     }
208 
209     num = psa_read(msg->handle, 0, &uid, sizeof(uid));
210     if (num != sizeof(uid)) {
211         return PSA_ERROR_PROGRAMMER_ERROR;
212     }
213 
214     return tfm_its_remove(msg->client_id, uid);
215 }
216 
tfm_its_entry(void)217 psa_status_t tfm_its_entry(void)
218 {
219     return tfm_its_init();
220 }
221 
tfm_internal_trusted_storage_service_sfn(const psa_msg_t * msg)222 psa_status_t tfm_internal_trusted_storage_service_sfn(const psa_msg_t *msg)
223 {
224     switch (msg->type) {
225     case TFM_ITS_SET:
226         return tfm_its_set_req(msg);
227     case TFM_ITS_GET:
228         return tfm_its_get_req(msg);
229     case TFM_ITS_GET_INFO:
230         return tfm_its_get_info_req(msg);
231     case TFM_ITS_REMOVE:
232         return tfm_its_remove_req(msg);
233     default:
234         return PSA_ERROR_NOT_SUPPORTED;
235     }
236 
237     return PSA_ERROR_GENERIC_ERROR;
238 }
239