1 /* --------------------------------------------------------------------------
2 * Copyright (c) 2013-2022 Arm Limited. All rights reserved.
4 * SPDX-License-Identifier: Apache-2.0
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
10 * www.apache.org/licenses/LICENSE-2.0
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.
19 * Purpose: ARM C library startup and initialization support
21 *---------------------------------------------------------------------------*/
26 #include "FreeRTOS.h" // ARM.FreeRTOS::RTOS:Core
27 #include "task.h" // ARM.FreeRTOS::RTOS:Core
28 #include "semphr.h" // ARM.FreeRTOS::RTOS:Core
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
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
40 /*----------------------------------------------------------------------------*/
42 /* Initialization after stack and heap setup */
43 #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
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)
54 #endif /* __MICROLIB */
56 #elif defined(__GNUC__)
58 void software_init_hook (void);
59 void software_init_hook (void) {
60 /* Initialize OS, memory, etc. */
61 #if defined(RTE_Compiler_EventRecorder)
68 /*----------------------------------------------------------------------------*/
70 /* C/C++ Standard Library Multithreading Interface */
71 #if (( defined(__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))) && !defined(__MICROLIB))
73 #define LIBSPACE_SIZE 96
75 /* Libspace memory pool */
76 static uint32_t os_libspace[OS_THREAD_LIBSPACE_NUM+1][LIBSPACE_SIZE/sizeof(uint32_t)];
78 /* Array of Threads (IDs) using libspace */
79 static TaskHandle_t os_libspace_id[OS_THREAD_LIBSPACE_NUM];
81 /* OS Kernel state checking */
82 static uint32_t os_kernel_is_active (void) {
83 if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
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 */
95 return 0U; /* Handler mode */
99 /* Provide libspace for current thread */
100 void *__user_perthread_libspace (void);
101 void *__user_perthread_libspace (void) {
105 if (!os_kernel_is_active()) {
106 return (void *)&os_libspace[OS_THREAD_LIBSPACE_NUM][0];
109 id = xTaskGetCurrentTaskHandle();
111 for (n = 0U; n < OS_THREAD_LIBSPACE_NUM; n++) {
112 if (os_libspace_id[n] == NULL) {
114 os_libspace_id[n] = id;
116 return (void *)&os_libspace[n][0];
118 if (os_libspace_id[n] == id) {
119 return (void *)&os_libspace[n][0];
123 return (void *)&os_libspace[n][0];
126 /*----------------------------------------------------------------------------*/
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];
133 /* Define mutex object and function prototypes */
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);
142 /* Initialize mutex */
143 int _mutex_initialize(mutex *m) {
144 #if (OS_MUTEX_CLIB_NUM > 0)
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]);
156 /* Return mutex id */
157 *m = clib_mutex_id[i];
162 if ((*m == NULL) && (os_kernel_is_active())) {
163 /* Create mutex using dynamic memory */
164 *m = xSemaphoreCreateMutex();
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();
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);
189 void _mutex_release(mutex *m) {
191 if (os_kernel_is_active() && is_thread_mode()) {
197 void _mutex_free(mutex *m) {
198 #if (OS_MUTEX_CLIB_NUM > 0)
202 vSemaphoreDelete(*m);
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;