1 /*
2  * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #ifndef __PSA_API_H__
9 #define __PSA_API_H__
10 
11 #include <stdint.h>
12 #include <stdbool.h>
13 #include "config_spm.h"
14 #include "psa/client.h"
15 #include "psa/service.h"
16 
17 #if PSA_FRAMEWORK_HAS_MM_IOVEC
18 
19 /*
20  * The MM-IOVEC status
21  * The max total number of invec and outvec is 8.
22  * Each invec/outvec takes 4 bit, 32 bits in total.
23  *
24  * The encoding format of the MM-IOVEC status:
25  *--------------------------------------------------------------
26  *|  Bit   |  31 - 28  |  27 - 24  | ... |  7 - 4   |  3 - 0   |
27  *--------------------------------------------------------------
28  *| Vector | outvec[3] | outvec[2] | ... | invec[1] | invec[0] |
29  *--------------------------------------------------------------
30  *
31  * Take invec[0] as an example:
32  *
33  * bit 0:  whether invec[0] has been mapped.
34  * bit 1:  whether invec[0] has been unmapped.
35  * bit 2:  whether invec[0] has been accessed using psa_read(), psa_skip() or
36  *         psa_write().
37  * bit 3:  reserved for invec[0].
38  */
39 
40 #define IOVEC_STATUS_BITS              4   /* Each vector occupies 4 bits. */
41 #define OUTVEC_IDX_BASE                4   /*
42                                             * Base index of outvec.
43                                             * There are four invecs in front of
44                                             * outvec.
45                                             */
46 #define INVEC_IDX_BASE                 0   /* Base index of invec. */
47 
48 #define IOVEC_MAPPED_BIT               (1U << 0)
49 #define IOVEC_UNMAPPED_BIT             (1U << 1)
50 #define IOVEC_ACCESSED_BIT             (1U << 2)
51 
52 #define IOVEC_IS_MAPPED(handle, iovec_idx)      \
53     ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) &  \
54                                IOVEC_MAPPED_BIT)
55 #define IOVEC_IS_UNMAPPED(handle, iovec_idx)    \
56     ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) &  \
57                                IOVEC_UNMAPPED_BIT)
58 #define IOVEC_IS_ACCESSED(handle, iovec_idx)    \
59     ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) &  \
60                                IOVEC_ACCESSED_BIT)
61 #define SET_IOVEC_MAPPED(handle, iovec_idx)     \
62     (((handle)->iovec_status) |= (IOVEC_MAPPED_BIT <<   \
63                               ((iovec_idx) * IOVEC_STATUS_BITS)))
64 #define SET_IOVEC_UNMAPPED(handle, iovec_idx)   \
65     (((handle)->iovec_status) |= (IOVEC_UNMAPPED_BIT << \
66                               ((iovec_idx) * IOVEC_STATUS_BITS)))
67 #define SET_IOVEC_ACCESSED(handle, iovec_idx)   \
68     (((handle)->iovec_status) |= (IOVEC_ACCESSED_BIT << \
69                               ((iovec_idx) * IOVEC_STATUS_BITS)))
70 
71 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */
72 
73 /**
74  * \brief This function handles the specific programmer error cases.
75  *
76  * \param[in] status            Standard error codes for the SPM.
77  *
78  * \retval void                 Status will not cause SPM panic
79  * \retval "SPM panic"          Following programmer errors are triggered by SP:
80  * \arg                           PSA_ERROR_PROGRAMMER_ERROR
81  * \arg                           PSA_ERROR_CONNECTION_REFUSED
82  * \arg                           PSA_ERROR_CONNECTION_BUSY
83  */
84 void spm_handle_programmer_errors(psa_status_t status);
85 
86 /**
87  * \brief This function get the current PSA RoT lifecycle state.
88  *
89  * \return state                The current security lifecycle state of the PSA
90  *                              RoT. The PSA state and implementation state are
91  *                              encoded as follows:
92  * \arg                           state[15:8] – PSA lifecycle state
93  * \arg                           state[7:0] – IMPLEMENTATION DEFINED state
94  */
95 uint32_t tfm_spm_get_lifecycle_state(void);
96 
97 /* PSA Client API function body, for privileged use only. */
98 
99 /**
100  * \brief handler for \ref psa_framework_version.
101  *
102  * \return version              The version of the PSA Framework implementation
103  *                              that is providing the runtime services.
104  */
105 uint32_t tfm_spm_client_psa_framework_version(void);
106 
107 /**
108  * \brief handler for \ref psa_version.
109  *
110  * \param[in] sid               RoT Service identity.
111  *
112  * \retval PSA_VERSION_NONE     The RoT Service is not implemented, or the
113  *                              caller is not permitted to access the service.
114  * \retval > 0                  The version of the implemented RoT Service.
115  */
116 uint32_t tfm_spm_client_psa_version(uint32_t sid);
117 
118 /**
119  * \brief handler for \ref psa_call.
120  *
121  * \param[in] handle            Service handle to the established connection,
122  *                              \ref psa_handle_t
123  * \param[in] ctrl_param        Parameters combined in uint32_t,
124  *                              includes request type, in_num and out_num.
125  * \param[in] inptr             Array of input psa_invec structures.
126  *                              \ref psa_invec
127  * \param[in] outptr            Array of output psa_outvec structures.
128  *                              \ref psa_outvec
129  *
130  * \retval PSA_SUCCESS          Success.
131  * \retval "Does not return"    The call is invalid, one or more of the
132  *                              following are true:
133  * \arg                           An invalid handle was passed.
134  * \arg                           The connection is already handling a request.
135  * \arg                           An invalid memory reference was provided.
136  * \arg                           in_num + out_num > PSA_MAX_IOVEC.
137  * \arg                           The message is unrecognized by the RoT
138  *                                Service or incorrectly formatted.
139  */
140 psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
141                                      uint32_t ctrl_param,
142                                      const psa_invec *inptr,
143                                      psa_outvec *outptr);
144 
145 /* Following PSA APIs are only needed by connection-based services */
146 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
147 
148 /**
149  * \brief handler for \ref psa_connect.
150  *
151  * \param[in] sid               RoT Service identity.
152  * \param[in] version           The version of the RoT Service.
153  *
154  * \retval PSA_SUCCESS          Success.
155  * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
156  *                              connection.
157  * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
158  *                              connection at the moment.
159  * \retval "Does not return"    The RoT Service ID and version are not
160  *                              supported, or the caller is not permitted to
161  *                              access the service.
162  */
163 psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version);
164 
165 /**
166  * \brief handler for \ref psa_close.
167  *
168  * \param[in] handle            Service handle to the connection to be closed,
169  *                              \ref psa_handle_t
170  *
171  * \retval PSA_SUCCESS          Success.
172  * \retval PSA_ERROR_PROGRAMMER_ERROR The call is invalid, one or more of the
173  *                              following are true:
174  * \arg                           Called with a stateless handle.
175  * \arg                           An invalid handle was provided that is not
176  *                                the null handle.
177  * \arg                           The connection is handling a request.
178  */
179 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle);
180 
181 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
182 
183 /* PSA Partition API function body, for privileged use only. */
184 
185 #if CONFIG_TFM_SPM_BACKEND_IPC == 1 \
186     || CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1
187 /**
188  * \brief Function body of \ref psa_wait.
189  *
190  * \param[in] signal_mask       A set of signals to query. Signals that are not
191  *                              in this set will be ignored.
192  * \param[in] timeout           Specify either blocking \ref PSA_BLOCK or
193  *                              polling \ref PSA_POLL operation.
194  *
195  * \retval >0                   At least one signal is asserted.
196  * \retval 0                    No signals are asserted. This is only seen when
197  *                              a polling timeout is used.
198  */
199 psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask,
200                                         uint32_t timeout);
201 #endif
202 
203 /* This API is only used in IPC backend. */
204 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
205 /**
206  * \brief Function body of \ref psa_get.
207  *
208  * \param[in] signal            The signal value for an asserted RoT Service.
209  * \param[out] msg              Pointer to \ref psa_msg_t object for receiving
210  *                              the message.
211  *
212  * \retval PSA_SUCCESS          Success, *msg will contain the delivered
213  *                              message.
214  * \retval PSA_ERROR_DOES_NOT_EXIST Message could not be delivered.
215  * \retval "PROGRAMMER ERROR"   The call is invalid because one or more of the
216  *                              following are true:
217  * \arg                           signal has more than a single bit set.
218  * \arg                           signal does not correspond to an RoT Service.
219  * \arg                           The RoT Service signal is not currently
220  *                                asserted.
221  * \arg                           The msg pointer provided is not a valid memory
222  *                                reference.
223  */
224 psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg);
225 #endif /* CONFIG_TFM_SPM_BACKEND_IPC == 1 */
226 
227 /**
228  * \brief Function body of \ref psa_read.
229  *
230  * \param[in] msg_handle        Handle for the client's message.
231  * \param[in] invec_idx         Index of the input vector to read from. Must be
232  *                              less than \ref PSA_MAX_IOVEC.
233  * \param[out] buffer           Buffer in the Secure Partition to copy the
234  *                              requested data to.
235  * \param[in] num_bytes         Maximum number of bytes to be read from the
236  *                              client input vector.
237  *
238  * \retval >0                   Number of bytes copied.
239  * \retval 0                    There was no remaining data in this input
240  *                              vector.
241  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
242  *                              following are true:
243  * \arg                           msg_handle is invalid.
244  * \arg                           msg_handle does not refer to a
245  *                                \ref PSA_IPC_CALL message.
246  * \arg                           invec_idx is equal to or greater than
247  *                                \ref PSA_MAX_IOVEC.
248  * \arg                           the memory reference for buffer is invalid or
249  *                                not writable.
250  */
251 size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
252                                   void *buffer, size_t num_bytes);
253 
254 /**
255  * \brief Function body of psa_skip.
256  *
257  * \param[in] msg_handle        Handle for the client's message.
258  * \param[in] invec_idx         Index of input vector to skip from. Must be
259  *                              less than \ref PSA_MAX_IOVEC.
260  * \param[in] num_bytes         Maximum number of bytes to skip in the client
261  *                              input vector.
262  *
263  * \retval >0                   Number of bytes skipped.
264  * \retval 0                    There was no remaining data in this input
265  *                              vector.
266  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
267  *                              following are true:
268  * \arg                           msg_handle is invalid.
269  * \arg                           msg_handle does not refer to a request
270  *                                message.
271  * \arg                           invec_idx is equal to or greater than
272  *                                \ref PSA_MAX_IOVEC.
273  */
274 size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx,
275                                   size_t num_bytes);
276 
277 /**
278  * \brief Function body of \ref psa_write.
279  *
280  * \param[in] msg_handle        Handle for the client's message.
281  * \param[out] outvec_idx       Index of output vector in message to write to.
282  *                              Must be less than \ref PSA_MAX_IOVEC.
283  * \param[in] buffer            Buffer with the data to write.
284  * \param[in] num_bytes         Number of bytes to write to the client output
285  *                              vector.
286  *
287  * \retval void                 Success
288  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
289  *                              following are true:
290  * \arg                           msg_handle is invalid.
291  * \arg                           msg_handle does not refer to a request
292  *                                message.
293  * \arg                           outvec_idx is equal to or greater than
294  *                                \ref PSA_MAX_IOVEC.
295  * \arg                           The memory reference for buffer is invalid.
296  * \arg                           The call attempts to write data past the end
297  *                                of the client output vector.
298  */
299 void tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
300                                  const void *buffer, size_t num_bytes);
301 
302 /**
303  * \brief Function body of \ref psa_reply.
304  *
305  * \param[in] msg_handle        Handle for the client's message.
306  * \param[in] status            Message result value to be reported to the
307  *                              client.
308  *
309  * \retval Positive integer     Success, the connection handle.
310  * \retval PSA_SUCCESS          Success
311  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
312  *                              following are true:
313  * \arg                         msg_handle is invalid.
314  * \arg                         An invalid status code is specified for the
315  *                              type of message.
316  */
317 int32_t tfm_spm_partition_psa_reply(psa_handle_t msg_handle,
318                                     psa_status_t status);
319 
320 #if CONFIG_TFM_DOORBELL_API == 1
321 /**
322  * \brief Function body of \ref psa_norify.
323  *
324  * \param[in] partition_id      Secure Partition ID of the target partition.
325  *
326  * \retval void                 Success.
327  * \retval "PROGRAMMER ERROR"   partition_id does not correspond to a Secure
328  *                              Partition.
329  */
330 void tfm_spm_partition_psa_notify(int32_t partition_id);
331 
332 /**
333  * \brief Function body of \ref psa_clear.
334  *
335  * \retval void                 Success.
336  * \retval "PROGRAMMER ERROR"   The Secure Partition's doorbell signal is not
337  *                              currently asserted.
338  */
339 void tfm_spm_partition_psa_clear(void);
340 #endif /* CONFIG_TFM_DOORBELL_API == 1 */
341 
342 /**
343  * \brief Function body of \ref psa_panic.
344  *
345  * \retval "Does not return"
346  */
347 void tfm_spm_partition_psa_panic(void);
348 
349 /* psa_set_rhandle is only needed by connection-based services */
350 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
351 
352 /**
353  * \brief Function body of \ref psa_set_rhandle.
354  *
355  * \param[in] msg_handle        Handle for the client's message.
356  * \param[in] rhandle           Reverse handle allocated by the RoT Service.
357  *
358  * \retval void                 Success, rhandle will be provided with all
359  *                              subsequent messages delivered on this
360  *                              connection.
361  * \retval "PROGRAMMER ERROR"   msg_handle is invalid.
362  */
363 void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
364 
365 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
366 
367 #if CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1
368 /**
369  * \brief Function body of \ref psa_irq_enable.
370  *
371  * \param[in] irq_signal The signal for the interrupt to be enabled.
372  *                       This must have a single bit set, which must be the
373  *                       signal value for an interrupt in the calling Secure
374  *                       Partition.
375  *
376  * \retval void
377  * \retval "PROGRAMMER ERROR" If one or more of the following are true:
378  * \arg                       \a irq_signal is not an interrupt signal.
379  * \arg                       \a irq_signal indicates more than one signal.
380  */
381 void tfm_spm_partition_psa_irq_enable(psa_signal_t irq_signal);
382 
383 /**
384  * \brief Function body of psa_irq_disable.
385  *
386  * \param[in] irq_signal The signal for the interrupt to be disabled.
387  *                       This must have a single bit set, which must be the
388  *                       signal value for an interrupt in the calling Secure
389  *                       Partition.
390  *
391  * \retval 0                  The interrupt was disabled prior to this call.
392  *         1                  The interrupt was enabled prior to this call.
393  * \retval "PROGRAMMER ERROR" If one or more of the following are true:
394  * \arg                       \a irq_signal is not an interrupt signal.
395  * \arg                       \a irq_signal indicates more than one signal.
396  *
397  * \note The current implementation always return 1. Do not use the return.
398  */
399 psa_irq_status_t tfm_spm_partition_psa_irq_disable(psa_signal_t irq_signal);
400 
401 /* This API is only used for FLIH. */
402 #if CONFIG_TFM_FLIH_API == 1
403 /**
404  * \brief Function body of \ref psa_reset_signal.
405  *
406  * \param[in] irq_signal    The interrupt signal to be reset.
407  *                          This must have a single bit set, corresponding to a
408  *                          currently asserted signal for an interrupt that is
409  *                          defined to use FLIH handling.
410  *
411  * \retval void
412  * \retval "Programmer Error" if one or more of the following are true:
413  * \arg                       \a irq_signal is not a signal for an interrupt
414  *                            that is specified with FLIH handling in the Secure
415  *                            Partition manifest.
416  * \arg                       \a irq_signal indicates more than one signal.
417  * \arg                       \a irq_signal is not currently asserted.
418  */
419 void tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal);
420 #endif
421 
422 /* This API is only used for SLIH. */
423 #if CONFIG_TFM_SLIH_API == 1
424 /**
425  * \brief Function body of \ref psa_eoi.
426  *
427  * \param[in] irq_signal        The interrupt signal that has been processed.
428  *
429  * \retval void                 Success.
430  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
431  *                              following are true:
432  * \arg                           irq_signal is not an interrupt signal.
433  * \arg                           irq_signal indicates more than one signal.
434  * \arg                           irq_signal is not currently asserted.
435  * \arg                           The interrupt is not using SLIH.
436  */
437 void tfm_spm_partition_psa_eoi(psa_signal_t irq_signal);
438 #endif
439 #endif /* CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 */
440 
441 #if PSA_FRAMEWORK_HAS_MM_IOVEC
442 
443 /**
444  * \brief Function body of psa_map_invec.
445  */
446 const void *tfm_spm_partition_psa_map_invec(psa_handle_t msg_handle,
447                                             uint32_t invec_idx);
448 
449 /**
450  * \brief Function body of psa_unmap_invec.
451  */
452 void tfm_spm_partition_psa_unmap_invec(psa_handle_t msg_handle,
453                                        uint32_t invec_idx);
454 
455 /**
456  * \brief Function body of psa_map_outvet.
457  */
458 void *tfm_spm_partition_psa_map_outvec(psa_handle_t msg_handle,
459                                        uint32_t outvec_idx);
460 
461 /**
462  * \brief Function body of psa_unmap_outvec.
463  */
464 void tfm_spm_partition_psa_unmap_outvec(psa_handle_t msg_handle,
465                                         uint32_t outvec_idx, size_t len);
466 
467 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */
468 
469 #endif /* __PSA_API_H__ */
470