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