1 /*
2 * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "config_tfm.h"
9 #include "platform_sp.h"
10
11 #include "tfm_platform_system.h"
12 #include "load/partition_defs.h"
13 #include "psa_manifest/pid.h"
14
15 #if !PLATFORM_NV_COUNTER_MODULE_DISABLED
16 #include "tfm_plat_nv_counters.h"
17 #endif /* !PLATFORM_NV_COUNTER_MODULE_DISABLED */
18
19 #include "psa/client.h"
20 #include "psa/service.h"
21 #include "region_defs.h"
22 #include "psa_manifest/tfm_platform.h"
23
24 #if !PLATFORM_NV_COUNTER_MODULE_DISABLED
25 #define NV_COUNTER_ID_SIZE sizeof(enum tfm_nv_counter_t)
26 #define NV_COUNTER_SIZE 4
27 #endif /* !PLATFORM_NV_COUNTER_MODULE_DISABLED */
28
29 typedef enum tfm_platform_err_t (*plat_func_t)(const psa_msg_t *msg);
30
31 enum tfm_platform_err_t platform_sp_system_reset(void)
32 {
33 /* FIXME: The system reset functionality is only supported in isolation
34 * level 1.
35 */
36
37 tfm_platform_hal_system_reset();
38
39 return TFM_PLATFORM_ERR_SUCCESS;
40 }
41
42 static psa_status_t platform_sp_system_reset_psa_api(const psa_msg_t *msg)
43 {
44 (void)msg; /* unused parameter */
45
46 return platform_sp_system_reset();
47 }
48
49 #if !PLATFORM_NV_COUNTER_MODULE_DISABLED
nv_counter_permissions_check(int32_t client_id,enum tfm_nv_counter_t nv_counter_no,bool is_read)50 static enum tfm_platform_err_t nv_counter_permissions_check(
51 int32_t client_id,
52 enum tfm_nv_counter_t nv_counter_no,
53 bool is_read)
54 {
55 /* Not used currently */
56 (void)is_read;
57
58 switch (nv_counter_no) {
59 #ifdef TFM_PARTITION_PROTECTED_STORAGE
60 case PLAT_NV_COUNTER_PS_0:
61 case PLAT_NV_COUNTER_PS_1:
62 case PLAT_NV_COUNTER_PS_2:
63 if (client_id == TFM_SP_PS) {
64 return TFM_PLATFORM_ERR_SUCCESS;
65 } else {
66 return TFM_PLATFORM_ERR_NOT_SUPPORTED;
67 }
68 #endif
69 case PLAT_NV_COUNTER_NS_0:
70 case PLAT_NV_COUNTER_NS_1:
71 case PLAT_NV_COUNTER_NS_2:
72 /* TODO how does this interact with the ns_ctx extension? */
73 if (client_id < 0) {
74 return TFM_PLATFORM_ERR_SUCCESS;
75 } else {
76 return TFM_PLATFORM_ERR_NOT_SUPPORTED;
77 }
78 default:
79 return TFM_PLATFORM_ERR_NOT_SUPPORTED;
80 }
81 }
82
platform_sp_nv_read_psa_api(const psa_msg_t * msg)83 static psa_status_t platform_sp_nv_read_psa_api(const psa_msg_t *msg)
84 {
85 enum tfm_plat_err_t err = TFM_PLAT_ERR_SYSTEM_ERR;
86 size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, num = 0;
87
88 enum tfm_nv_counter_t counter_id;
89 uint8_t counter_val[NV_COUNTER_SIZE] = {0};
90
91 /* Check the number of in_vec filled */
92 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
93 in_len--;
94 }
95
96 /* Check the number of out_vec filled */
97 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
98 out_len--;
99 }
100
101 if (msg->in_size[0] != NV_COUNTER_ID_SIZE ||
102 msg->out_size[0] > NV_COUNTER_SIZE ||
103 in_len != 1 || out_len != 1) {
104 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
105 }
106
107 num = psa_read(msg->handle, 0, &counter_id, msg->in_size[0]);
108 if (num != NV_COUNTER_ID_SIZE) {
109 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
110 }
111
112 if (msg->client_id < 0) {
113 counter_id += PLAT_NV_COUNTER_NS_0;
114 }
115
116 if (nv_counter_permissions_check(msg->client_id, counter_id, true)
117 != TFM_PLATFORM_ERR_SUCCESS) {
118 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
119 }
120
121 err = tfm_plat_read_nv_counter(counter_id, msg->out_size[0],
122 counter_val);
123
124 if (err != TFM_PLAT_ERR_SUCCESS) {
125 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
126 }
127
128 psa_write(msg->handle, 0, counter_val, msg->out_size[0]);
129
130 return TFM_PLATFORM_ERR_SUCCESS;
131 }
132
platform_sp_nv_increment_psa_api(const psa_msg_t * msg)133 static psa_status_t platform_sp_nv_increment_psa_api(const psa_msg_t *msg)
134 {
135 enum tfm_plat_err_t err = TFM_PLAT_ERR_SYSTEM_ERR;
136 size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, num = 0;
137
138 enum tfm_nv_counter_t counter_id;
139
140 /* Check the number of in_vec filled */
141 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
142 in_len--;
143 }
144
145 /* Check the number of out_vec filled */
146 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
147 out_len--;
148 }
149
150 if (msg->in_size[0] != NV_COUNTER_ID_SIZE ||
151 in_len != 1 || out_len != 0) {
152 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
153 }
154
155 num = psa_read(msg->handle, 0, &counter_id, msg->in_size[0]);
156 if (num != NV_COUNTER_ID_SIZE) {
157 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
158 }
159
160 if (msg->client_id < 0) {
161 counter_id += PLAT_NV_COUNTER_NS_0;
162 }
163
164 if (nv_counter_permissions_check(msg->client_id, counter_id, false)
165 != TFM_PLATFORM_ERR_SUCCESS) {
166 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
167 }
168
169 err = tfm_plat_increment_nv_counter(counter_id);
170
171 if (err != TFM_PLAT_ERR_SUCCESS) {
172 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
173 }
174
175 return TFM_PLATFORM_ERR_SUCCESS;
176 }
177 #endif /* !PLATFORM_NV_COUNTER_MODULE_DISABLED*/
178
platform_sp_ioctl_psa_api(const psa_msg_t * msg)179 static psa_status_t platform_sp_ioctl_psa_api(const psa_msg_t *msg)
180 {
181 void *input = NULL;
182 void *output = NULL;
183 psa_invec invec = {0};
184 psa_outvec outvec = {0};
185 uint8_t input_buffer[PLATFORM_SERVICE_INPUT_BUFFER_SIZE] = {0};
186 uint8_t output_buffer[PLATFORM_SERVICE_OUTPUT_BUFFER_SIZE] = {0};
187 tfm_platform_ioctl_req_t request = 0;
188 enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SYSTEM_ERROR;
189 int num = 0;
190 uint32_t in_len = PSA_MAX_IOVEC;
191 uint32_t out_len = PSA_MAX_IOVEC;
192 size_t input_size;
193
194 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
195 in_len--;
196 }
197
198 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
199 out_len--;
200 }
201
202 if ((in_len < 1) || (in_len > 2) ||
203 (out_len > 1)) {
204 return TFM_PLATFORM_ERR_SYSTEM_ERROR;
205 }
206
207 num = psa_read(msg->handle, 0, &request, sizeof(request));
208 if (num != sizeof(request)) {
209 return (enum tfm_platform_err_t) PSA_ERROR_PROGRAMMER_ERROR;
210 }
211
212 if (in_len > 1) {
213 input_size = msg->in_size[1];
214 if (input_size > PLATFORM_SERVICE_INPUT_BUFFER_SIZE) {
215 return (enum tfm_platform_err_t) PSA_ERROR_BUFFER_TOO_SMALL;
216 }
217 num = psa_read(msg->handle, 1, &input_buffer, msg->in_size[1]);
218 if (num != input_size) {
219 return (enum tfm_platform_err_t) PSA_ERROR_PROGRAMMER_ERROR;
220 }
221 invec.base = input_buffer;
222 invec.len = input_size;
223 input = &invec;
224 }
225
226 if (out_len > 0) {
227 if (msg->out_size[0] > PLATFORM_SERVICE_OUTPUT_BUFFER_SIZE) {
228 return (enum tfm_platform_err_t) PSA_ERROR_PROGRAMMER_ERROR;
229 }
230 outvec.base = output_buffer;
231 outvec.len = msg->out_size[0];
232 output = &outvec;
233 }
234
235 ret = tfm_platform_hal_ioctl(request, input, output);
236
237 if (output != NULL) {
238 psa_write(msg->handle, 0, outvec.base, outvec.len);
239 }
240
241 return ret;
242 }
243
tfm_platform_service_sfn(const psa_msg_t * msg)244 psa_status_t tfm_platform_service_sfn(const psa_msg_t *msg)
245 {
246 switch (msg->type) {
247 #if !PLATFORM_NV_COUNTER_MODULE_DISABLED
248 case TFM_PLATFORM_API_ID_NV_READ:
249 return platform_sp_nv_read_psa_api(msg);
250 case TFM_PLATFORM_API_ID_NV_INCREMENT:
251 return platform_sp_nv_increment_psa_api(msg);
252 #endif /* PLATFORM_NV_COUNTER_MODULE_DISABLED */
253 case TFM_PLATFORM_API_ID_SYSTEM_RESET:
254 return platform_sp_system_reset_psa_api(msg);
255 case TFM_PLATFORM_API_ID_IOCTL:
256 return platform_sp_ioctl_psa_api(msg);
257 default:
258 return PSA_ERROR_NOT_SUPPORTED;
259 }
260
261 return PSA_ERROR_GENERIC_ERROR;
262 }
263
platform_sp_init(void)264 psa_status_t platform_sp_init(void)
265 {
266 #if !PLATFORM_NV_COUNTER_MODULE_DISABLED
267 /* Initialise the non-volatile counters */
268 enum tfm_plat_err_t err;
269
270 err = tfm_plat_init_nv_counter();
271 if (err != TFM_PLAT_ERR_SUCCESS) {
272 return PSA_ERROR_HARDWARE_FAILURE;
273 }
274 #endif /* PLATFORM_NV_COUNTER_MODULE_DISABLED */
275
276 return PSA_SUCCESS;
277 }
278