1 /*
2  * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
3  * Copyright (c) 2024 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 /* Data types and API definitions in NSPE mailbox library */
11 
12 #ifndef __TFM_NS_MAILBOX_H__
13 #define __TFM_NS_MAILBOX_H__
14 
15 #include <stdbool.h>
16 #include <stdint.h>
17 
18 #include "tfm_mailbox.h"
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 #if !defined(TFM_MULTI_CORE_NS_OS) && (NUM_MAILBOX_QUEUE_SLOT > 1)
25 #pragma message("Note: NUM_MAILBOX_QUEUE_SLOT is set to more than 1 in NS bare metal environment")
26 #endif
27 
28 /*
29  * A single slot structure in NSPE mailbox queue for NS side only.
30  * This information is needed to handle mailbox requests/responses on NS side.
31  * It may contain information about thread that initiated request and is waiting on response.
32  */
33 struct ns_mailbox_slot_t {
34     const void *owner;                      /* Handle of owner task. */
35     int32_t    *reply;                      /* Address of reply value belonging
36                                              * to owner task.
37                                              */
38 #ifdef TFM_MULTI_CORE_NS_OS_MAILBOX_THREAD
39     uint8_t    *woken_flag;                 /* Indicate that owner task has been
40                                              * or should be woken up, after the
41                                              * reply is received.
42                                              */
43 #else
44     bool        is_woken;                   /* Indicate that owner task has been
45                                              * or should be woken up, after the
46                                              * reply is received.
47                                              */
48 #endif
49 };
50 
51 /* NSPE mailbox queue */
52 struct ns_mailbox_queue_t {
53     struct mailbox_status_t status;
54     struct mailbox_slot_t slots[NUM_MAILBOX_QUEUE_SLOT];
55 
56     /* Following data are not shared with secure */
57     struct ns_mailbox_slot_t slots_ns[NUM_MAILBOX_QUEUE_SLOT];
58 
59     mailbox_queue_status_t   empty_slots;       /* Bitmask of empty slots */
60 
61 #ifdef TFM_MULTI_CORE_TEST
62     uint32_t                 nr_tx;             /* The total number of
63                                                  * submission of NS PSA Client
64                                                  * calls from NS task via
65                                                  * mailbox.
66                                                  */
67     uint32_t                 nr_used_slots;     /* The total number of used
68                                                  * mailbox queue slots each time
69                                                  * NS thread requests a mailbox
70                                                  * queue slot.
71                                                  */
72 #endif
73 
74     bool                     is_full;           /* Queue if full */
75 };
76 
77 /**
78  * \brief NSPE mailbox initialization
79  *
80  * \param[in] queue             The base address of NSPE mailbox queue to be
81  *                              initialized.
82  *
83  * \retval MAILBOX_SUCCESS      Operation succeeded.
84  * \retval Other return code    Operation failed with an error code.
85  */
86 int32_t tfm_ns_mailbox_init(struct ns_mailbox_queue_t *queue);
87 
88 /**
89  * \brief Send PSA client call to SPE via mailbox. Wait and fetch PSA client
90  *        call result.
91  *
92  * \param[in] call_type         PSA client call type
93  * \param[in] params            Parameters used for PSA client call
94  * \param[in] client_id         Optional client ID of non-secure caller.
95  *                              It is required to identify the non-secure caller
96  *                              when NSPE OS enforces non-secure task isolation.
97  * \param[out] reply            The buffer written with PSA client call result.
98  *
99  * \retval MAILBOX_SUCCESS      The PSA client call is completed successfully.
100  * \retval Other return code    Operation failed with an error code.
101  */
102 int32_t tfm_ns_mailbox_client_call(uint32_t call_type,
103                                    const struct psa_client_params_t *params,
104                                    int32_t client_id,
105                                    int32_t *reply);
106 
107 #ifdef TFM_MULTI_CORE_NS_OS_MAILBOX_THREAD
108 /**
109  * \brief Handling PSA client calls in a dedicated NS mailbox thread.
110  *        This function constructs NS mailbox messages, transmits them to SPE
111  *        mailbox and returns the results to NS PSA client.
112  *
113  * \param[in] args              The pointer to the structure of PSA client call
114  *                              parameters.
115  */
116 void tfm_ns_mailbox_thread_runner(void *args);
117 #else /* TFM_MULTI_CORE_NS_OS_MAILBOX_THREAD */
118 #define tfm_ns_mailbox_thread_runner(args)        do {} while (0)
119 #endif /* TFM_MULTI_CORE_NS_OS_MAILBOX_THREAD */
120 
121 /**
122  * \brief Platform specific NSPE mailbox initialization.
123  *        Invoked by \ref tfm_ns_mailbox_init().
124  *
125  * \param[in] queue             The base address of NSPE mailbox queue to be
126  *                              initialized.
127  *
128  * \retval MAILBOX_SUCCESS      Operation succeeded.
129  * \retval Other return code    Operation failed with an error code.
130  */
131 int32_t tfm_ns_mailbox_hal_init(struct ns_mailbox_queue_t *queue);
132 
133 /**
134  * \brief Notify SPE to deal with the PSA client call sent via mailbox
135  *
136  * \note The implementation depends on platform specific hardware and use case.
137  *
138  * \retval MAILBOX_SUCCESS      Operation succeeded.
139  * \retval Other return code    Operation failed with an error code.
140  */
141 int32_t tfm_ns_mailbox_hal_notify_peer(void);
142 
143 /**
144  * \brief Enter critical section of NSPE mailbox.
145  *
146  * \note The implementation depends on platform specific hardware and use case.
147  */
148 void tfm_ns_mailbox_hal_enter_critical(void);
149 
150 /**
151  * \brief Exit critical section of NSPE mailbox.
152  *
153  * \note The implementation depends on platform specific hardware and use case.
154  */
155 void tfm_ns_mailbox_hal_exit_critical(void);
156 
157 /**
158  * \brief Enter critical section of NSPE mailbox in IRQ handler.
159  *
160  * \note The implementation depends on platform specific hardware and use case.
161  */
162 void tfm_ns_mailbox_hal_enter_critical_isr(void);
163 
164 /**
165  * \brief Enter critical section of NSPE mailbox in IRQ handler
166  *
167  * \note The implementation depends on platform specific hardware and use case.
168  */
169 void tfm_ns_mailbox_hal_exit_critical_isr(void);
170 
171 #ifdef TFM_MULTI_CORE_NS_OS
172 /**
173  * \brief Initialize the multi-core lock for synchronizing PSA client call(s)
174  *        The actual implementation depends on the non-secure use scenario.
175  *
176  * \return \ref MAILBOX_SUCCESS on success
177  * \return \ref MAILBOX_GENERIC_ERROR on error
178  */
179 int32_t tfm_ns_mailbox_os_lock_init(void);
180 
181 /**
182  * \brief Acquire the multi-core lock for synchronizing PSA client call(s)
183  *        The actual implementation depends on the non-secure use scenario.
184  *
185  * \return \ref MAILBOX_SUCCESS on success
186  * \return \ref MAILBOX_GENERIC_ERROR on error
187  */
188 int32_t tfm_ns_mailbox_os_lock_acquire(void);
189 
190 /**
191  * \brief Release the multi-core lock for synchronizing PSA client call(s)
192  *        The actual implementation depends on the non-secure use scenario.
193  *
194  * \return \ref MAILBOX_SUCCESS on success
195  * \return \ref MAILBOX_GENERIC_ERROR on error
196  */
197 int32_t tfm_ns_mailbox_os_lock_release(void);
198 
199 /**
200  * \brief Get the handle of the current non-secure task executing mailbox
201  *        functionalities
202  *
203  * \note This function should be implemented according to NS OS and
204  *       actual use scenario.
205  *       This function can be ignored or return NULL if sleep/wake-up mechanism
206  *       is not required in PSA Client API implementation.
207  *
208  * \return Return the handle of task.
209  */
210 const void *tfm_ns_mailbox_os_get_task_handle(void);
211 
212 /**
213  * \brief Performs use scenario and NS OS specific waiting mechanism to wait for
214  *        the reply to be returned from SPE.
215  *
216  * \note This function is implemented by NS OS specific waiting mechanism
217  *       according to use scenario.
218  */
219 void tfm_ns_mailbox_os_wait_reply(void);
220 
221 /*
222  * \brief Performs use scenario and NS OS specific mechanism in a mailbox IRQ
223  *        handler, to wake up a sleeping task which is waiting for its mailbox
224  *        message reply.
225  *
226  * \note The underlying NS OS specific function called inside this function
227  *       should be able to work in an IRQ handler.
228  *
229  * \note This function is implemented by NS OS specific waiting
230  *       mechanism according to use scenario.
231  *
232  * \param[in] task_handle       The handle to the task to be woken up.
233  */
234 void tfm_ns_mailbox_os_wake_task_isr(const void *task_handle);
235 
236 /**
237  * \brief Create and initialize a message queue
238  *
239  * \param[in] msg_size        The maximum message size in bytes
240  * \param[in] msg_count       The maximum number of messages in queue
241  *
242  * \return Returns handle of the message queue created, or NULL in case of error
243  */
244 void *tfm_ns_mailbox_os_mq_create(size_t msg_size, uint8_t msg_count);
245 
246 /**
247  * \brief Send a request via message queue
248  *
249  * \param[in] mq_handle       The handle of message queue
250  * \param[in] msg_ptr         The pointer to the message to be sent
251  *
252  * \note The message size must be the same as the value set in
253  *       \ref tfm_ns_mailbox_os_mq_create.
254  *
255  * \return \ref MAILBOX_SUCCESS if the message is successfully sent, or
256  *         other return code in case of error
257  */
258 int32_t tfm_ns_mailbox_os_mq_send(void *mq_handle, const void *msg_ptr);
259 
260 /**
261  * \brief Receive a request from message queue
262  *
263  * \param[in] mq_handle       The handle of message queue
264  * \param[in] msg_ptr         The pointer to buffer for message to be received
265  *
266  * \return \ref MAILBOX_SUCCESS if the message is successfully received, or
267  *         other return code in case of error
268  *
269  * \note The message size is the same as the value set in
270  *       \ref tfm_ns_mailbox_os_mq_create.
271  *
272  * \note The function should be blocked until a message is received from message
273  *       queue, unless a fatal error occurs.
274  */
275 int32_t tfm_ns_mailbox_os_mq_receive(void *mq_handle, void *msg_ptr);
276 
277 /**
278  * \brief Go through mailbox messages already replied by SPE mailbox and
279  *        wake up the owner tasks of replied mailbox messages.
280  *        This function is intended to be called inside platform specific
281  *        notification IRQ handler.
282  *
283  * \return MAILBOX_SUCCESS       The tasks of replied mailbox messages
284  *                               were found and wake-up signals were sent.
285  * \return MAILBOX_NO_PEND_EVENT No replied mailbox message is found.
286  * \return Other return code     Failed with an error code
287  */
288 int32_t tfm_ns_mailbox_wake_reply_owner_isr(void);
289 
290 /**
291  * \brief NSPE local mailbox spin lock.
292  *        Implemented by NS RTOS specific implementation.
293  */
294 void tfm_ns_mailbox_os_spin_lock(void);
295 
296 /**
297  * \brief NSPE local mailbox spin unlock.
298  *        Implemented by NS RTOS specific implementation.
299  */
300 void tfm_ns_mailbox_os_spin_unlock(void);
301 #else /* TFM_MULTI_CORE_NS_OS */
302 #define tfm_ns_mailbox_os_wait_reply()         do {} while (0)
303 
304 #define tfm_ns_mailbox_os_wake_task_isr(task)  do {} while (0)
305 
tfm_ns_mailbox_os_lock_init(void)306 static inline int32_t tfm_ns_mailbox_os_lock_init(void)
307 {
308     return MAILBOX_SUCCESS;
309 }
310 
tfm_ns_mailbox_os_lock_acquire(void)311 static inline int32_t tfm_ns_mailbox_os_lock_acquire(void)
312 {
313     return MAILBOX_SUCCESS;
314 }
315 
tfm_ns_mailbox_os_lock_release(void)316 static inline int32_t tfm_ns_mailbox_os_lock_release(void)
317 {
318     return MAILBOX_SUCCESS;
319 }
320 
tfm_ns_mailbox_os_get_task_handle(void)321 static inline const void *tfm_ns_mailbox_os_get_task_handle(void)
322 {
323     return NULL;
324 }
325 
tfm_ns_mailbox_wake_reply_owner_isr(void)326 static inline int32_t tfm_ns_mailbox_wake_reply_owner_isr(void)
327 {
328     return MAILBOX_NO_PEND_EVENT;
329 }
330 
331 /*
332  * Local spinlock is implemented as a dummy one when integrating with NS bare
333  * metal environment since interrupt is not required in NS mailbox.
334  */
335 #define tfm_ns_mailbox_os_spin_lock()   do {} while (0)
336 
337 #define tfm_ns_mailbox_os_spin_unlock() do {} while (0)
338 #endif /* TFM_MULTI_CORE_NS_OS */
339 
340 /* The following inline functions configure non-secure mailbox queue status */
clear_queue_slot_empty(struct ns_mailbox_queue_t * queue_ptr,uint8_t idx)341 static inline void clear_queue_slot_empty(struct ns_mailbox_queue_t *queue_ptr,
342                                           uint8_t idx)
343 {
344     if (idx < NUM_MAILBOX_QUEUE_SLOT) {
345         queue_ptr->empty_slots &= ~(1UL << idx);
346     }
347 }
348 
set_queue_slot_pend(struct ns_mailbox_queue_t * queue_ptr,uint8_t idx)349 static inline void set_queue_slot_pend(struct ns_mailbox_queue_t *queue_ptr,
350                                        uint8_t idx)
351 {
352     if (idx < NUM_MAILBOX_QUEUE_SLOT) {
353         queue_ptr->status.pend_slots |= (1UL << idx);
354     }
355 }
356 
clear_queue_slot_all_replied(struct ns_mailbox_queue_t * queue_ptr)357 static inline mailbox_queue_status_t clear_queue_slot_all_replied(
358                                            struct ns_mailbox_queue_t *queue_ptr)
359 {
360     mailbox_queue_status_t status = queue_ptr->status.replied_slots;
361 
362     queue_ptr->status.replied_slots = 0;
363     return status;
364 }
365 
366 #ifdef __cplusplus
367 }
368 #endif
369 
370 #endif /* __TFM_NS_MAILBOX_H__ */
371