1 /*
2 * SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates
3 * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
8 */
9
10 /*
11 * FreeRTOS Kernel V11.1.0
12 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy of
15 * this software and associated documentation files (the "Software"), to deal in
16 * the Software without restriction, including without limitation the rights to
17 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
18 * the Software, and to permit persons to whom the Software is furnished to do so,
19 * subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in all
22 * copies or substantial portions of the Software. If you wish to use our Amazon
23 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
27 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
28 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
29 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 *
32 * https://www.FreeRTOS.org
33 * https://github.com/FreeRTOS
34 *
35 * 1 tab == 4 spaces!
36 */
37
38 /*
39 * Copyright (c) 2015-2019 Cadence Design Systems, Inc.
40 *
41 * Permission is hereby granted, free of charge, to any person obtaining
42 * a copy of this software and associated documentation files (the
43 * "Software"), to deal in the Software without restriction, including
44 * without limitation the rights to use, copy, modify, merge, publish,
45 * distribute, sublicense, and/or sell copies of the Software, and to
46 * permit persons to whom the Software is furnished to do so, subject to
47 * the following conditions:
48 *
49 * The above copyright notice and this permission notice shall be included
50 * in all copies or substantial portions of the Software.
51 *
52 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
53 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
55 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
56 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
57 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
58 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
59 */
60
61 #include <stdlib.h>
62 #include <string.h>
63 #include <xtensa/config/core.h>
64
65 #include "xtensa_rtos.h"
66 #include "esp_idf_version.h"
67
68 #if ( ESP_IDF_VERSION < ESP_IDF_VERSION_VAL( 4, 2, 0 ) )
69 #include "rom/ets_sys.h"
70 #include "esp_panic.h"
71 #include "esp_crosscore_int.h"
72 #else
73 #if CONFIG_IDF_TARGET_ESP32S3
74 #include "esp32s3/rom/ets_sys.h"
75 #elif CONFIG_IDF_TARGET_ESP32S2
76 #include "esp32s2/rom/ets_sys.h"
77 #elif CONFIG_IDF_TARGET_ESP32
78 #include "esp32/rom/ets_sys.h"
79 #endif
80 #include "esp_private/panic_reason.h"
81 #include "esp_debug_helpers.h"
82 #include "esp_private/crosscore_int.h"
83 #include "esp_log.h"
84 #endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
85 #include "soc/cpu.h"
86
87 #include "FreeRTOS.h"
88 #include "task.h"
89
90 #include "esp_heap_caps.h"
91
92 #include "esp_intr_alloc.h"
93
94 #include "port_systick.h"
95
96 /* Defined in xtensa_context.S */
97 extern void _xt_coproc_init( void );
98
99 _Static_assert( tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value" );
100
101 /*-----------------------------------------------------------*/
102
103 extern volatile int port_xSchedulerRunning[ portNUM_PROCESSORS ];
104 unsigned port_interruptNesting[ portNUM_PROCESSORS ] = { 0 }; /* Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit */
105
106 /*-----------------------------------------------------------*/
107
108 /* User exception dispatcher when exiting */
109 void _xt_user_exit( void );
110
111 #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
112 /* Wrapper to allow task functions to return (increases stack overhead by 16 bytes) */
vPortTaskWrapper(TaskFunction_t pxCode,void * pvParameters)113 static void vPortTaskWrapper( TaskFunction_t pxCode,
114 void * pvParameters )
115 {
116 pxCode( pvParameters );
117 /*FreeRTOS tasks should not return. Log the task name and abort. */
118 char * pcTaskName = pcTaskGetTaskName( NULL );
119 ESP_LOGE( "FreeRTOS", "FreeRTOS Task \"%s\" should not return, Aborting now!", pcTaskName );
120 abort();
121 }
122 #endif /* if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER */
123
124 /*
125 * Stack initialization
126 */
127 /* *INDENT-OFF* */
128 #if portUSING_MPU_WRAPPERS
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters,BaseType_t xRunPrivileged)129 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
130 TaskFunction_t pxCode,
131 void * pvParameters,
132 BaseType_t xRunPrivileged )
133 #else
134 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
135 TaskFunction_t pxCode,
136 void * pvParameters )
137 #endif
138 /* *INDENT-ON* */
139 {
140 StackType_t * sp;
141 StackType_t * tp;
142 XtExcFrame * frame;
143
144 #if XCHAL_CP_NUM > 0
145 uint32_t * p;
146 #endif
147
148 uint32_t * threadptr;
149 void * task_thread_local_start;
150 extern int _thread_local_start, _thread_local_end, _flash_rodata_start, _flash_rodata_align;
151
152 /* TODO: check that TLS area fits the stack */
153 uint32_t thread_local_sz = ( uint8_t * ) &_thread_local_end - ( uint8_t * ) &_thread_local_start;
154
155 thread_local_sz = ALIGNUP( 0x10, thread_local_sz );
156
157 /* Initialize task's stack so that we have the following structure at the top:
158 *
159 * ----LOW ADDRESSES ----------------------------------------HIGH ADDRESSES----------
160 * task stack | interrupt stack frame | thread local vars | co-processor save area |
161 * ----------------------------------------------------------------------------------
162 | |
163 | SP pxTopOfStack
164 |
165 | All parts are aligned to 16 byte boundary.
166 */
167
168 /* Create interrupt stack frame aligned to 16 byte boundary */
169 sp = ( StackType_t * ) ( ( ( UBaseType_t ) pxTopOfStack - XT_CP_SIZE - thread_local_sz - XT_STK_FRMSZ ) & ~0xf );
170
171 /* Clear the entire frame (do not use memset() because we don't depend on C library) */
172 for( tp = sp; tp <= pxTopOfStack; ++tp )
173 {
174 *tp = 0;
175 }
176
177 frame = ( XtExcFrame * ) sp;
178
179 /* Explicitly initialize certain saved registers */
180 #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
181 frame->pc = ( UBaseType_t ) vPortTaskWrapper; /* task wrapper */
182 #else
183 frame->pc = ( UBaseType_t ) pxCode; /* task entrypoint */
184 #endif
185 frame->a0 = 0; /* to terminate GDB backtrace */
186 frame->a1 = ( UBaseType_t ) sp + XT_STK_FRMSZ; /* physical top of stack frame */
187 frame->exit = ( UBaseType_t ) _xt_user_exit; /* user exception exit dispatcher */
188
189 /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */
190 /* Also set entry point argument parameter. */
191 #ifdef __XTENSA_CALL0_ABI__
192 #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
193 frame->a2 = ( UBaseType_t ) pxCode;
194 frame->a3 = ( UBaseType_t ) pvParameters;
195 #else
196 frame->a2 = ( UBaseType_t ) pvParameters;
197 #endif
198 frame->ps = PS_UM | PS_EXCM;
199 #else
200 /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
201 #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
202 frame->a6 = ( UBaseType_t ) pxCode;
203 frame->a7 = ( UBaseType_t ) pvParameters;
204 #else
205 frame->a6 = ( UBaseType_t ) pvParameters;
206 #endif
207 frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC( 1 );
208 #endif /* ifdef __XTENSA_CALL0_ABI__ */
209
210 #ifdef XT_USE_SWPRI
211 /* Set the initial virtual priority mask value to all 1's. */
212 frame->vpri = 0xFFFFFFFF;
213 #endif
214
215 /* Init threadptr register and set up TLS run-time area. */
216 task_thread_local_start = ( void * ) ( ( ( uint32_t ) pxTopOfStack - XT_CP_SIZE - thread_local_sz ) & ~0xf );
217 memcpy( task_thread_local_start, &_thread_local_start, thread_local_sz );
218 threadptr = ( uint32_t * ) ( sp + XT_STK_EXTRA );
219
220 /* Calculate THREADPTR value.
221 * The generated code will add THREADPTR value to a constant value determined at link time,
222 * to get the address of the TLS variable.
223 * The constant value is calculated by the linker as follows
224 * (search for 'tpoff' in elf32-xtensa.c in BFD):
225 * offset = address - tls_section_vma + align_up(TCB_SIZE, tls_section_alignment)
226 * where TCB_SIZE is hardcoded to 8.
227 */
228 const uint32_t tls_section_alignment = ( uint32_t ) &_flash_rodata_align; /* ALIGN value of .flash.rodata section */
229 const uint32_t tcb_size = 8; /* Unrelated to FreeRTOS, this is the constant from BFD */
230 const uint32_t base = ( tcb_size + tls_section_alignment - 1 ) & ( ~( tls_section_alignment - 1 ) );
231 *threadptr = ( uint32_t ) task_thread_local_start - ( ( uint32_t ) &_thread_local_start - ( uint32_t ) &_flash_rodata_start ) - base;
232
233 #if XCHAL_CP_NUM > 0
234 /* Init the coprocessor save area (see xtensa_context.h) */
235
236 /* No access to TCB here, so derive indirectly. Stack growth is top to bottom.
237 * //p = (uint32_t *) xMPUSettings->coproc_area;
238 */
239 p = ( uint32_t * ) ( ( ( uint32_t ) pxTopOfStack - XT_CP_SIZE ) & ~0xf );
240 configASSERT( ( uint32_t ) p >= frame->a1 );
241 p[ 0 ] = 0;
242 p[ 1 ] = 0;
243 p[ 2 ] = ( ( ( uint32_t ) p ) + 12 + XCHAL_TOTAL_SA_ALIGN - 1 ) & -XCHAL_TOTAL_SA_ALIGN;
244 #endif
245
246 return sp;
247 }
248
249 /*-----------------------------------------------------------*/
250
vPortEndScheduler(void)251 void vPortEndScheduler( void )
252 {
253 /* It is unlikely that the Xtensa port will get stopped. If required simply
254 * disable the tick interrupt here. */
255 abort();
256 }
257
258 /*-----------------------------------------------------------*/
259
xPortStartScheduler(void)260 BaseType_t xPortStartScheduler( void )
261 {
262 portDISABLE_INTERRUPTS();
263 /* Interrupts are disabled at this point and stack contains PS with enabled interrupts when task context is restored */
264
265 #if XCHAL_CP_NUM > 0
266 /* Initialize co-processor management for tasks. Leave CPENABLE alone. */
267 _xt_coproc_init();
268 #endif
269
270 /* Setup the hardware to generate the tick */
271 vPortSetupTimer();
272
273 /* NOTE: For ESP32-S3, vPortSetupTimer allocates an interrupt for the
274 * systimer which is used as the source for FreeRTOS systick.
275 *
276 * The behaviour of portEXIT_CRITICAL is different in FreeRTOS and ESP-IDF -
277 * the former enables the interrupts no matter what the state was at the beginning
278 * of the call while the latter restores the interrupt state to what was at the
279 * beginning of the call.
280 *
281 * This resulted in the interrupts being enabled before the _frxt_dispatch call,
282 * who was unable to switch context to the queued tasks.
283 */
284 portDISABLE_INTERRUPTS();
285
286 port_xSchedulerRunning[ xPortGetCoreID() ] = 1;
287
288 /* Cannot be directly called from C; never returns */
289 __asm__ volatile ( "call0 _frxt_dispatch\n" );
290
291 /* Should not get here. */
292 return pdTRUE;
293 }
294
295 /*-----------------------------------------------------------*/
296
vPortYieldOtherCore(BaseType_t coreid)297 void vPortYieldOtherCore( BaseType_t coreid )
298 {
299 esp_crosscore_int_send_yield( coreid );
300 }
301
302 /*-----------------------------------------------------------*/
303
304 /*
305 * Used to set coprocessor area in stack. Current hack is to reuse MPU pointer for coprocessor area.
306 */
307 #if portUSING_MPU_WRAPPERS
vPortStoreTaskMPUSettings(xMPU_SETTINGS * xMPUSettings,const struct xMEMORY_REGION * const xRegions,StackType_t * pxBottomOfStack,configSTACK_DEPTH_TYPE uxStackDepth)308 void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
309 const struct xMEMORY_REGION * const xRegions,
310 StackType_t * pxBottomOfStack,
311 configSTACK_DEPTH_TYPE uxStackDepth )
312 {
313 #if XCHAL_CP_NUM > 0
314 xMPUSettings->coproc_area = ( StackType_t * ) ( ( uint32_t ) ( pxBottomOfStack + uxStackDepth - 1 ) );
315 xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) xMPUSettings->coproc_area ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
316 xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( uint32_t ) xMPUSettings->coproc_area - XT_CP_SIZE ) & ~0xf );
317
318 /* NOTE: we cannot initialize the coprocessor save area here because FreeRTOS is going to
319 * clear the stack area after we return. This is done in pxPortInitialiseStack().
320 */
321 #endif
322 }
323
vPortReleaseTaskMPUSettings(xMPU_SETTINGS * xMPUSettings)324 void vPortReleaseTaskMPUSettings( xMPU_SETTINGS * xMPUSettings )
325 {
326 /* If task has live floating point registers somewhere, release them */
327 _xt_coproc_release( xMPUSettings->coproc_area );
328 }
329
330 #endif /* if portUSING_MPU_WRAPPERS */
331
332 /*
333 * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
334 * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
335 */
xPortInIsrContext()336 BaseType_t xPortInIsrContext()
337 {
338 unsigned int irqStatus;
339 BaseType_t ret;
340
341 irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
342 ret = ( port_interruptNesting[ xPortGetCoreID() ] != 0 );
343 portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
344 return ret;
345 }
346
347 /*
348 * This function will be called in High prio ISRs. Returns true if the current core was in ISR context
349 * before calling into high prio ISR context.
350 */
xPortInterruptedFromISRContext()351 BaseType_t IRAM_ATTR xPortInterruptedFromISRContext()
352 {
353 return( port_interruptNesting[ xPortGetCoreID() ] != 0 );
354 }
355
vPortEvaluateYieldFromISR(int argc,...)356 void IRAM_ATTR vPortEvaluateYieldFromISR( int argc,
357 ... )
358 {
359 BaseType_t xYield;
360 va_list ap;
361
362 va_start( ap, argc );
363
364 if( argc )
365 {
366 xYield = ( BaseType_t ) va_arg( ap, int );
367 va_end( ap );
368 }
369 else
370 {
371 /*it is a empty parameter vPortYieldFromISR macro call: */
372 va_end( ap );
373 traceISR_EXIT_TO_SCHEDULER();
374 _frxt_setup_switch();
375 return;
376 }
377
378 /*Yield exists, so need evaluate it first then switch: */
379 if( xYield == pdTRUE )
380 {
381 traceISR_EXIT_TO_SCHEDULER();
382 _frxt_setup_switch();
383 }
384 }
385
vPortAssertIfInISR()386 void vPortAssertIfInISR()
387 {
388 if( xPortInIsrContext() )
389 {
390 esp_rom_printf( "core=%d port_interruptNesting=%d\n\n", xPortGetCoreID(), port_interruptNesting[ xPortGetCoreID() ] );
391 }
392
393 configASSERT( !xPortInIsrContext() );
394 }
395
396 /*
397 * For kernel use: Initialize a per-CPU mux. Mux will be initialized unlocked.
398 */
vPortCPUInitializeMutex(portMUX_TYPE * mux)399 void vPortCPUInitializeMutex( portMUX_TYPE * mux )
400 {
401 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
402 esp_rom_printf( "Initializing mux %p\n", mux );
403 mux->lastLockedFn = "(never locked)";
404 mux->lastLockedLine = -1;
405 #endif
406 mux->owner = portMUX_FREE_VAL;
407 mux->count = 0;
408 }
409
410 #include "portmux_impl.h"
411
412 /*
413 * For kernel use: Acquire a per-CPU mux. Spinlocks, so don't hold on to these muxes for too long.
414 */
415 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
vPortCPUAcquireMutex(portMUX_TYPE * mux,const char * fnName,int line)416 void vPortCPUAcquireMutex( portMUX_TYPE * mux,
417 const char * fnName,
418 int line )
419 {
420 unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
421
422 vPortCPUAcquireMutexIntsDisabled( mux, portMUX_NO_TIMEOUT, fnName, line );
423 portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
424 }
425
vPortCPUAcquireMutexTimeout(portMUX_TYPE * mux,int timeout_cycles,const char * fnName,int line)426 bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux,
427 int timeout_cycles,
428 const char * fnName,
429 int line )
430 {
431 unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
432 bool result = vPortCPUAcquireMutexIntsDisabled( mux, timeout_cycles, fnName, line );
433
434 portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
435 return result;
436 }
437
438 #else /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */
vPortCPUAcquireMutex(portMUX_TYPE * mux)439 void vPortCPUAcquireMutex( portMUX_TYPE * mux )
440 {
441 unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
442
443 vPortCPUAcquireMutexIntsDisabled( mux, portMUX_NO_TIMEOUT );
444 portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
445 }
446
vPortCPUAcquireMutexTimeout(portMUX_TYPE * mux,int timeout_cycles)447 bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux,
448 int timeout_cycles )
449 {
450 unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
451 bool result = vPortCPUAcquireMutexIntsDisabled( mux, timeout_cycles );
452
453 portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
454 return result;
455 }
456 #endif /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */
457
458
459 /*
460 * For kernel use: Release a per-CPU mux
461 *
462 * Mux must be already locked by this core
463 */
464 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
vPortCPUReleaseMutex(portMUX_TYPE * mux,const char * fnName,int line)465 void vPortCPUReleaseMutex( portMUX_TYPE * mux,
466 const char * fnName,
467 int line )
468 {
469 unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
470
471 vPortCPUReleaseMutexIntsDisabled( mux, fnName, line );
472 portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
473 }
474 #else
vPortCPUReleaseMutex(portMUX_TYPE * mux)475 void vPortCPUReleaseMutex( portMUX_TYPE * mux )
476 {
477 unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
478
479 vPortCPUReleaseMutexIntsDisabled( mux );
480 portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
481 }
482 #endif /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */
483
484 #define STACK_WATCH_AREA_SIZE ( 32 )
485 #define STACK_WATCH_POINT_NUMBER ( SOC_CPU_WATCHPOINTS_NUM - 1 )
486
vPortSetStackWatchpoint(void * pxStackStart)487 void vPortSetStackWatchpoint( void * pxStackStart )
488 {
489 /*Set watchpoint 1 to watch the last 32 bytes of the stack. */
490 /*Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because */
491 /*the size works by masking off the lowest address bits. For that reason, we futz a bit and watch the lowest 32 */
492 /*bytes of the stack we can actually watch. In general, this can cause the watchpoint to be triggered at most */
493 /*28 bytes early. The value 32 is chosen because it's larger than the stack canary, which in FreeRTOS is 20 bytes. */
494 /*This way, we make sure we trigger before/when the stack canary is corrupted, not after. */
495 int addr = ( int ) pxStackStart;
496
497 addr = ( addr + 31 ) & ( ~31 );
498 esp_cpu_set_watchpoint( STACK_WATCH_POINT_NUMBER, ( char * ) addr, 32, ESP_WATCHPOINT_STORE );
499 }
500
501 #if ( ESP_IDF_VERSION < ESP_IDF_VERSION_VAL( 4, 2, 0 ) )
502
503 #if defined( CONFIG_SPIRAM_SUPPORT )
504
505 /*
506 * Compare & set (S32C1) does not work in external RAM. Instead, this routine uses a mux (in internal memory) to fake it.
507 */
508 static portMUX_TYPE extram_mux = portMUX_INITIALIZER_UNLOCKED;
509
uxPortCompareSetExtram(volatile uint32_t * addr,uint32_t compare,uint32_t * set)510 void uxPortCompareSetExtram( volatile uint32_t * addr,
511 uint32_t compare,
512 uint32_t * set )
513 {
514 uint32_t prev;
515
516 uint32_t oldlevel = portSET_INTERRUPT_MASK_FROM_ISR();
517
518 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
519 vPortCPUAcquireMutexIntsDisabled( &extram_mux, portMUX_NO_TIMEOUT, __FUNCTION__, __LINE__ );
520 #else
521 vPortCPUAcquireMutexIntsDisabled( &extram_mux, portMUX_NO_TIMEOUT );
522 #endif
523 prev = *addr;
524
525 if( prev == compare )
526 {
527 *addr = *set;
528 }
529
530 *set = prev;
531 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
532 vPortCPUReleaseMutexIntsDisabled( &extram_mux, __FUNCTION__, __LINE__ );
533 #else
534 vPortCPUReleaseMutexIntsDisabled( &extram_mux );
535 #endif
536
537 portCLEAR_INTERRUPT_MASK_FROM_ISR( oldlevel );
538 }
539 #endif //defined(CONFIG_SPIRAM_SUPPORT)
540
541 #endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
542
543
xPortGetTickRateHz(void)544 uint32_t xPortGetTickRateHz( void )
545 {
546 return ( uint32_t ) configTICK_RATE_HZ;
547 }
548
549 /* For now, running FreeRTOS on one core and a bare metal on the other (or other OSes) */
550 /* is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE */
551 /* should mirror each other's values. */
552 /* */
553 /* And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE. */
554 #if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
555 #error "FreeRTOS and system configuration mismatch regarding the use of multiple cores."
556 #endif
557
558 extern void esp_startup_start_app_common( void );
559
esp_startup_start_app(void)560 void esp_startup_start_app( void )
561 {
562 #if !CONFIG_ESP_INT_WDT
563 #if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
564 assert( !soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!" );
565 #endif
566 #endif
567
568 esp_startup_start_app_common();
569
570 ESP_LOGI( "cpu_start", "Starting scheduler on PRO CPU." );
571 vTaskStartScheduler();
572 }
573