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