1 /*
2  * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
3  * Copyright (c) 2022-2023 Cypress Semiconductor Corporation (an Infineon company)
4  * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  */
9 
10 /*
11  * Definitions of Remote Procedure Call (RPC) functionalities in TF-M, which
12  * sits between upper TF-M SPM and underlying mailbox implementation.
13  */
14 
15 #ifndef __TFM_RPC_H__
16 #define __TFM_RPC_H__
17 
18 #ifdef TFM_PARTITION_NS_AGENT_MAILBOX
19 
20 #include <stdbool.h>
21 #include <stdint.h>
22 #include "cmsis_compiler.h"
23 #include "psa/client.h"
24 #include "psa/service.h"
25 #include "thread.h"
26 #include "spm.h"
27 #include "ffm/agent_api.h"
28 
29 #define TFM_RPC_SUCCESS             (0)
30 #define TFM_RPC_INVAL_PARAM         (INT32_MIN + 1)
31 #define TFM_RPC_CONFLICT_CALLBACK   (INT32_MIN + 2)
32 
33 /*
34  * The underlying mailbox communication implementation should provide
35  * the specific operations to complete the RPC functionalities.
36  *
37  * It includes the following operations:
38  * handle_req() - Handle PSA client call request from NSPE
39  * reply()      - Reply PSA client call return result to NSPE. The parameter
40  *                owner identifies the owner of the PSA client call.
41  * get_caller_data() - Get the private data of NSPE client from mailbox to
42  *                     identify the PSA client call.
43  */
44 struct tfm_rpc_ops_t {
45     void (*handle_req)(void);
46     void (*reply)(const void *owner, int32_t ret);
47     const void * (*get_caller_data)(int32_t client_id);
48 };
49 
50 /**
51  * \brief RPC handler for \ref psa_framework_version.
52  *
53  * \return version              The version of the PSA Framework implementation
54  *                              that is providing the runtime services.
55  */
56 uint32_t tfm_rpc_psa_framework_version(void);
57 
58 /**
59  * \brief RPC handler for \ref psa_version.
60  *
61  * \param[in] sid               RoT Service identity.
62  *
63  * \retval PSA_VERSION_NONE     The RoT Service is not implemented, or the
64  *                              caller is not permitted to access the service.
65  * \retval > 0                  The version of the implemented RoT Service.
66  */
67 uint32_t tfm_rpc_psa_version(uint32_t sid);
68 
69 /**
70  * \brief RPC handler for \ref psa_connect.
71  *
72  * \param[in] sid               RoT Service identity.
73  * \param[in] version           The version of the RoT Service.
74  * \param[in] ns_client_id      Agent representing NS client's identifier.
75  * \param[in] client_data       Client data, treated as opaque by SPM.
76  *
77  * \retval PSA_SUCCESS          Success.
78  * \retval PSA_CONNECTION_BUSY  The SPM cannot make the connection
79  *                              at the moment.
80  * \retval "Does not return"    The RoT Service ID and version are not
81  *                              supported, or the caller is not permitted to
82  *                              access the service.
83  */
84 psa_status_t tfm_rpc_psa_connect(uint32_t sid,
85                                  uint32_t version,
86                                  int32_t ns_client_id,
87                                  const void *client_data);
88 
89 /**
90  * \brief RPC handler for \ref psa_call.
91  *
92  * \param[in] handle                 Handle to the service being accessed.
93  * \param[in] control                A composited uint32_t value for controlling purpose,
94  *                                   containing call types, numbers of in/out vectors and
95  *                                   attributes of vectors.
96  * \param[in] params                 Combines the psa_invec and psa_outvec params
97  *                                   for the psa_call() to be made, as well as
98  *                                   NS agent's client identifier, which is ignored
99  *                                   for connection-based services.
100  * \param[in] client_data_stateless  Client data, treated as opaque by SPM.
101  *
102  * \retval PSA_SUCCESS               Success.
103  * \retval "Does not return"         The call is invalid, one or more of the
104  *                                   following are true:
105  * \arg                                An invalid handle was passed.
106  * \arg                                The connection is already handling a request.
107  * \arg                                An invalid memory reference was provided.
108  * \arg                                in_num + out_num > PSA_MAX_IOVEC.
109  * \arg                                The message is unrecognized by the RoT
110  *                                     Service or incorrectly formatted.
111  */
112 psa_status_t tfm_rpc_psa_call(psa_handle_t handle, uint32_t control,
113                               const struct client_params_t *params,
114                               const void *client_data_stateless);
115 
116 /**
117  * \brief RPC handler for \ref psa_close.
118  *
119  * \param[in] handle            A handle to an established connection, or the null handle.
120  *
121  * \retval void                 Success.
122  * \retval "Does not return"    The call is invalid, one or more of the
123  *                              following are true:
124  * \arg                           An invalid handle was provided that is not
125  *                                the null handle..
126  */
127 void tfm_rpc_psa_close(psa_handle_t handle);
128 
129 /**
130  * \brief Register underlying mailbox communication operations.
131  *
132  * \param[in] ops_ptr           Pointer to the specific operation structure.
133  *
134  * \retval TFM_RPC_SUCCESS      Mailbox operations are successfully registered.
135  * \retval Other error code     Fail to register mailbox operations.
136  */
137 int32_t tfm_rpc_register_ops(const struct tfm_rpc_ops_t *ops_ptr);
138 
139 /**
140  * \brief Unregister underlying mailbox communication operations.
141  *
142  * Currently one and only one underlying mailbox communication implementation is
143  * allowed in runtime. Thus it is unnecessary to specify the mailbox
144  * communication operation callbacks to be unregistered.
145  *
146  * \param[in] void
147  */
148 void tfm_rpc_unregister_ops(void);
149 
150 /**
151  * \brief Handling PSA client call request
152  *
153  * \param void
154  */
155 void tfm_rpc_client_call_handler(void);
156 
157 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
158 /**
159  * \brief Reply PSA client call return result
160  *
161  * \param[in] void
162  */
163 void tfm_rpc_client_call_reply(void);
164 #endif /* CONFIG_TFM_SPM_BACKEND_IPC == 1 */
165 
166 /*
167  * Check if the message was allocated for a non-secure request via RPC
168  *
169  * \param[in] handle        The connection handle context pointer
170  *                          \ref connection_t structures
171  *
172  * \retval true             The message was allocated for a NS request via RPC.
173  * \retval false            Otherwise.
174  */
is_tfm_rpc_msg(const struct connection_t * handle)175 __STATIC_INLINE bool is_tfm_rpc_msg(const struct connection_t *handle)
176 {
177     /*
178      * FIXME
179      * The ID should be smaller than 0 if the message is allocated by a
180      * non-secure caller.
181      * However, current TF-M implementation use 0 as the default non-secure
182      * caller ID. Therefore, treat the caller as non-secure when client_id == 0.
183      *
184      * This condition check should be improved after TF-M non-secure client ID
185      * management is implemented.
186      */
187     if (handle && (handle->caller_data) && (handle->msg.client_id <= 0)) {
188         return true;
189     }
190 
191     return false;
192 }
193 
194 /*
195  * \brief Set the private data of the NS caller in \ref connection_t, to
196  *        identify the caller after PSA client call is compeleted.
197  *
198  * \param[in] handle        The address of \ref connection_t structure
199  * \param[in] client_id     The client ID of the NS caller.
200  */
201 void tfm_rpc_set_caller_data(struct connection_t *handle, int32_t client_id);
202 
203 #else /* TFM_PARTITION_NS_AGENT_MAILBOX */
204 
205 /* RPC is only available in multi-core scenario */
206 #define is_tfm_rpc_msg(x)                       (false)
207 
208 #define tfm_rpc_client_call_reply(owner, ret)   do {} while (0)
209 
210 #endif /* TFM_PARTITION_NS_AGENT_MAILBOX */
211 #endif /* __TFM_RPC_H__ */
212