]> begriffs open source - cmsis-freertos/blob - CMSIS/RTOS2/FreeRTOS/Source/ARM/clib_arm.c
Update component versions (consistency)
[cmsis-freertos] / CMSIS / RTOS2 / FreeRTOS / Source / ARM / clib_arm.c
1 /* -------------------------------------------------------------------------- 
2  * Copyright (c) 2013-2022 Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Licensed under the Apache License, Version 2.0 (the License); you may
7  * not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  *      Name:    clib_arm.c
19  *      Purpose: ARM C library startup and initialization support
20  *
21  *---------------------------------------------------------------------------*/
22
23 #include <stdint.h>
24 #include <stddef.h>
25
26 #include "FreeRTOS.h"                   // ARM.FreeRTOS::RTOS:Core
27 #include "task.h"                       // ARM.FreeRTOS::RTOS:Core
28 #include "semphr.h"                     // ARM.FreeRTOS::RTOS:Core
29
30 /* Define the number of Threads which use standard C/C++ library libspace */
31 #ifndef OS_THREAD_LIBSPACE_NUM
32   #define OS_THREAD_LIBSPACE_NUM      4
33 #endif
34
35 /* Define the number of Mutexes used by standard C/C++ library for stream protection */
36 #ifndef OS_MUTEX_CLIB_NUM
37   #define OS_MUTEX_CLIB_NUM           5
38 #endif
39
40 /*----------------------------------------------------------------------------*/
41
42 /* Initialization after stack and heap setup */
43 #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
44
45 #ifndef __MICROLIB
46 __WEAK
47 void _platform_post_stackheap_init (void);
48 void _platform_post_stackheap_init (void) {
49   /* Initialize OS, memory, etc. */
50   #if defined(RTE_Compiler_EventRecorder)
51     EvrFreeRTOSSetup(0);
52   #endif
53 }
54 #endif /* __MICROLIB */
55
56 #elif defined(__GNUC__)
57 __WEAK
58 void software_init_hook (void);
59 void software_init_hook (void) {
60   /* Initialize OS, memory, etc. */
61   #if defined(RTE_Compiler_EventRecorder)
62     EvrFreeRTOSSetup(0);
63   #endif
64 }
65
66 #endif
67
68 /*----------------------------------------------------------------------------*/
69
70 /* C/C++ Standard Library Multithreading Interface */
71 #if (( defined(__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))) && !defined(__MICROLIB))
72
73 #define LIBSPACE_SIZE 96
74
75 /* Libspace memory pool */
76 static uint32_t os_libspace[OS_THREAD_LIBSPACE_NUM+1][LIBSPACE_SIZE/sizeof(uint32_t)];
77
78 /* Array of Threads (IDs) using libspace */
79 static TaskHandle_t os_libspace_id[OS_THREAD_LIBSPACE_NUM];
80
81 /* OS Kernel state checking */
82 static uint32_t os_kernel_is_active (void) {
83   if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
84     return 1U;
85   } else {
86     return 0U;
87   }
88 }
89
90 /* Check if processor is in Thread or Handler mode */
91 static uint32_t is_thread_mode (void) {
92   if (__get_IPSR() == 0U) {
93     return 1U; /* Thread mode  */
94   } else {
95     return 0U; /* Handler mode */
96   }
97 }
98
99 /* Provide libspace for current thread */
100 void *__user_perthread_libspace (void);
101 void *__user_perthread_libspace (void) {
102   TaskHandle_t id;
103   uint32_t     n;
104
105   if (!os_kernel_is_active()) {
106     return (void *)&os_libspace[OS_THREAD_LIBSPACE_NUM][0];
107   }
108
109   id = xTaskGetCurrentTaskHandle();
110
111   for (n = 0U; n < OS_THREAD_LIBSPACE_NUM; n++) {
112     if (os_libspace_id[n] == NULL) {
113
114       os_libspace_id[n] = id;
115
116       return (void *)&os_libspace[n][0];
117     }
118     if (os_libspace_id[n] == id) {
119       return (void *)&os_libspace[n][0];
120     }
121   }
122
123   return (void *)&os_libspace[n][0];
124 }
125
126 /*----------------------------------------------------------------------------*/
127
128 #if (OS_MUTEX_CLIB_NUM > 0)
129 static StaticSemaphore_t clib_mutex_cb[OS_MUTEX_CLIB_NUM];
130 static SemaphoreHandle_t clib_mutex_id[OS_MUTEX_CLIB_NUM];
131 #endif
132
133 /* Define mutex object and function prototypes */
134 typedef void *mutex;
135
136 __USED int  _mutex_initialize(mutex *m);
137 __USED void _mutex_acquire   (mutex *m);
138 __USED void _mutex_release   (mutex *m);
139 __USED void _mutex_free      (mutex *m);
140
141
142 /* Initialize mutex */
143 int _mutex_initialize(mutex *m) {
144 #if (OS_MUTEX_CLIB_NUM > 0)
145   uint32_t i;
146 #endif
147
148   *m = NULL;
149
150 #if (OS_MUTEX_CLIB_NUM > 0)
151   for (i = 0U; i < OS_MUTEX_CLIB_NUM; i++) {
152     if (clib_mutex_id[i] == NULL) {
153       /* Create mutex using static memory */
154       clib_mutex_id[i] = xSemaphoreCreateMutexStatic(&clib_mutex_cb[i]);
155
156       /* Return mutex id */
157       *m = clib_mutex_id[i];
158       break;
159     }
160   }
161 #endif
162   if ((*m == NULL) && (os_kernel_is_active())) {
163     /* Create mutex using dynamic memory */
164     *m = xSemaphoreCreateMutex();
165   }
166
167   /* FreeRTOS disables interrupts when its API is called before the kernel is started. */
168   /* This is pre-main context and since interrupts shall not happen before reaching    */
169   /* main we can re-enable interrupts and have consistent state when main gets called. */
170   portENABLE_INTERRUPTS();
171
172   if (*m == NULL) {
173     return 0;
174   }
175   return 1;
176 }
177
178 /* Acquire mutex */
179 void _mutex_acquire(mutex *m) {
180   /* Don't allow mutex operations when the kernel is not switching tasks and also   */
181   /* block protection when in interrupt. Using stdio streams in interrupt is bad    */
182   /* practice, but some applications call printf as last resort for debug purposes. */
183   if (os_kernel_is_active() && is_thread_mode()) {
184     xSemaphoreTake(*m, portMAX_DELAY);
185   }
186 }
187
188 /* Release mutex */
189 void _mutex_release(mutex *m) {
190
191   if (os_kernel_is_active() && is_thread_mode()) {
192     xSemaphoreGive(*m);
193   }
194 }
195
196 /* Free mutex */
197 void _mutex_free(mutex *m) {
198 #if (OS_MUTEX_CLIB_NUM > 0)
199   uint32_t i;
200 #endif
201
202   vSemaphoreDelete(*m);
203
204 #if (OS_MUTEX_CLIB_NUM > 0)
205   /* Check if mutex was using static memory */
206   for (i = 0U; i < OS_MUTEX_CLIB_NUM; i++) {
207     if (*m == clib_mutex_id[i]) {
208       clib_mutex_id[i] = NULL;
209       break;
210     }
211   }
212 #endif
213 }
214
215 #endif