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