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