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