]> begriffs open source - freertos/blob - portable/ThirdParty/GCC/Xtensa_ESP32/port.c
Fix some broken/redirected URL (#172)
[freertos] / portable / ThirdParty / GCC / Xtensa_ESP32 / port.c
1 /*\r
2  *  FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd.\r
3  *  All rights reserved\r
4  *\r
5  *  VISIT https://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6  *\r
7  *  This file is part of the FreeRTOS distribution.\r
8  *\r
9  *  FreeRTOS is free software; you can redistribute it and/or modify it under\r
10  *  the terms of the GNU General Public License (version 2) as published by the\r
11  *  Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
12  *\r
13  ***************************************************************************\r
14  *  >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15  *  >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16  *  >>!   obliged to provide the source code for proprietary components     !<<\r
17  *  >>!   outside of the FreeRTOS kernel.                                   !<<\r
18  ***************************************************************************\r
19  *\r
20  *  FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22  *  FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23  *  link: https://www.FreeRTOS.org/a00114.html\r
24  *\r
25  ***************************************************************************\r
26  *                                                                       *\r
27  *    FreeRTOS provides completely free yet professionally developed,    *\r
28  *    robust, strictly quality controlled, supported, and cross          *\r
29  *    platform software that is more than just the market leader, it     *\r
30  *    is the industry's de facto standard.                               *\r
31  *                                                                       *\r
32  *    Help yourself get started quickly while simultaneously helping     *\r
33  *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34  *    tutorial book, reference manual, or both:                          *\r
35  *    https://www.FreeRTOS.org/Documentation                             *\r
36  *                                                                       *\r
37  ***************************************************************************\r
38  *\r
39  *  https://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40  *  the FAQ page "My application does not run, what could be wrong?".  Have you\r
41  *  defined configASSERT()?\r
42  *\r
43  *  https://www.FreeRTOS.org/support - In return for receiving this top quality\r
44  *  embedded software for free we request you assist our global community by\r
45  *  participating in the support forum.\r
46  *\r
47  *  https://www.FreeRTOS.org/training - Investing in training allows your team\r
48  *  to be as productive as possible as early as possible.  Now you can receive\r
49  *  FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50  *  Ltd, and the world's leading authority on the world's leading RTOS.\r
51  *\r
52  *  https://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53  *  including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54  *  compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55  *\r
56  *  https://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57  *  Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58  *\r
59  *  https://www.highintegritysystems.com/openrtos/ - Real Time Engineers ltd.\r
60  *  license FreeRTOS to High Integrity Systems ltd. to sell under the OpenRTOS\r
61  *  brand.  Low cost OpenRTOS licenses offer ticketed support, indemnification\r
62  *  and commercial middleware.\r
63  *\r
64  *  https://www.highintegritysystems.com/safertos/ - High Integrity Systems\r
65  *  also provide a safety engineered and independently SIL3 certified version\r
66  *  for use in safety and mission critical applications that require provable\r
67  *  dependability.\r
68  *\r
69  */\r
70 \r
71 /*******************************************************************************\r
72  * // Copyright (c) 2003-2015 Cadence Design Systems, Inc.\r
73  * //\r
74  * // Permission is hereby granted, free of charge, to any person obtaining\r
75  * // a copy of this software and associated documentation files (the\r
76  * // "Software"), to deal in the Software without restriction, including\r
77  * // without limitation the rights to use, copy, modify, merge, publish,\r
78  * // distribute, sublicense, and/or sell copies of the Software, and to\r
79  * // permit persons to whom the Software is furnished to do so, subject to\r
80  * // the following conditions:\r
81  * //\r
82  * // The above copyright notice and this permission notice shall be included\r
83  * // in all copies or substantial portions of the Software.\r
84  * //\r
85  * // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
86  * // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
87  * // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
88  * // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r
89  * // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r
90  * // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r
91  * // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
92  * -----------------------------------------------------------------------------\r
93  */\r
94 \r
95 #include <stdlib.h>\r
96 #include <xtensa/config/core.h>\r
97 \r
98 #include "xtensa_rtos.h"\r
99 \r
100 #include "rom/ets_sys.h"\r
101 #include "soc/cpu.h"\r
102 \r
103 #include "FreeRTOS.h"\r
104 #include "task.h"\r
105 \r
106 #include "esp_panic.h"\r
107 #include "esp_heap_caps.h"\r
108 #include "esp_crosscore_int.h"\r
109 \r
110 #include "esp_intr_alloc.h"\r
111 \r
112 /* Defined in portasm.h */\r
113 extern void _frxt_tick_timer_init( void );\r
114 \r
115 /* Defined in xtensa_context.S */\r
116 extern void _xt_coproc_init( void );\r
117 \r
118 \r
119 #if CONFIG_FREERTOS_CORETIMER_0\r
120     #define SYSTICK_INTR_ID    ( ETS_INTERNAL_TIMER0_INTR_SOURCE + ETS_INTERNAL_INTR_SOURCE_OFF )\r
121 #endif\r
122 #if CONFIG_FREERTOS_CORETIMER_1\r
123     #define SYSTICK_INTR_ID    ( ETS_INTERNAL_TIMER1_INTR_SOURCE + ETS_INTERNAL_INTR_SOURCE_OFF )\r
124 #endif\r
125 \r
126 /*-----------------------------------------------------------*/\r
127 \r
128 unsigned port_xSchedulerRunning[ portNUM_PROCESSORS ] = { 0 }; /* Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting */\r
129 unsigned port_interruptNesting[ portNUM_PROCESSORS ] = { 0 };  /* Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit */\r
130 \r
131 /*-----------------------------------------------------------*/\r
132 \r
133 /* User exception dispatcher when exiting */\r
134 void _xt_user_exit( void );\r
135 \r
136 /*\r
137  * Stack initialization\r
138  */\r
139 /* *INDENT-OFF* */\r
140 #if portUSING_MPU_WRAPPERS\r
141     StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
142                                          TaskFunction_t pxCode,\r
143                                          void * pvParameters,\r
144                                          BaseType_t xRunPrivileged )\r
145 #else\r
146     StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
147                                          TaskFunction_t pxCode,\r
148                                          void * pvParameters )\r
149 #endif\r
150 /* *INDENT-ON* */\r
151 {\r
152     StackType_t * sp, * tp;\r
153     XtExcFrame * frame;\r
154 \r
155     #if XCHAL_CP_NUM > 0\r
156         uint32_t * p;\r
157     #endif\r
158 \r
159     /* Create interrupt stack frame aligned to 16 byte boundary */\r
160     sp = ( StackType_t * ) ( ( ( UBaseType_t ) ( pxTopOfStack + 1 ) - XT_CP_SIZE - XT_STK_FRMSZ ) & ~0xf );\r
161 \r
162     /* Clear the entire frame (do not use memset() because we don't depend on C library) */\r
163     for( tp = sp; tp <= pxTopOfStack; ++tp )\r
164     {\r
165         *tp = 0;\r
166     }\r
167 \r
168     frame = ( XtExcFrame * ) sp;\r
169 \r
170     /* Explicitly initialize certain saved registers */\r
171     frame->pc = ( UBaseType_t ) pxCode;             /* task entrypoint                */\r
172     frame->a0 = 0;                                  /* to terminate GDB backtrace     */\r
173     frame->a1 = ( UBaseType_t ) sp + XT_STK_FRMSZ;  /* physical top of stack frame    */\r
174     frame->exit = ( UBaseType_t ) _xt_user_exit;    /* user exception exit dispatcher */\r
175 \r
176     /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */\r
177     /* Also set entry point argument parameter. */\r
178     #ifdef __XTENSA_CALL0_ABI__\r
179         frame->a2 = ( UBaseType_t ) pvParameters;\r
180         frame->ps = PS_UM | PS_EXCM;\r
181     #else\r
182         /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */\r
183         frame->a6 = ( UBaseType_t ) pvParameters;\r
184         frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC( 1 );\r
185     #endif\r
186 \r
187     #ifdef XT_USE_SWPRI\r
188         /* Set the initial virtual priority mask value to all 1's. */\r
189         frame->vpri = 0xFFFFFFFF;\r
190     #endif\r
191 \r
192     #if XCHAL_CP_NUM > 0\r
193         /* Init the coprocessor save area (see xtensa_context.h) */\r
194 \r
195         /* No access to TCB here, so derive indirectly. Stack growth is top to bottom.\r
196          * //p = (uint32_t *) xMPUSettings->coproc_area;\r
197          */\r
198         p = ( uint32_t * ) ( ( ( uint32_t ) pxTopOfStack - XT_CP_SIZE ) & ~0xf );\r
199         p[ 0 ] = 0;\r
200         p[ 1 ] = 0;\r
201         p[ 2 ] = ( ( ( uint32_t ) p ) + 12 + XCHAL_TOTAL_SA_ALIGN - 1 ) & -XCHAL_TOTAL_SA_ALIGN;\r
202     #endif\r
203 \r
204     return sp;\r
205 }\r
206 \r
207 /*-----------------------------------------------------------*/\r
208 \r
209 void vPortEndScheduler( void )\r
210 {\r
211     /* It is unlikely that the Xtensa port will get stopped.  If required simply\r
212      * disable the tick interrupt here. */\r
213 }\r
214 \r
215 /*-----------------------------------------------------------*/\r
216 \r
217 BaseType_t xPortStartScheduler( void )\r
218 {\r
219     /* Interrupts are disabled at this point and stack contains PS with enabled interrupts when task context is restored */\r
220 \r
221     #if XCHAL_CP_NUM > 0\r
222         /* Initialize co-processor management for tasks. Leave CPENABLE alone. */\r
223         _xt_coproc_init();\r
224     #endif\r
225 \r
226     /* Init the tick divisor value */\r
227     _xt_tick_divisor_init();\r
228 \r
229     /* Setup the hardware to generate the tick. */\r
230     _frxt_tick_timer_init();\r
231 \r
232     port_xSchedulerRunning[ xPortGetCoreID() ] = 1;\r
233 \r
234     /* Cannot be directly called from C; never returns */\r
235     __asm__ volatile ( "call0    _frxt_dispatch\n" );\r
236 \r
237     /* Should not get here. */\r
238     return pdTRUE;\r
239 }\r
240 /*-----------------------------------------------------------*/\r
241 \r
242 BaseType_t xPortSysTickHandler( void )\r
243 {\r
244     BaseType_t ret;\r
245     unsigned interruptMask;\r
246 \r
247     portbenchmarkIntLatency();\r
248     traceISR_ENTER( SYSTICK_INTR_ID );\r
249 \r
250     /* Interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY must be\r
251      * disabled before calling xTaskIncrementTick as it access the\r
252      * kernel lists. */\r
253     interruptMask = portSET_INTERRUPT_MASK_FROM_ISR();\r
254     {\r
255         ret = xTaskIncrementTick();\r
256     }\r
257     portCLEAR_INTERRUPT_MASK_FROM_ISR( interruptMask );\r
258 \r
259     if( ret != pdFALSE )\r
260     {\r
261         portYIELD_FROM_ISR();\r
262     }\r
263     else\r
264     {\r
265         traceISR_EXIT();\r
266     }\r
267 \r
268     return ret;\r
269 }\r
270 \r
271 \r
272 void vPortYieldOtherCore( BaseType_t coreid )\r
273 {\r
274     esp_crosscore_int_send_yield( coreid );\r
275 }\r
276 \r
277 /*-----------------------------------------------------------*/\r
278 \r
279 /*\r
280  * Used to set coprocessor area in stack. Current hack is to reuse MPU pointer for coprocessor area.\r
281  */\r
282 #if portUSING_MPU_WRAPPERS\r
283     void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,\r
284                                     const struct xMEMORY_REGION * const xRegions,\r
285                                     StackType_t * pxBottomOfStack,\r
286                                     uint32_t usStackDepth )\r
287     {\r
288         #if XCHAL_CP_NUM > 0\r
289             xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( ( uint32_t ) ( pxBottomOfStack + usStackDepth - 1 ) ) - XT_CP_SIZE ) & ~0xf );\r
290 \r
291 \r
292             /* NOTE: we cannot initialize the coprocessor save area here because FreeRTOS is going to\r
293              * clear the stack area after we return. This is done in pxPortInitialiseStack().\r
294              */\r
295         #endif\r
296     }\r
297 \r
298     void vPortReleaseTaskMPUSettings( xMPU_SETTINGS * xMPUSettings )\r
299     {\r
300         /* If task has live floating point registers somewhere, release them */\r
301         _xt_coproc_release( xMPUSettings->coproc_area );\r
302     }\r
303 \r
304 #endif /* if portUSING_MPU_WRAPPERS */\r
305 \r
306 /*\r
307  * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs\r
308  * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.\r
309  */\r
310 BaseType_t xPortInIsrContext()\r
311 {\r
312     unsigned int irqStatus;\r
313     BaseType_t ret;\r
314 \r
315     irqStatus = portENTER_CRITICAL_NESTED();\r
316     ret = ( port_interruptNesting[ xPortGetCoreID() ] != 0 );\r
317     portEXIT_CRITICAL_NESTED( irqStatus );\r
318     return ret;\r
319 }\r
320 \r
321 /*\r
322  * This function will be called in High prio ISRs. Returns true if the current core was in ISR context\r
323  * before calling into high prio ISR context.\r
324  */\r
325 BaseType_t IRAM_ATTR xPortInterruptedFromISRContext()\r
326 {\r
327     return( port_interruptNesting[ xPortGetCoreID() ] != 0 );\r
328 }\r
329 \r
330 void vPortAssertIfInISR()\r
331 {\r
332     if( xPortInIsrContext() )\r
333     {\r
334         ets_printf( "core=%d port_interruptNesting=%d\n\n", xPortGetCoreID(), port_interruptNesting[ xPortGetCoreID() ] );\r
335     }\r
336 \r
337     configASSERT( !xPortInIsrContext() );\r
338 }\r
339 \r
340 /*\r
341  * For kernel use: Initialize a per-CPU mux. Mux will be initialized unlocked.\r
342  */\r
343 void vPortCPUInitializeMutex( portMUX_TYPE * mux )\r
344 {\r
345     #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG\r
346         ets_printf( "Initializing mux %p\n", mux );\r
347         mux->lastLockedFn = "(never locked)";\r
348         mux->lastLockedLine = -1;\r
349     #endif\r
350     mux->owner = portMUX_FREE_VAL;\r
351     mux->count = 0;\r
352 }\r
353 \r
354 #include "portmux_impl.h"\r
355 \r
356 /*\r
357  * For kernel use: Acquire a per-CPU mux. Spinlocks, so don't hold on to these muxes for too long.\r
358  */\r
359 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG\r
360     void vPortCPUAcquireMutex( portMUX_TYPE * mux,\r
361                                const char * fnName,\r
362                                int line )\r
363     {\r
364         unsigned int irqStatus = portENTER_CRITICAL_NESTED();\r
365 \r
366         vPortCPUAcquireMutexIntsDisabled( mux, portMUX_NO_TIMEOUT, fnName, line );\r
367         portEXIT_CRITICAL_NESTED( irqStatus );\r
368     }\r
369 \r
370     bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux,\r
371                                       int timeout_cycles,\r
372                                       const char * fnName,\r
373                                       int line )\r
374     {\r
375         unsigned int irqStatus = portENTER_CRITICAL_NESTED();\r
376         bool result = vPortCPUAcquireMutexIntsDisabled( mux, timeout_cycles, fnName, line );\r
377 \r
378         portEXIT_CRITICAL_NESTED( irqStatus );\r
379         return result;\r
380     }\r
381 \r
382 #else /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */\r
383     void vPortCPUAcquireMutex( portMUX_TYPE * mux )\r
384     {\r
385         unsigned int irqStatus = portENTER_CRITICAL_NESTED();\r
386 \r
387         vPortCPUAcquireMutexIntsDisabled( mux, portMUX_NO_TIMEOUT );\r
388         portEXIT_CRITICAL_NESTED( irqStatus );\r
389     }\r
390 \r
391     bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux,\r
392                                       int timeout_cycles )\r
393     {\r
394         unsigned int irqStatus = portENTER_CRITICAL_NESTED();\r
395         bool result = vPortCPUAcquireMutexIntsDisabled( mux, timeout_cycles );\r
396 \r
397         portEXIT_CRITICAL_NESTED( irqStatus );\r
398         return result;\r
399     }\r
400 #endif /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */\r
401 \r
402 \r
403 /*\r
404  * For kernel use: Release a per-CPU mux\r
405  *\r
406  * Mux must be already locked by this core\r
407  */\r
408 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG\r
409     void vPortCPUReleaseMutex( portMUX_TYPE * mux,\r
410                                const char * fnName,\r
411                                int line )\r
412     {\r
413         unsigned int irqStatus = portENTER_CRITICAL_NESTED();\r
414 \r
415         vPortCPUReleaseMutexIntsDisabled( mux, fnName, line );\r
416         portEXIT_CRITICAL_NESTED( irqStatus );\r
417     }\r
418 #else\r
419     void vPortCPUReleaseMutex( portMUX_TYPE * mux )\r
420     {\r
421         unsigned int irqStatus = portENTER_CRITICAL_NESTED();\r
422 \r
423         vPortCPUReleaseMutexIntsDisabled( mux );\r
424         portEXIT_CRITICAL_NESTED( irqStatus );\r
425     }\r
426 #endif /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */\r
427 \r
428 void vPortSetStackWatchpoint( void * pxStackStart )\r
429 {\r
430     /*Set watchpoint 1 to watch the last 32 bytes of the stack. */\r
431     /*Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because */\r
432     /*the size works by masking off the lowest address bits. For that reason, we futz a bit and watch the lowest 32 */\r
433     /*bytes of the stack we can actually watch. In general, this can cause the watchpoint to be triggered at most */\r
434     /*28 bytes early. The value 32 is chosen because it's larger than the stack canary, which in FreeRTOS is 20 bytes. */\r
435     /*This way, we make sure we trigger before/when the stack canary is corrupted, not after. */\r
436     int addr = ( int ) pxStackStart;\r
437 \r
438     addr = ( addr + 31 ) & ( ~31 );\r
439     esp_set_watchpoint( 1, ( char * ) addr, 32, ESP_WATCHPOINT_STORE );\r
440 }\r
441 \r
442 #if defined( CONFIG_SPIRAM_SUPPORT )\r
443 \r
444 /*\r
445  * Compare & set (S32C1) does not work in external RAM. Instead, this routine uses a mux (in internal memory) to fake it.\r
446  */\r
447     static portMUX_TYPE extram_mux = portMUX_INITIALIZER_UNLOCKED;\r
448 \r
449     void uxPortCompareSetExtram( volatile uint32_t * addr,\r
450                                  uint32_t compare,\r
451                                  uint32_t * set )\r
452     {\r
453         uint32_t prev;\r
454 \r
455         #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG\r
456             vPortCPUAcquireMutexIntsDisabled( &extram_mux, portMUX_NO_TIMEOUT, __FUNCTION__, __LINE__ );\r
457         #else\r
458             vPortCPUAcquireMutexIntsDisabled( &extram_mux, portMUX_NO_TIMEOUT );\r
459         #endif\r
460         prev = *addr;\r
461 \r
462         if( prev == compare )\r
463         {\r
464             *addr = *set;\r
465         }\r
466 \r
467         *set = prev;\r
468         #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG\r
469             vPortCPUReleaseMutexIntsDisabled( &extram_mux, __FUNCTION__, __LINE__ );\r
470         #else\r
471             vPortCPUReleaseMutexIntsDisabled( &extram_mux );\r
472         #endif\r
473     }\r
474 #endif //defined(CONFIG_SPIRAM_SUPPORT)\r
475 \r
476 \r
477 \r
478 uint32_t xPortGetTickRateHz( void )\r
479 {\r
480     return ( uint32_t ) configTICK_RATE_HZ;\r
481 }\r