1 /**************************************************************************/ /**
2  * @file
3  * @brief OS abstraction layer primitives for platform/security on CMSIS RTOS2
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #ifndef SLI_PSEC_OSAL_CMSIS_RTOS_H
32 #define SLI_PSEC_OSAL_CMSIS_RTOS_H
33 
34 // -----------------------------------------------------------------------------
35 // Includes
36 #include "sl_common.h"
37 #include "sl_status.h"
38 #include "cmsis_os2.h"
39 #include "sl_core.h"
40 #include "sl_code_classification.h"
41 
42 #if defined (SL_COMPONENT_CATALOG_PRESENT)
43   #include "sl_component_catalog.h"
44 #endif
45 
46 #if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT)
47   #include "FreeRTOSConfig.h"
48   #if (configSUPPORT_STATIC_ALLOCATION == 1)
49     #include "FreeRTOS.h"  // StaticSemaphore_t
50     #include <string.h>
51   #endif
52 #endif
53 
54 #ifdef __cplusplus
55 extern "C" {
56 #endif
57 
58 // -----------------------------------------------------------------------------
59 // Defines
60 
61 /// In order to wait forever in blocking functions the user can pass the
62 /// following value.
63 #define SLI_PSEC_OSAL_WAIT_FOREVER  (osWaitForever)
64 /// In order to return immediately in blocking functions the user can pass the
65 /// following value.
66 #define SLI_PSEC_OSAL_NON_BLOCKING  (0)
67 
68 // Checks if kernel is running
69 #define SLI_PSEC_OSAL_KERNEL_RUNNING (osKernelGetState() == osKernelRunning)
70 
71 // Lock kernel (task scheduler) to enter critical section
72 #define SLI_PSEC_OSAL_KERNEL_CRITICAL_SECTION_START                        \
73   int32_t kernel_lock_state = 0;                                           \
74   osKernelState_t kernel_state = osKernelGetState();                       \
75   if (kernel_state != osKernelInactive && kernel_state != osKernelReady) { \
76     kernel_lock_state = osKernelLock();                                    \
77     if (kernel_lock_state < 0) {                                           \
78       return SL_STATUS_FAIL;                                               \
79     }                                                                      \
80   }
81 
82 // Resume kernel to exit critical section
83 #define SLI_PSEC_OSAL_KERNEL_CRITICAL_SECTION_END                          \
84   if (kernel_state != osKernelInactive && kernel_state != osKernelReady) { \
85     if (osKernelRestoreLock(kernel_lock_state) < 0) {                      \
86       return SL_STATUS_FAIL;                                               \
87     }                                                                      \
88   }
89 
90 // -----------------------------------------------------------------------------
91 // Typedefs
92 
93 /// Completion object used to wait for and signal end of an operation.
94 typedef struct sli_psec_osal_completion {
95 #if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT) && (configSUPPORT_STATIC_ALLOCATION == 1)
96   osSemaphoreAttr_t semaphore_attr;
97   StaticSemaphore_t static_sem_object;
98 #endif
99   osSemaphoreId_t   semaphore_ID;
100 } sli_psec_osal_completion_t;
101 
102 /// SLI PSEC lock definition for CMSIS RTOS2.
103 typedef struct sli_psec_osal_lock {
104 #if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT) && (configSUPPORT_STATIC_ALLOCATION == 1)
105   StaticSemaphore_t static_sem_object;
106 #endif
107   osMutexAttr_t mutex_attr;
108   osMutexId_t   mutex_ID;
109 } sli_psec_osal_lock_t;
110 
111 // -----------------------------------------------------------------------------
112 // Functions
113 
114 /***************************************************************************//**
115  * @brief          Set recursive attribute of lock
116  *
117  * @details        If recursive lock is needed, this function must be called
118  *                 before calling sli_psec_osal_init_lock.
119  *
120  * @param lock     Pointer to the lock
121  *
122  * @return         SL_STATUS_OK on success, error code otherwise.
123  *****************************************************************************/
124 __STATIC_INLINE
sli_psec_osal_set_recursive_lock(sli_psec_osal_lock_t * lock)125 sl_status_t sli_psec_osal_set_recursive_lock(sli_psec_osal_lock_t *lock)
126 {
127   if (lock == NULL) {
128     return SL_STATUS_INVALID_PARAMETER;
129   }
130   lock->mutex_attr.attr_bits |= osMutexRecursive;
131   return SL_STATUS_OK;
132 }
133 
134 /***************************************************************************//**
135  * @brief          Initialize a given lock
136  *
137  * @param lock     Pointer to the lock needing initialization
138  *
139  * @return         SL_STATUS_OK on success, error code otherwise.
140  *****************************************************************************/
sli_psec_osal_init_lock(sli_psec_osal_lock_t * lock)141 __STATIC_INLINE sl_status_t sli_psec_osal_init_lock(sli_psec_osal_lock_t *lock)
142 {
143   if (lock == NULL) {
144     return SL_STATUS_FAIL;
145   }
146 
147 #if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT) && (configSUPPORT_STATIC_ALLOCATION == 1)
148   // Zeroize all members of the lock attributes object and setup the static control block.
149   lock->mutex_attr.cb_mem = &lock->static_sem_object;
150   lock->mutex_attr.cb_size = sizeof(lock->static_sem_object);
151 #endif
152 
153   lock->mutex_ID = osMutexNew(&lock->mutex_attr);
154 
155   return (lock->mutex_ID == NULL ? SL_STATUS_FAIL : SL_STATUS_OK);
156 }
157 
158 /***************************************************************************//**
159  * @brief          Free a given lock
160  *
161  * @param lock     Pointer to the lock being freed
162  *
163  * @return         SL_STATUS_OK on success, error code otherwise.
164  *****************************************************************************/
sli_psec_osal_free_lock(sli_psec_osal_lock_t * lock)165 __STATIC_INLINE sl_status_t sli_psec_osal_free_lock(sli_psec_osal_lock_t *lock)
166 {
167   if (lock == NULL) {
168     return SL_STATUS_FAIL;
169   }
170 
171   osStatus_t status = osMutexDelete(lock->mutex_ID);
172   return (status == osOK ? SL_STATUS_OK : SL_STATUS_FAIL);
173 }
174 
175 /***************************************************************************//**
176  * @brief          Pend on a lock with timeout
177  *
178  * @param lock     Pointer to the lock being pended on
179  *
180  * @return         SL_STATUS_OK on success, error code otherwise.
181  *****************************************************************************/
182 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_PSEC_OSAL, SL_CODE_CLASS_TIME_CRITICAL)
183 sl_status_t sli_psec_osal_take_lock_timeout(sli_psec_osal_lock_t *lock,
184                                             uint32_t timeout);
185 
186 /***************************************************************************//**
187  * @brief          Pend on a lock forever
188  *
189  * @param lock     Pointer to the lock being pended on
190  *
191  * @return         SL_STATUS_OK on success, error code otherwise.
192  *****************************************************************************/
sli_psec_osal_take_lock(sli_psec_osal_lock_t * lock)193 __STATIC_INLINE sl_status_t sli_psec_osal_take_lock(sli_psec_osal_lock_t *lock)
194 {
195   return sli_psec_osal_take_lock_timeout(lock, SLI_PSEC_OSAL_WAIT_FOREVER);
196 }
197 
198 /***************************************************************************//**
199  * @brief          Try to acquire ownership of a lock without waiting.
200  *
201  * @param lock     Pointer to the lock being tested
202  *
203  * @return         SL_STATUS_OK on success (= lock successfully owned),
204  *                 error code otherwise.
205  *****************************************************************************/
206 __STATIC_INLINE
sli_psec_osal_take_lock_non_blocking(sli_psec_osal_lock_t * lock)207 sl_status_t sli_psec_osal_take_lock_non_blocking(sli_psec_osal_lock_t *lock)
208 {
209   return sli_psec_osal_take_lock_timeout(lock, SLI_PSEC_OSAL_NON_BLOCKING);
210 }
211 
212 /***************************************************************************//**
213  * @brief          Release a lock
214  *
215  * @param lock     Pointer to the lock being released
216  *
217  * @return         SL_STATUS_OK on success, error code otherwise.
218  *****************************************************************************/
219 SL_CODE_CLASSIFY(SL_CODE_COMPONENT_PSEC_OSAL, SL_CODE_CLASS_TIME_CRITICAL)
220 sl_status_t sli_psec_osal_give_lock(sli_psec_osal_lock_t *lock);
221 
222 /***************************************************************************//**
223  * @brief          Initialize a completion object.
224  *
225  * @param p_comp   Pointer to an sli_psec_osal_completion_t object allocated
226  *                 by the user.
227  *
228  * @return         Status code, @ref sl_status.h.
229  *****************************************************************************/
230 __STATIC_INLINE sl_status_t
sli_psec_osal_init_completion(sli_psec_osal_completion_t * p_comp)231 sli_psec_osal_init_completion(sli_psec_osal_completion_t *p_comp)
232 {
233   if (p_comp == NULL) {
234     return SL_STATUS_FAIL;
235   }
236 
237 #if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT) && (configSUPPORT_STATIC_ALLOCATION == 1)
238   // Zeroize all members of the semaphore attributes object and setup the static control block.
239   memset(&p_comp->semaphore_attr, 0, sizeof(p_comp->semaphore_attr));
240   p_comp->semaphore_attr.cb_mem = &p_comp->static_sem_object;
241   p_comp->semaphore_attr.cb_size = sizeof(p_comp->static_sem_object);
242   p_comp->semaphore_ID = osSemaphoreNew(1u, 0u, &p_comp->semaphore_attr);
243 #else
244   p_comp->semaphore_ID = osSemaphoreNew(1u, 0u, NULL);
245 #endif
246 
247   return (p_comp->semaphore_ID == NULL ? SL_STATUS_FAIL : SL_STATUS_OK);
248 }
249 
250 /***************************************************************************//**
251  * @brief          Free a completion object.
252  *
253  * @param p_comp   Pointer to an sli_psec_osal_completion_t object.
254  *
255  * @return         Status code, @ref sl_status.h.
256  *****************************************************************************/
257 __STATIC_INLINE sl_status_t
sli_psec_osal_free_completion(sli_psec_osal_completion_t * p_comp)258 sli_psec_osal_free_completion(sli_psec_osal_completion_t *p_comp)
259 {
260   if (p_comp == NULL) {
261     return SL_STATUS_FAIL;
262   }
263 
264   osStatus_t status = osSemaphoreDelete(p_comp->semaphore_ID);
265   return (status == osOK ? SL_STATUS_OK : SL_STATUS_FAIL);
266 }
267 
268 /***************************************************************************//**
269  * @brief          Wait for completion event.
270  *
271  * @param p_comp   Pointer to completion object which must be initialized by
272  *                 calling sli_psec_osal_completion_init before calling this
273  *                 function.
274  *
275  * @param ticks    Ticks to wait for the completion.
276  *                 Pass a value of SLI_PSEC_OSAL_WAIT_FOREVER in order to
277  *                 wait forever.
278  *                 Pass a value of SLI_PSEC_OSAL_NON_BLOCKING in order to
279  *                 return immediately.
280  *
281  * @return         Status code, @ref sl_status.h. Typcally SL_STATUS_OK if success,
282  *                 or SL_STATUS_TIMEOUT if no completion within the given ticks.
283  *****************************************************************************/
284 __STATIC_INLINE sl_status_t
sli_psec_osal_wait_completion(sli_psec_osal_completion_t * p_comp,int ticks)285 sli_psec_osal_wait_completion(sli_psec_osal_completion_t *p_comp, int ticks)
286 {
287   if (p_comp == NULL) {
288     return SL_STATUS_FAIL;
289   }
290 
291   osStatus_t status = osOK;
292   if (osKernelGetState() == osKernelRunning) {
293     status = osSemaphoreAcquire(p_comp->semaphore_ID,
294                                 (uint32_t)ticks);
295   }
296   return (status == osOK ? SL_STATUS_OK : SL_STATUS_FAIL);
297 }
298 
299 /***************************************************************************//**
300  * @brief          Signal completion.
301  *
302  * @param p_comp   Pointer to completion object which must be initialized by
303  *                 calling sli_psec_osal_completion_init before calling this
304  *                 function.
305  *
306  * @return         Status code, @ref sl_status.h.
307  *****************************************************************************/
308 __STATIC_INLINE
sli_psec_osal_complete(sli_psec_osal_completion_t * p_comp)309 sl_status_t sli_psec_osal_complete(sli_psec_osal_completion_t* p_comp)
310 {
311   if (p_comp == NULL) {
312     return SL_STATUS_FAIL;
313   }
314 
315   osStatus_t status = osOK;
316   osKernelState_t state = osKernelGetState();
317   if ((state == osKernelRunning) || (state == osKernelLocked)) {
318     status = osSemaphoreRelease(p_comp->semaphore_ID);
319   }
320   return (status == osOK ? SL_STATUS_OK : SL_STATUS_FAIL);
321 }
322 
323 /***************************************************************************//**
324  * @brief          Lock the RTOS Kernel scheduler.
325  *
326  * @return         Status code, @ref cmsis_os2.h
327  *****************************************************************************/
sli_psec_osal_kernel_lock(void)328 __STATIC_INLINE int32_t sli_psec_osal_kernel_lock(void)
329 {
330   return osKernelLock();
331 }
332 
333 /***************************************************************************//**
334  * @brief          Restore the RTOS Kernel scheduler lock state.
335  *
336  * @return         Status code, @ref cmsis_os2.h
337  *****************************************************************************/
sli_psec_osal_kernel_restore_lock(int32_t lock)338 __STATIC_INLINE int32_t sli_psec_osal_kernel_restore_lock(int32_t lock)
339 {
340   return osKernelRestoreLock(lock);
341 }
342 
343 /***************************************************************************//**
344  * @brief          Get current RTOS kernel state.
345  *
346  * @return         Status code, @ref cmsis_os2.h
347  *****************************************************************************/
348 __STATIC_INLINE osKernelState_t
sli_psec_osal_kernel_get_state(void)349 sli_psec_osal_kernel_get_state(void)
350 {
351   return osKernelGetState();
352 }
353 
354 #ifdef __cplusplus
355 }
356 #endif
357 
358 #endif // SLI_PSEC_OSAL_CMSIS_RTOS_H
359