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