1 /*
2  * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
3  * Copyright (c) 2021-2024 Cypress Semiconductor Corporation (an Infineon
4  * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5  * reserved.
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  */
10 
11 #ifndef __SPM_H__
12 #define __SPM_H__
13 
14 #include <stdbool.h>
15 #include <stdint.h>
16 #include "config_impl.h"
17 #include "config_spm.h"
18 #include "current.h"
19 #include "tfm_arch.h"
20 #include "lists.h"
21 #include "runtime_defs.h"
22 #include "thread.h"
23 #include "psa/service.h"
24 #include "load/partition_defs.h"
25 #include "load/interrupt_defs.h"
26 
27 enum connection_status {
28     TFM_HANDLE_STATUS_IDLE = 0,     /* Handle created, idle */
29     TFM_HANDLE_STATUS_ACTIVE = 1,   /* Handle in use */
30     TFM_HANDLE_STATUS_TO_FREE = 2,  /* Handle to be freed */
31     TFM_HANDLE_STATUS_MAX = 3,
32 
33     _TFM_HANDLE_STATUS_PAD = UINT32_MAX,
34 };
35 
36 /* The mask used for timeout values */
37 #define PSA_TIMEOUT_MASK        PSA_BLOCK
38 
39 /*
40  * Set a number limit for stateless handle.
41  * Valid handle must be positive, set client handle minimum value to 1.
42  */
43 #define STATIC_HANDLE_NUM_LIMIT         32
44 #define CLIENT_HANDLE_VALUE_MIN         1
45 
46 /*
47  * Bit width can be increased to match STATIC_HANDLE_NUM_LIMIT,
48  * current allowed maximum bit width is 8 for 256 handles.
49  */
50 #define STATIC_HANDLE_IDX_BIT_WIDTH     5
51 #define STATIC_HANDLE_IDX_MASK \
52     (uint32_t)((1UL << STATIC_HANDLE_IDX_BIT_WIDTH) - 1)
53 #define GET_INDEX_FROM_STATIC_HANDLE(handle) \
54     (uint32_t)((handle) & STATIC_HANDLE_IDX_MASK)
55 
56 #define STATIC_HANDLE_VER_BIT_WIDTH     8
57 #define STATIC_HANDLE_VER_OFFSET        8
58 #define STATIC_HANDLE_VER_MASK \
59     (uint32_t)((1UL << STATIC_HANDLE_VER_BIT_WIDTH) - 1)
60 #define GET_VERSION_FROM_STATIC_HANDLE(handle) \
61     (uint32_t)(((handle) >> STATIC_HANDLE_VER_OFFSET) & STATIC_HANDLE_VER_MASK)
62 
63 /* Validate the static handle indicator bit */
64 #define STATIC_HANDLE_INDICATOR_OFFSET  30
65 #define IS_STATIC_HANDLE(handle) \
66     ((handle) & (1UL << STATIC_HANDLE_INDICATOR_OFFSET))
67 
68 #define SPM_INVALID_PARTITION_IDX       (~0U)
69 
70 /* Get partition by thread or context data */
71 #define GET_THRD_OWNER(x)        TO_CONTAINER(x, struct partition_t, thrd)
72 #define GET_CTX_OWNER(x)         TO_CONTAINER(x, struct partition_t, ctx_ctrl)
73 
74 /* Checks if the provided client ID is a non-secure client ID */
75 #define TFM_CLIENT_ID_IS_NS(client_id)        ((client_id) < 0)
76 
77 /* RoT connection handle list */
78 struct connection_t {
79     enum connection_status status;
80     struct partition_t *p_client;            /* Caller partition               */
81     const struct service_t *service;         /* RoT service pointer            */
82     psa_msg_t msg;                           /* PSA message body               */
83     const void *invec_base[PSA_MAX_IOVEC];   /* Base addresses of invec from client */
84     size_t invec_accessed[PSA_MAX_IOVEC];    /* Size of data accessed by psa_read/skip */
85     void *outvec_base[PSA_MAX_IOVEC];        /* Base addresses of outvec from client */
86     size_t outvec_written[PSA_MAX_IOVEC];    /* Size of data written by psa_write */
87     psa_outvec *caller_outvec;               /* Save caller outvec pointer for write length update*/
88 #ifdef TFM_PARTITION_NS_AGENT_MAILBOX
89     const void *client_data;                 /*
90                                               * Pointer to the private data of the
91                                               * client. It saves the mailbox private
92                                               * data in multi-core topology.
93                                               */
94 #endif
95 #if PSA_FRAMEWORK_HAS_MM_IOVEC
96     uint32_t iovec_status;                   /* MM-IOVEC status                */
97 #endif
98 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
99     struct connection_t *p_reqs;             /* Request handle(s) link         */
100     struct connection_t *p_replied;          /* Replied Handle(s) link         */
101     uintptr_t replied_value;                 /* Result of this operation       */
102 #endif
103 };
104 
105 /* Partition runtime type */
106 struct partition_t {
107     const struct partition_load_info_t *p_ldinf;
108     uintptr_t                          boundary;
109     uint32_t                           signals_allowed;
110     uint32_t                           signals_waiting;
111     volatile uint32_t                  signals_asserted;
112 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
113     const struct runtime_metadata_t    *p_metadata;
114     struct context_ctrl_t              ctx_ctrl;
115     struct thread_t                    thrd;       /* IPC model */
116     struct connection_t                *p_replied; /* Handle(s) to record replied connections */
117 #else
118     uint32_t                           state;      /* SFN model */
119 #endif
120     struct connection_t                *p_reqs;    /* Handle(s) to record request connections to service. */
121     struct partition_t                 *next;
122 };
123 
124 /* RoT Service data */
125 struct service_t {
126     const struct service_load_info_t *p_ldinf;     /* Service load info      */
127     struct partition_t *partition;                 /* Owner of the service   */
128     struct service_t *next;                        /* For list operation     */
129 };
130 
131 /**
132  * \brief   Get the running partition ID.
133  *
134  * \return  Returns the partition ID
135  */
136 int32_t tfm_spm_partition_get_running_partition_id(void);
137 
138 /******************** Service handle management functions ********************/
139 void spm_init_connection_space(void);
140 
141 struct connection_t *spm_allocate_connection(void);
142 
143 psa_status_t spm_validate_connection(const struct connection_t *p_connection);
144 
145 /* Panic if invalid connection is given. */
146 void spm_free_connection(struct connection_t *p_connection);
147 
148 /******************** Partition management functions *************************/
149 
150 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
151 
152 /*
153  * Get the replied handles in the asynchnorous reply mode. The first handle to
154  * be replied is at the tail of list. Take the handle one by one and clean the
155  * asynchronous signal after all handles are operated.
156  */
157 struct connection_t *spm_get_async_replied_handle(struct partition_t *partition);
158 
159 /*
160  * Lookup and grab the last spotted handles containing the message
161  * by the given signal. Only ONE signal bit can be accepted in 'signal',
162  * multiple bits lead to 'no matched handles found to that signal'.
163  *
164  * Returns NULL if no handles matched with the given signal.
165  * Returns an internal handle instance if spotted, the instance
166  * is moved out of partition handles. Partition available signals
167  * also get updated based on the count of handles with given signal
168  * still in the partition handles.
169  */
170 struct connection_t *spm_get_handle_by_signal(struct partition_t *p_ptn,
171                                               psa_signal_t signal);
172 #endif /* CONFIG_TFM_SPM_BACKEND_IPC */
173 
174 #if CONFIG_TFM_DOORBELL_API == 1
175 /**
176  * \brief                   Get partition by Partition ID.
177  *
178  * \param[in] partition_id  The Partition ID of the partition to get
179  *
180  * \retval NULL             Failed
181  * \retval "Not NULL"       Return the partition context pointer
182  *                          \ref partition_t structures
183  */
184 struct partition_t *tfm_spm_get_partition_by_id(int32_t partition_id);
185 #endif /* CONFIG_TFM_DOORBELL_API == 1 */
186 
187 /**
188  * \brief                   Get the service context by service ID.
189  *
190  * \param[in] sid           RoT Service identity
191  *
192  * \retval NULL             Failed
193  * \retval "Not NULL"       Target service context pointer,
194  *                          \ref service_t structures
195  */
196 const struct service_t *tfm_spm_get_service_by_sid(uint32_t sid);
197 
198 /************************ Message functions **********************************/
199 
200 /**
201  * \brief                   Convert the given user handle to an SPM recognised
202  *                          connection and verify that it is a valid idle
203  *                          connection that the caller is authorised to access.
204  *
205  * \param[out] p_connection The address of connection pointer to be converted
206  *                          from the given user handle.
207  *
208  * \param[in] handle        Either a static handle or a handle to an established
209  *                          connection that was returned by a prior psa_connect
210  *                          call.
211  *
212  * \param[in] client_id     The client ID of the caller.
213  *
214  * \retval PSA_SUCCESS      Success.
215  * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
216  *                          connection.
217  * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
218  *                          connection at the moment.
219  * \retval PSA_ERROR_PROGRAMMER_ERROR The handle is invalid, the caller is not
220  *                          authorised to use it or the connection is already
221  *                          handling a request.
222  */
223 psa_status_t spm_get_idle_connection(struct connection_t **p_connection,
224                                      psa_handle_t handle,
225                                      int32_t client_id);
226 
227 /**
228  * \brief                   Convert the given message handle to SPM recognised
229  *                          handle and verify it.
230  *
231  * \param[in] msg_handle    Message handle which is a reference generated
232  *                          by the SPM to a specific message.
233  *
234  * \return                  A SPM recognised handle or NULL. It is NULL when
235  *                          verification of the converted SPM handle fails.
236  *                          \ref connection_t structures
237  */
238 struct connection_t *spm_msg_handle_to_connection(psa_handle_t msg_handle);
239 
240 /**
241  * \brief                   Initialize connection, fill in with the input
242  *                          information and set to idle.
243  *
244  * \param[in] p_connection  The 'p_connection' to initialize and fill information in.
245  * \param[in] service       Target service context pointer, which can be
246  *                          obtained by partition management functions
247  * \param[in] client_id     Partition ID of the sender of the message
248  */
249 void spm_init_idle_connection(struct connection_t *p_connection,
250                               const struct service_t *service,
251                               int32_t client_id);
252 
253 /*
254  * Update connection content with information extracted from control param,
255  * including message type and information of IO vectors if any.
256  */
257 psa_status_t spm_associate_call_params(struct connection_t *p_connection,
258                                        uint32_t            ctrl_param,
259                                        const psa_invec     *inptr,
260                                        psa_outvec          *outptr);
261 
262 /**
263  * \brief                   Check the client version according to
264  *                          version policy
265  *
266  * \param[in] service       Target service context pointer, which can be get
267  *                          by partition management functions
268  * \param[in] version       Client support version
269  *
270  * \retval PSA_SUCCESS      Success
271  * \retval SPM_ERROR_BAD_PARAMETERS Bad parameters input
272  * \retval SPM_ERROR_VERSION Check failed
273  */
274 int32_t tfm_spm_check_client_version(const struct service_t *service,
275                                      uint32_t version);
276 
277 /**
278  * \brief                   Check the client access authorization
279  *
280  * \param[in] sid           Target RoT Service identity
281  * \param[in] service       Target service context pointer, which can be get
282  *                          by partition management functions
283  * \param[in] ns_caller     Whether from NS caller
284  *
285  * \retval PSA_SUCCESS      Success
286  * \retval SPM_ERROR_GENERIC Authorization check failed
287  */
288 int32_t tfm_spm_check_authorization(uint32_t sid,
289                                     const struct service_t *service,
290                                     bool ns_caller);
291 
292 /**
293  * \brief                       Get the ns_caller info from runtime context.
294  *
295  * \retval                      - true: the PSA API caller is from non-secure
296  *                              - false: the PSA API caller is from secure
297  */
298 bool tfm_spm_is_ns_caller(void);
299 
300 /**
301  * \brief               Get ID of current RoT Service client.
302  *                      This API ensures the caller gets a valid ID.
303  *
304  * \param[in] ns_caller If the client is Non-Secure or not.
305  *
306  * \retval              The client ID
307  */
308 int32_t tfm_spm_get_client_id(bool ns_caller);
309 
310 /*
311  * PendSV specified function.
312  *
313  * Parameters :
314  *  exc_return    -    EXC_RETURN value for the PendSV handler
315  *
316  * Return:
317  *  Pointers to context control (sp, splimit, dummy, lr) of the current and
318  *  the next thread.
319  *  Each takes 32 bits. The context control is used by PendSV_Handler to do
320  *  context switch.
321  */
322 uint64_t ipc_schedule(uint32_t exc_return);
323 
324 /**
325  * \brief                      SPM initialization implementation
326  *
327  * \details                    This function must be called under handler mode.
328  * \retval                     This function returns an EXC_RETURN value. Other
329  *                             faults would panic the execution and never
330  *                             returned.
331  */
332 uint32_t tfm_spm_init(void);
333 
334 /**
335  * \brief Converts a handle instance into a corresponded user handle.
336  */
337 psa_handle_t connection_to_handle(struct connection_t *p_connection);
338 
339 /**
340  * \brief Converts a user handle into a corresponded handle instance.
341  */
342 struct connection_t *handle_to_connection(psa_handle_t handle);
343 
344 
345 /* Following PSA APIs are only needed by connection-based services */
346 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
347 
348 /* Handler for \ref psa_connect.
349  *
350  * \param[in] p_connection      The address of connection pointer.
351  * \param[in] sid               RoT Service identity.
352  * \param[in] version           The version of the RoT Service.
353  * \param[in] client_id         Client id of the service caller. It should be
354  *                              validated before this API is being called.
355  *
356  * \retval PSA_SUCCESS          Success.
357  * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
358  *                              connection.
359  * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
360  *                              connection at the moment.
361  * \retval "Does not return"    The RoT Service ID and version are not
362  *                              supported, or the caller is not permitted to
363  *                              access the service.
364  */
365 psa_status_t spm_psa_connect_client_id_associated(struct connection_t **p_connection,
366                                                   uint32_t sid, uint32_t version,
367                                                   int32_t client_id);
368 
369 /* Handler for \ref psa_close.
370  *
371  * \param[in] handle            Service handle to the connection to be closed,
372  *                              \ref psa_handle_t
373  * \param[in] client_id         Client id of the connection caller.
374  *
375  * \retval PSA_SUCCESS          Success.
376  * \retval PSA_ERROR_PROGRAMMER_ERROR The call is invalid, one or more of the
377  *                              following are true:
378  * \arg                           Called with a stateless handle.
379  * \arg                           An invalid handle was provided that is not
380  *                                the null handle.
381  * \arg                           The connection is handling a request.
382  */
383 psa_status_t spm_psa_close_client_id_associated(psa_handle_t handle, int32_t client_id);
384 
385 #endif /* #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 */
386 
387 #ifdef TFM_PARTITION_NS_AGENT_MAILBOX
388 
389 /*
390  * Check if the message was allocated for a non-secure request via RPC
391  *
392  *  param[in] handle        The connection handle context pointer
393  *                          connection_t structures
394  *
395  *  retval true             The message was allocated for a NS request via RPC.
396  *  retval false            Otherwise.
397  */
tfm_spm_is_rpc_msg(const struct connection_t * handle)398 __STATIC_INLINE bool tfm_spm_is_rpc_msg(const struct connection_t *handle)
399 {
400     if (handle && (handle->client_data) && (handle->msg.client_id < 0)) {
401         return true;
402     }
403 
404     return false;
405 }
406 #else /* TFM_PARTITION_NS_AGENT_MAILBOX */
407 
408 /* RPC is only available in multi-core scenario */
409 #define tfm_spm_is_rpc_msg(x)                       (false)
410 
411 #endif /* TFM_PARTITION_NS_AGENT_MAILBOX */
412 
413 #endif /* __SPM_H__ */
414