1 /*
2  * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
3  * Copyright (c) 2021-2023 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 <stdint.h>
15 #include "config_impl.h"
16 #include "config_spm.h"
17 #include "current.h"
18 #include "tfm_arch.h"
19 #include "lists.h"
20 #include "thread.h"
21 #include "psa/service.h"
22 #include "load/partition_defs.h"
23 #include "load/interrupt_defs.h"
24 
25 #define TFM_HANDLE_STATUS_IDLE          0 /* Handle created             */
26 #define TFM_HANDLE_STATUS_ACTIVE        1 /* Handle in use              */
27 #define TFM_HANDLE_STATUS_TO_FREE       2 /* Free the handle            */
28 
29 /* The mask used for timeout values */
30 #define PSA_TIMEOUT_MASK        PSA_BLOCK
31 
32 /*
33  * Set a number limit for stateless handle.
34  * Valid handle must be positive, set client handle minimum value to 1.
35  */
36 #define STATIC_HANDLE_NUM_LIMIT         32
37 #define CLIENT_HANDLE_VALUE_MIN         1
38 
39 /*
40  * Bit width can be increased to match STATIC_HANDLE_NUM_LIMIT,
41  * current allowed maximum bit width is 8 for 256 handles.
42  */
43 #define STATIC_HANDLE_IDX_BIT_WIDTH     5
44 #define STATIC_HANDLE_IDX_MASK \
45     (uint32_t)((1UL << STATIC_HANDLE_IDX_BIT_WIDTH) - 1)
46 #define GET_INDEX_FROM_STATIC_HANDLE(handle) \
47     (uint32_t)((handle) & STATIC_HANDLE_IDX_MASK)
48 
49 #define STATIC_HANDLE_VER_BIT_WIDTH     8
50 #define STATIC_HANDLE_VER_OFFSET        8
51 #define STATIC_HANDLE_VER_MASK \
52     (uint32_t)((1UL << STATIC_HANDLE_VER_BIT_WIDTH) - 1)
53 #define GET_VERSION_FROM_STATIC_HANDLE(handle) \
54     (uint32_t)(((handle) >> STATIC_HANDLE_VER_OFFSET) & STATIC_HANDLE_VER_MASK)
55 
56 /* Validate the static handle indicator bit */
57 #define STATIC_HANDLE_INDICATOR_OFFSET  30
58 #define IS_STATIC_HANDLE(handle) \
59     ((handle) & (1UL << STATIC_HANDLE_INDICATOR_OFFSET))
60 
61 #define SPM_INVALID_PARTITION_IDX       (~0U)
62 
63 /* Get partition by thread or context data */
64 #define GET_THRD_OWNER(x)        TO_CONTAINER(x, struct partition_t, thrd)
65 #define GET_CTX_OWNER(x)         TO_CONTAINER(x, struct partition_t, ctx_ctrl)
66 
67 /* Checks if the provided client ID is a non-secure client ID */
68 #define TFM_CLIENT_ID_IS_NS(client_id)        ((client_id) < 0)
69 
70 /* RoT connection handle list */
71 struct connection_t {
72     uint32_t status;                         /*
73                                               * Status of handle, three valid
74                                               * options:
75                                               * TFM_HANDLE_STATUS_ACTIVE,
76                                               * TFM_HANDLE_STATUS_IDLE and
77                                               * TFM_HANDLE_STATUS_TO_FREE
78                                               */
79     struct partition_t *p_client;            /* Caller partition               */
80     struct service_t *service;               /* RoT service pointer            */
81     psa_msg_t msg;                           /* PSA message body               */
82     const void *invec_base[PSA_MAX_IOVEC];   /* Base addresses of invec from client */
83     size_t invec_accessed[PSA_MAX_IOVEC];    /* Size of data accessed by psa_read/skip */
84     void *outvec_base[PSA_MAX_IOVEC];        /* Base addresses of outvec from client */
85     size_t outvec_written[PSA_MAX_IOVEC];    /* Size of data written by psa_write */
86     psa_outvec *caller_outvec;               /* Save caller outvec pointer for write length update*/
87 #ifdef TFM_PARTITION_NS_AGENT_MAILBOX
88     const void *caller_data;                 /*
89                                               * Pointer to the private data of the
90                                               * caller. It identifies the NSPE PSA
91                                               * client calls in multi-core topology
92                                               */
93 #endif
94 #if PSA_FRAMEWORK_HAS_MM_IOVEC
95     uint32_t iovec_status;                   /* MM-IOVEC status                */
96 #endif
97 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
98     struct connection_t *p_handles;          /* Handle(s) link                 */
99     uintptr_t reply_value;                   /* Result of this operation, if aynchronous */
100 #endif
101 };
102 
103 /* Partition runtime type */
104 struct partition_t {
105     const struct partition_load_info_t *p_ldinf;
106     void                               *p_interrupts;
107     uintptr_t                          boundary;
108     uint32_t                           signals_allowed;
109     uint32_t                           signals_waiting;
110     volatile uint32_t                  signals_asserted;
111 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
112     void                               *p_metadata;
113     struct context_ctrl_t              ctx_ctrl;
114     struct thread_t                    thrd;            /* IPC model */
115     uintptr_t                          reply_value;
116 #else
117     uint32_t                           state;           /* SFN model */
118 #endif
119     struct connection_t                *p_handles;
120     struct partition_t                 *next;
121 };
122 
123 /* RoT Service data */
124 struct service_t {
125     const struct service_load_info_t *p_ldinf;     /* Service load info      */
126     struct partition_t *partition;                 /* Owner of the service   */
127     struct service_t *next;                        /* For list operation     */
128 };
129 
130 /**
131  * \brief   Get the running partition ID.
132  *
133  * \return  Returns the partition ID
134  */
135 int32_t tfm_spm_partition_get_running_partition_id(void);
136 
137 /******************** Service handle management functions ********************/
138 void spm_init_connection_space(void);
139 
140 struct connection_t *spm_allocate_connection(void);
141 
142 psa_status_t spm_validate_connection(const struct connection_t *p_connection);
143 
144 /* Panic if invalid connection is given. */
145 void spm_free_connection(struct connection_t *p_connection);
146 
147 /******************** Partition management functions *************************/
148 
149 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
150 /*
151  * Lookup and grab the last spotted handles containing the message
152  * by the given signal. Only ONE signal bit can be accepted in 'signal',
153  * multiple bits lead to 'no matched handles found to that signal'.
154  *
155  * Returns NULL if no handles matched with the given signal.
156  * Returns an internal handle instance if spotted, the instance
157  * is moved out of partition handles. Partition available signals
158  * also get updated based on the count of handles with given signal
159  * still in the partition handles.
160  */
161 struct connection_t *spm_get_handle_by_signal(struct partition_t *p_ptn,
162                                               psa_signal_t signal);
163 #endif /* CONFIG_TFM_SPM_BACKEND_IPC */
164 
165 #if CONFIG_TFM_DOORBELL_API == 1
166 /**
167  * \brief                   Get partition by Partition ID.
168  *
169  * \param[in] partition_id  The Partition ID of the partition to get
170  *
171  * \retval NULL             Failed
172  * \retval "Not NULL"       Return the parttion context pointer
173  *                          \ref partition_t structures
174  */
175 struct partition_t *tfm_spm_get_partition_by_id(int32_t partition_id);
176 #endif /* CONFIG_TFM_DOORBELL_API == 1 */
177 
178 /**
179  * \brief                   Get the service context by service ID.
180  *
181  * \param[in] sid           RoT Service identity
182  *
183  * \retval NULL             Failed
184  * \retval "Not NULL"       Target service context pointer,
185  *                          \ref service_t structures
186  */
187 struct service_t *tfm_spm_get_service_by_sid(uint32_t sid);
188 
189 /************************ Message functions **********************************/
190 
191 /**
192  * \brief                   Convert the given user handle to SPM recognised
193  *                          connection and verify it.
194  *
195  * \param[in] p_connection  The address of connection pointer to be converted
196  *                          from the given user handle.
197  *
198  * \param[in] handle        A handle to an established connection that is
199  *                          returned by a prior psa_connect call.
200  *
201  * \retval PSA_SUCCESS      Success.
202  * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
203  *                          connection.
204  * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
205  *                          connection at the moment.
206  */
207 psa_status_t spm_get_connection(struct connection_t **p_connection,
208                                 psa_handle_t handle,
209                                 int32_t client_id);
210 
211 /**
212  * \brief                   Convert the given message handle to SPM recognised
213  *                          handle and verify it.
214  *
215  * \param[in] msg_handle    Message handle which is a reference generated
216  *                          by the SPM to a specific message.
217  *
218  * \return                  A SPM recognised handle or NULL. It is NULL when
219  *                          verification of the converted SPM handle fails.
220  *                          \ref connection_t structures
221  */
222 struct connection_t *spm_msg_handle_to_connection(psa_handle_t msg_handle);
223 
224 /**
225  * \brief                   Initialize connection and fill in with the input information.
226  *
227  * \param[in] p_connection  The 'p_connection' to initialize and fill information in.
228  * \param[in] service       Target service context pointer, which can be
229  *                          obtained by partition management functions
230  * \param[in] client_id     Partition ID of the sender of the message
231  */
232 void spm_init_connection(struct connection_t *p_connection,
233                          struct service_t *service,
234                          int32_t client_id);
235 
236 /*
237  * Update connection content with information extracted from control param,
238  * including message type and information of IO vectors if any.
239  */
240 psa_status_t spm_associate_call_params(struct connection_t *p_connection,
241                                        uint32_t            ctrl_param,
242                                        const psa_invec     *inptr,
243                                        psa_outvec          *outptr);
244 
245 /**
246  * \brief                   Check the client version according to
247  *                          version policy
248  *
249  * \param[in] service       Target service context pointer, which can be get
250  *                          by partition management functions
251  * \param[in] version       Client support version
252  *
253  * \retval PSA_SUCCESS      Success
254  * \retval SPM_ERROR_BAD_PARAMETERS Bad parameters input
255  * \retval SPM_ERROR_VERSION Check failed
256  */
257 int32_t tfm_spm_check_client_version(struct service_t *service,
258                                      uint32_t version);
259 
260 /**
261  * \brief                   Check the client access authorization
262  *
263  * \param[in] sid           Target RoT Service identity
264  * \param[in] service       Target service context pointer, which can be get
265  *                          by partition management functions
266  * \param[in] ns_caller     Whether from NS caller
267  *
268  * \retval PSA_SUCCESS      Success
269  * \retval SPM_ERROR_GENERIC Authorization check failed
270  */
271 int32_t tfm_spm_check_authorization(uint32_t sid,
272                                     struct service_t *service,
273                                     bool ns_caller);
274 
275 /**
276  * \brief                       Get the ns_caller info from runtime context.
277  *
278  * \retval                      - true: the PSA API caller is from non-secure
279  *                              - false: the PSA API caller is from secure
280  */
281 bool tfm_spm_is_ns_caller(void);
282 
283 /**
284  * \brief               Get ID of current RoT Service client.
285  *                      This API ensures the caller gets a valid ID.
286  *
287  * \param[in] ns_caller If the client is Non-Secure or not.
288  *
289  * \retval              The client ID
290  */
291 int32_t tfm_spm_get_client_id(bool ns_caller);
292 
293 /*
294  * PendSV specified function.
295  *
296  * Parameters :
297  *  p_actx        -    Architecture context storage pointer
298  *
299  * Return:
300  *  Pointers to context control (sp, splimit, dummy, lr) of the current and
301  *  the next thread.
302  *  Each takes 32 bits. The context control is used by PendSV_Handler to do
303  *  context switch.
304  */
305 uint64_t ipc_schedule(void);
306 
307 /**
308  * \brief                      SPM initialization implementation
309  *
310  * \details                    This function must be called under handler mode.
311  * \retval                     This function returns an EXC_RETURN value. Other
312  *                             faults would panic the execution and never
313  *                             returned.
314  */
315 uint32_t tfm_spm_init(void);
316 
317 /**
318  * \brief Converts a handle instance into a corresponded user handle.
319  */
320 psa_handle_t connection_to_handle(struct connection_t *p_connection);
321 
322 /**
323  * \brief Converts a user handle into a corresponded handle instance.
324  */
325 struct connection_t *handle_to_connection(psa_handle_t handle);
326 
327 /**
328  * \brief Move to handler mode by a SVC for specific purpose
329  */
330 void tfm_core_handler_mode(void);
331 
332 void update_caller_outvec_len(struct connection_t *handle);
333 
334 #endif /* __SPM_H__ */
335