1 /*
2  * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #ifndef __PSA_SERVICE_H__
9 #define __PSA_SERVICE_H__
10 
11 #include <stddef.h>
12 #include <stdint.h>
13 
14 #include "config_impl.h"
15 
16 #include "psa/client.h"
17 #include "psa/error.h"
18 #include "psa/framework_feature.h"
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /********************** PSA Secure Partition Macros and Types ****************/
25 
26 /**
27  * A timeout value that requests a polling wait operation.
28  */
29 #define PSA_POLL                (0x00000000u)
30 
31 /**
32  * A timeout value that requests a blocking wait operation.
33  */
34 #define PSA_BLOCK               (0x80000000u)
35 
36 /**
37  * A mask value that includes all Secure Partition signals.
38  */
39 #define PSA_WAIT_ANY            (0xFFFFFFFFu)
40 
41 /**
42  * The signal number for the Secure Partition doorbell.
43  */
44 #define PSA_DOORBELL            (0x00000008u)
45 
46 /* PSA message types */
47 /* An IPC message type that indicates a new connection. */
48 #define PSA_IPC_CONNECT         (-1)
49 /* An IPC message type that indicates the end of a connection. */
50 #define PSA_IPC_DISCONNECT      (-2)
51 
52 /* FLIH return types */
53 #define PSA_FLIH_NO_SIGNAL      ((psa_flih_result_t) 0)
54 #define PSA_FLIH_SIGNAL         ((psa_flih_result_t) 1)
55 
56 /* Store a set of one or more Secure Partition signals */
57 typedef uint32_t psa_signal_t;
58 
59 /* A type used to temporarily store a previous interrupt state. */
60 typedef uint32_t psa_irq_status_t;
61 
62 /* The type of the return value from an FLIH function */
63 typedef uint32_t psa_flih_result_t;
64 
65 /**
66  * Describe a message received by an RoT Service after calling \ref psa_get().
67  */
68 typedef struct psa_msg_t {
69     int32_t type;              /* One of the following values:
70                                  * \ref PSA_IPC_CONNECT
71                                  * >= 0
72                                  * \ref PSA_IPC_DISCONNECT
73                                  */
74     psa_handle_t handle;        /* A reference generated by the SPM to the
75                                  * message returned by psa_get().
76                                  */
77     int32_t client_id;          /*
78                                  * Partition ID of the sender of the
79                                  * message:
80                                  *  - secure partition id;
81                                  *  - non secure client endpoint id.
82                                  */
83 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
84     void *rhandle;              /* Be useful for binding a connection to some
85                                  * application-specific data or function
86                                  * pointer within the RoT Service
87                                  * implementation.
88                                  */
89 #endif
90     size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input
91                                     * vector in bytes.
92                                     */
93     size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output
94                                     * vector in bytes.
95                                     */
96 } psa_msg_t;
97 
98 /************************* PSA Secure Partition API **************************/
99 
100 /**
101  * \brief Return the Secure Partition interrupt signals that have been asserted
102  *        from a subset of signals provided by the caller.
103  *
104  * \param[in] signal_mask       A set of signals to query. Signals that are not
105  *                              in this set will be ignored.
106  * \param[in] timeout           Specify either blocking \ref PSA_BLOCK or
107  *                              polling \ref PSA_POLL operation.
108  *
109  * \retval >0                   At least one signal is asserted.
110  * \retval 0                    No signals are asserted. This is only seen when
111  *                              a polling timeout is used.
112  */
113 psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout);
114 
115 /**
116  * \brief Retrieve the message which corresponds to a given RoT Service signal
117  *        and remove the message from the RoT Service queue.
118  *
119  * \param[in] signal            The signal value for an asserted RoT Service.
120  * \param[out] msg              Pointer to \ref psa_msg_t object for receiving
121  *                              the message.
122  *
123  * \retval PSA_SUCCESS          Success, *msg will contain the delivered
124  *                              message.
125  * \retval PSA_ERROR_DOES_NOT_EXIST Message could not be delivered.
126  * \retval "PROGRAMMER ERROR"   The call is invalid because one or more of the
127  *                              following are true:
128  * \arg                           signal has more than a single bit set.
129  * \arg                           signal does not correspond to an RoT Service.
130  * \arg                           The RoT Service signal is not currently
131  *                                asserted.
132  * \arg                           The msg pointer provided is not a valid memory
133  *                                reference.
134  */
135 psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg);
136 
137 /**
138  * \brief Associate some RoT Service private data with a client connection.
139  *
140  * \param[in] msg_handle        Handle for the client's message.
141  * \param[in] rhandle           Reverse handle allocated by the RoT Service.
142  *
143  * \retval void                 Success, rhandle will be provided with all
144  *                              subsequent messages delivered on this
145  *                              connection.
146  * \retval "PROGRAMMER ERROR"   msg_handle is invalid.
147  */
148 void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
149 
150 /**
151  * \brief Read a message parameter or part of a message parameter from a client
152  *        input vector.
153  *
154  * \param[in] msg_handle        Handle for the client's message.
155  * \param[in] invec_idx         Index of the input vector to read from. Must be
156  *                              less than \ref PSA_MAX_IOVEC.
157  * \param[out] buffer           Buffer in the Secure Partition to copy the
158  *                              requested data to.
159  * \param[in] num_bytes         Maximum number of bytes to be read from the
160  *                              client input vector.
161  *
162  * \retval >0                   Number of bytes copied.
163  * \retval 0                    There was no remaining data in this input
164  *                              vector.
165  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
166  *                              following are true:
167  * \arg                           msg_handle is invalid.
168  * \arg                           msg_handle does not refer to a
169  *                                \ref PSA_IPC_CALL message.
170  * \arg                           invec_idx is equal to or greater than
171  *                                \ref PSA_MAX_IOVEC.
172  * \arg                           the memory reference for buffer is invalid or
173  *                                not writable.
174  */
175 size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
176                 void *buffer, size_t num_bytes);
177 
178 /**
179  * \brief Skip over part of a client input vector.
180  *
181  * \param[in] msg_handle        Handle for the client's message.
182  * \param[in] invec_idx         Index of input vector to skip from. Must be
183  *                              less than \ref PSA_MAX_IOVEC.
184  * \param[in] num_bytes         Maximum number of bytes to skip in the client
185  *                              input vector.
186  *
187  * \retval >0                   Number of bytes skipped.
188  * \retval 0                    There was no remaining data in this input
189  *                              vector.
190  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
191  *                              following are true:
192  * \arg                           msg_handle is invalid.
193  * \arg                           msg_handle does not refer to a request
194  *                                message.
195  * \arg                           invec_idx is equal to or greater than
196  *                                \ref PSA_MAX_IOVEC.
197  */
198 size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes);
199 
200 /**
201  * \brief Write a message response to a client output vector.
202  *
203  * \param[in] msg_handle        Handle for the client's message.
204  * \param[out] outvec_idx       Index of output vector in message to write to.
205  *                              Must be less than \ref PSA_MAX_IOVEC.
206  * \param[in] buffer            Buffer with the data to write.
207  * \param[in] num_bytes         Number of bytes to write to the client output
208  *                              vector.
209  *
210  * \retval void                 Success
211  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
212  *                              following are true:
213  * \arg                           msg_handle is invalid.
214  * \arg                           msg_handle does not refer to a request
215  *                                message.
216  * \arg                           outvec_idx is equal to or greater than
217  *                                \ref PSA_MAX_IOVEC.
218  * \arg                           The memory reference for buffer is invalid.
219  * \arg                           The call attempts to write data past the end
220  *                                of the client output vector.
221  */
222 void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
223                const void *buffer, size_t num_bytes);
224 
225 /**
226  * \brief Complete handling of a specific message and unblock the client.
227  *
228  * \param[in] msg_handle        Handle for the client's message.
229  * \param[in] status            Message result value to be reported to the
230  *                              client.
231  *
232  * \retval void                 Success.
233  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
234  *                              following are true:
235  * \arg                         msg_handle is invalid.
236  * \arg                         An invalid status code is specified for the
237  *                              type of message.
238  */
239 void psa_reply(psa_handle_t msg_handle, psa_status_t status);
240 
241 /**
242  * \brief Send a PSA_DOORBELL signal to a specific Secure Partition.
243  *
244  * \param[in] partition_id      Secure Partition ID of the target partition.
245  *
246  * \retval void                 Success.
247  * \retval "PROGRAMMER ERROR"   partition_id does not correspond to a Secure
248  *                              Partition.
249  */
250 void psa_notify(int32_t partition_id);
251 
252 /**
253  * \brief Clear the PSA_DOORBELL signal.
254  *
255  * \retval void                 Success.
256  * \retval "PROGRAMMER ERROR"   The Secure Partition's doorbell signal is not
257  *                              currently asserted.
258  */
259 void psa_clear(void);
260 
261 /**
262  * \brief Inform the SPM that an interrupt has been handled (end of interrupt).
263  *
264  * \param[in] irq_signal        The interrupt signal that has been processed.
265  *
266  * \retval void                 Success.
267  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
268  *                              following are true:
269  * \arg                           irq_signal is not an interrupt signal.
270  * \arg                           irq_signal indicates more than one signal.
271  * \arg                           irq_signal is not currently asserted.
272  * \arg                           The interrupt is not using SLIH.
273  */
274 void psa_eoi(psa_signal_t irq_signal);
275 
276 /**
277  * \brief Terminate execution within the calling Secure Partition and will not
278  *        return.
279  *
280  * \retval "Does not return"
281  */
282 void psa_panic(void);
283 
284 /**
285  * \brief Enable an interrupt.
286  *
287  * \param[in] irq_signal The signal for the interrupt to be enabled.
288  *                       This must have a single bit set, which must be the
289  *                       signal value for an interrupt in the calling Secure
290  *                       Partition.
291  *
292  * \retval void
293  * \retval "PROGRAMMER ERROR" If one or more of the following are true:
294  * \arg                       \a irq_signal is not an interrupt signal.
295  * \arg                       \a irq_signal indicates more than one signal.
296  */
297 void psa_irq_enable(psa_signal_t irq_signal);
298 
299 /**
300  * \brief Disable an interrupt and return the status of the interrupt prior to
301  *        being disabled by this call.
302  *
303  * \param[in] irq_signal The signal for the interrupt to be disabled.
304  *                       This must have a single bit set, which must be the
305  *                       signal value for an interrupt in the calling Secure
306  *                       Partition.
307  *
308  * \retval 0                  The interrupt was disabled prior to this call.
309  *         1                  The interrupt was enabled prior to this call.
310  * \retval "PROGRAMMER ERROR" If one or more of the following are true:
311  * \arg                       \a irq_signal is not an interrupt signal.
312  * \arg                       \a irq_signal indicates more than one signal.
313  *
314  * \note The current implementation always return 1. Do not use the return.
315  */
316 psa_irq_status_t psa_irq_disable(psa_signal_t irq_signal);
317 
318 /**
319  * \brief Reset the signal for an interrupt that is using FLIH handling.
320  *
321  * \param[in] irq_signal    The interrupt signal to be reset.
322  *                          This must have a single bit set, corresponding to a
323  *                          currently asserted signal for an interrupt that is
324  *                          defined to use FLIH handling.
325  *
326  * \retval void
327  * \retval "Programmer Error" if one or more of the following are true:
328  * \arg                       \a irq_signal is not a signal for an interrupt
329  *                            that is specified with FLIH handling in the Secure
330  *                            Partition manifest.
331  * \arg                       \a irq_signal indicates more than one signal.
332  * \arg                       \a irq_signal is not currently asserted.
333  */
334 void psa_reset_signal(psa_signal_t irq_signal);
335 
336 #if PSA_FRAMEWORK_HAS_MM_IOVEC
337 
338 /**
339  * \brief Map a client input vector for direct access by a Secure Partition RoT
340  *        Service.
341  *
342  * \param[in] msg_handle        Handle for the client's message.
343  * \param[in] invec_idx         Index of input vector to map. Must be
344  *                              less than \ref PSA_MAX_IOVEC.
345  *
346  * \retval                      A pointer to the input vector data.
347  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
348  *                              following are true:
349  * \arg                           MM-IOVEC has not been enabled for the RoT
350  *                                Service that received the message.
351  * \arg                           msg_handle is invalid.
352  * \arg                           msg_handle does not refer to a request
353  *                                message.
354  * \arg                           invec_idx is equal to or greater than
355  *                                \ref PSA_MAX_IOVEC.
356  * \arg                           The input vector has length zero.
357  * \arg                           The input vector has already been mapped using
358  *                                psa_map_invec().
359  * \arg                           The input vector has already been accessed
360  *                                using psa_read() or psa_skip().
361  */
362 const void *psa_map_invec(psa_handle_t msg_handle, uint32_t invec_idx);
363 
364 /**
365  * \brief Unmap a previously mapped client input vector from a Secure Partition
366  *        RoT Service.
367  *
368  * \param[in] msg_handle        Handle for the client's message.
369  * \param[in] invec_idx         Index of input vector to map. Must be
370  *                              less than \ref PSA_MAX_IOVEC.
371  *
372  * \retval void
373  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
374  *                              following are true:
375  * \arg                           msg_handle is invalid.
376  * \arg                           msg_handle does not refer to a request
377  *                                message.
378  * \arg                           invec_idx is equal to or greater than
379  *                                \ref PSA_MAX_IOVEC.
380  * \arg                           The input vector has not been mapped by a call
381  *                                to psa_map_invec().
382  * \arg                           The input vector has already been unmapped by
383  *                                a call to psa_unmap_invec().
384  */
385 void psa_unmap_invec(psa_handle_t msg_handle, uint32_t invec_idx);
386 
387 /**
388  * \brief Map a client output vector for direct access by a Secure Partition RoT
389  *        Service.
390  *
391  * \param[in] msg_handle        Handle for the client's message.
392  * \param[in] outvec_idx        Index of output vector to map. Must be
393  *                              less than \ref PSA_MAX_IOVEC.
394  *
395  * \retval                      A pointer to the output vector data.
396  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
397  *                              following are true:
398  * \arg                           MM-IOVEC has not been enabled for the RoT
399  *                                Service that received the message.
400  * \arg                           msg_handle is invalid.
401  * \arg                           msg_handle does not refer to a request
402  *                                message.
403  * \arg                           outvec_idx is equal to or greater than
404  *                                \ref PSA_MAX_IOVEC.
405  * \arg                           The output vector has length zero.
406  * \arg                           The output vector has already been mapped
407  *                                using psa_map_outvec().
408  * \arg                           The output vector has already been accessed
409  *                                using psa_write().
410  */
411 void *psa_map_outvec(psa_handle_t msg_handle, uint32_t outvec_idx);
412 
413 /**
414  * \brief Unmap a previously mapped client output vector from a Secure Partition
415  *        RoT Service.
416  *
417  * \param[in] msg_handle        Handle for the client's message.
418  * \param[in] outvec_idx        Index of output vector to map. Must be
419  *                              less than \ref PSA_MAX_IOVEC.
420  * \param[in] len               The number of bytes written to the output
421  *                              vector. This must be less than or equal to the
422  *                              size of the output vector.
423  *
424  * \retval void
425  * \retval "PROGRAMMER ERROR"   The call is invalid, one or more of the
426  *                              following are true:
427  * \arg                           msg_handle is invalid.
428  * \arg                           msg_handle does not refer to a request
429  *                                message.
430  * \arg                           outvec_idx is equal to or greater than
431  *                                \ref PSA_MAX_IOVEC.
432  * \arg                           The output vector has not been mapped by a
433  *                                call to psa_map_outvec().
434  * \arg                           The output vector has already been unmapped by
435  *                                a call to psa_unmap_outvec().
436  */
437 void psa_unmap_outvec(psa_handle_t msg_handle, uint32_t outvec_idx, size_t len);
438 
439 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */
440 
441 #ifdef __cplusplus
442 }
443 #endif
444 
445 #endif /* __PSA_SERVICE_H__ */
446