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